diff --git a/MusicX/Controls/NavigationBar.cs b/MusicX/Controls/NavigationBar.cs index 7e3787ff..57995dd2 100644 --- a/MusicX/Controls/NavigationBar.cs +++ b/MusicX/Controls/NavigationBar.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; @@ -7,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using MusicX.Services; using NLog; -using Wpf.Ui.Extensions; + namespace MusicX.Controls; public class NavigationBar : Control @@ -91,9 +92,15 @@ private void FrameOnNavigated(object sender, NavigationEventArgs e) CurrentItem = Items.FirstOrDefault(b => b.Tag == menuView.MenuTag); else CurrentItem = null; - + if (CurrentItem != null) - Frame.CleanNavigation(); + { + while (Frame.CanGoBack) + { + if (Frame.RemoveBackEntry().CustomContentState is IDisposable disposable) + disposable.Dispose(); + } + } Log.Info("Navigated to {Content}", e.Content.ToString()); } diff --git a/MusicX/Controls/PlayerControl.xaml.cs b/MusicX/Controls/PlayerControl.xaml.cs index f34b143b..1c11fd1f 100644 --- a/MusicX/Controls/PlayerControl.xaml.cs +++ b/MusicX/Controls/PlayerControl.xaml.cs @@ -424,15 +424,18 @@ private async void LikeTrack_Click(object sender, RoutedEventArgs e) var vkService = StaticService.Container.GetRequiredService(); var boomService = StaticService.Container.GetRequiredService(); var snackbarService = StaticService.Container.GetRequiredService(); + var eventService = StaticService.Container.GetRequiredService(); switch (PlayerService.CurrentTrack?.Data) { case VkTrackData vkData when LikeIcon.Filled: await vkService.Dislike(vkData.Info.Id, vkData.Info.OwnerId); await vkService.AudioDeleteAsync(vkData.Info.Id, vkData.Info.OwnerId); + eventService.Dispatch(this, SectionEvent.AudiosRemove); break; case VkTrackData vkData: await vkService.AudioAddAsync(vkData.Info.Id, vkData.Info.OwnerId); + eventService.Dispatch(this, SectionEvent.AudiosAdd); break; case BoomTrackData boomData when LikeIcon.Filled: await boomService.UnLike(boomData.Id); diff --git a/MusicX/Controls/PlaylistControl.xaml.cs b/MusicX/Controls/PlaylistControl.xaml.cs index a6d1a36f..2c775cbd 100644 --- a/MusicX/Controls/PlaylistControl.xaml.cs +++ b/MusicX/Controls/PlaylistControl.xaml.cs @@ -342,12 +342,15 @@ private void cardAction_MouseLeave(object sender, MouseEventArgs e) private async void AddToLibrary_MouseDown(object sender, MouseButtonEventArgs e) { var snackbarService = StaticService.Container.GetRequiredService(); + var eventService = StaticService.Container.GetRequiredService(); try { var vkService = StaticService.Container.GetRequiredService(); await vkService.AddPlaylistAsync(Playlist.Id, Playlist.OwnerId, Playlist.AccessKey); + + eventService.Dispatch(this, SectionEvent.PlaylistsFollow); snackbarService.Show("Плейлист добавлен", "Плейлист теперь находится в Вашей библиотеке", ControlAppearance.Success); } diff --git a/MusicX/Controls/TrackControl.xaml.cs b/MusicX/Controls/TrackControl.xaml.cs index 94e64dd0..f0501325 100644 --- a/MusicX/Controls/TrackControl.xaml.cs +++ b/MusicX/Controls/TrackControl.xaml.cs @@ -481,18 +481,19 @@ private async void AddRemove_MouseDown(object sender, MouseButtonEventArgs e) { var configService = StaticService.Container.GetRequiredService(); var vkService = StaticService.Container.GetRequiredService(); - + var eventService = StaticService.Container.GetRequiredService(); var config = await configService.GetConfig(); if (Audio.OwnerId == config.UserId) { await vkService.AudioDeleteAsync(Audio.Id, Audio.OwnerId); + eventService.Dispatch(this, SectionEvent.AudiosRemove); } else { await vkService.AudioAddAsync(Audio.Id, Audio.OwnerId); - + eventService.Dispatch(this, SectionEvent.AudiosAdd); } }catch(Exception ex) { diff --git a/MusicX/RootWindow.xaml.cs b/MusicX/RootWindow.xaml.cs index 210871da..ea8931d4 100644 --- a/MusicX/RootWindow.xaml.cs +++ b/MusicX/RootWindow.xaml.cs @@ -365,7 +365,8 @@ private void NavigationServiceOnBackRequested(object? sender, EventArgs e) return; RootFrame.GoBack(); - RootFrame.RemoveBackEntry(); + if (RootFrame.RemoveBackEntry().CustomContentState is IDisposable disposable) + disposable.Dispose(); } private void NavigationServiceOnExternalSectionOpened(object? sender, SectionViewModel e) { diff --git a/MusicX/Services/SectionEventService.cs b/MusicX/Services/SectionEventService.cs new file mode 100644 index 00000000..b2111019 --- /dev/null +++ b/MusicX/Services/SectionEventService.cs @@ -0,0 +1,28 @@ +using System; + +namespace MusicX.Services; + +public class SectionEventService +{ + public event EventHandler? Event; + + public void Dispatch(object? sender, string name) + { + Event?.Invoke(sender, name); + } +} + +public static class SectionEvent +{ + public const string AudiosAdd = "music_audios_add"; + public const string AudiosRemove = "music_audios_remove"; + + public const string PlaylistsAdd = "music_playlists_add"; + public const string PlaylistsRemove = "music_playlists_remove"; + + public const string PlaylistsFollow = "music_playlists_follow"; + public const string PlaylistsUnfollow = "music_playlists_unfollow"; + + public const string ArtistSubscribe = "artist_subscribe"; + public const string ArtistUnsubscribe = "artist_unsubscribe"; +} \ No newline at end of file diff --git a/MusicX/ViewModels/BlockViewModel.cs b/MusicX/ViewModels/BlockViewModel.cs index a0ddcc3f..dc39c821 100644 --- a/MusicX/ViewModels/BlockViewModel.cs +++ b/MusicX/ViewModels/BlockViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Specialized; +using System.Collections.Immutable; +using System.Collections.Specialized; using MusicX.Core.Models; using MusicX.Helpers; using MusicX.Shared.ListenTogether.Radio; @@ -49,6 +50,8 @@ public class BlockViewModel : BaseViewModel public ObservableRangeCollection Longreads { get; } + public ImmutableHashSet ListenEvents { get; private set; } + public BlockViewModel(Block block) { Id = block.Id; @@ -74,6 +77,7 @@ public BlockViewModel(Block block) Stations = new(block.Stations); Curators = new(block.Curators); Longreads = new(block.Longreads); + ListenEvents = [..block.ListenEvents]; } public void MergeBlock(Block block) @@ -98,5 +102,6 @@ public void MergeBlock(Block block) Stations.AddRange(block.Stations, action); Curators.AddRange(block.Curators, action); Longreads.AddRange(block.Longreads, action); + ListenEvents = ListenEvents.Union(block.ListenEvents); } } \ No newline at end of file diff --git a/MusicX/ViewModels/Controls/BlockButtonViewModel.cs b/MusicX/ViewModels/Controls/BlockButtonViewModel.cs index 4dbfc12b..0c403b45 100644 --- a/MusicX/ViewModels/Controls/BlockButtonViewModel.cs +++ b/MusicX/ViewModels/Controls/BlockButtonViewModel.cs @@ -101,13 +101,16 @@ private async void Invoke() case "toggle_artist_subscription" when Artist is not null && ParentBlock is not null: { var vkService = StaticService.Container.GetRequiredService(); + var eventService = StaticService.Container.GetRequiredService(); if (Artist.IsFollowed) await vkService.UnfollowArtist(Action.ArtistId, ParentBlock.Id); else await vkService.FollowArtist(Action.ArtistId, ParentBlock.Id); - Artist.IsFollowed = !Artist.IsFollowed; + Artist.IsFollowed = !Artist.IsFollowed; + + eventService.Dispatch(this, Artist.IsFollowed ? SectionEvent.ArtistSubscribe : SectionEvent.ArtistUnsubscribe); Refresh(); break; } diff --git a/MusicX/ViewModels/Modals/CreatePlaylistModalViewModel.cs b/MusicX/ViewModels/Modals/CreatePlaylistModalViewModel.cs index 8728fb40..245b7e24 100644 --- a/MusicX/ViewModels/Modals/CreatePlaylistModalViewModel.cs +++ b/MusicX/ViewModels/Modals/CreatePlaylistModalViewModel.cs @@ -53,6 +53,7 @@ public class CreatePlaylistModalViewModel : BaseViewModel private readonly TracksSelectorModalViewModel selectorViewModel; private readonly ConfigService configService; private readonly ISnackbarService _snackbarService; + private readonly SectionEventService _eventService; private bool isEdit; public bool IsEdit @@ -67,13 +68,14 @@ public bool IsEdit public CreatePlaylistModalViewModel(NavigationService navigationService, VkService vkService, TracksSelectorModalViewModel selectorViewModel, ConfigService configService, - ISnackbarService snackbarService) + ISnackbarService snackbarService, SectionEventService eventService) { this.navigationService = navigationService; this.vkService = vkService; this.selectorViewModel = selectorViewModel; this.configService = configService; _snackbarService = snackbarService; + _eventService = eventService; this.AddTracksCommand = new RelayCommand(AddTracks); this.CreateCommand = new AsyncCommand(Create); @@ -145,7 +147,7 @@ private async Task Create() }else { playlistId = await vkService.CreatePlaylistAsync(config.UserId, this.Title, this.Description, Tracks); - + _eventService.Dispatch(this, SectionEvent.PlaylistsAdd); } if(!this.CoverPath.StartsWith("http")) diff --git a/MusicX/ViewModels/PlaylistViewModel.cs b/MusicX/ViewModels/PlaylistViewModel.cs index 3348eb6d..2055a1c0 100644 --- a/MusicX/ViewModels/PlaylistViewModel.cs +++ b/MusicX/ViewModels/PlaylistViewModel.cs @@ -40,17 +40,19 @@ public class PlaylistViewModel:BaseViewModel private readonly VkService vkService; private readonly Logger logger; private readonly ISnackbarService _snackbarService; + private readonly SectionEventService _eventService; public ConfigService ConfigService { get; set; } public PlaylistViewModel(VkService vkService, Logger logger, ConfigService configService, - ISnackbarService snackbarService) + ISnackbarService snackbarService, SectionEventService eventService) { this.vkService = vkService; this.ConfigService = configService; this.logger = logger; _snackbarService = snackbarService; + _eventService = eventService; } public async ValueTask LoadMore() { @@ -270,6 +272,7 @@ public async Task AddPlaylist() try { await vkService.AddPlaylistAsync(Playlist.Id, Playlist.OwnerId, Playlist.AccessKey); + _eventService.Dispatch(this, SectionEvent.PlaylistsFollow); return true; }catch(Exception ex) { @@ -296,6 +299,10 @@ public async Task RemovePlaylist() try { await vkService.DeletePlaylistAsync(Playlist.Id, Playlist.OwnerId); + _eventService.Dispatch(this, + Playlist.OwnerId == ConfigService.Config.UserId + ? SectionEvent.PlaylistsRemove + : SectionEvent.PlaylistsUnfollow); return true; } catch (Exception ex) diff --git a/MusicX/ViewModels/SectionViewModel.cs b/MusicX/ViewModels/SectionViewModel.cs index 307d6066..029b5029 100644 --- a/MusicX/ViewModels/SectionViewModel.cs +++ b/MusicX/ViewModels/SectionViewModel.cs @@ -22,12 +22,13 @@ public enum ContentState Loaded } - public class SectionViewModel : BaseViewModel, INotifyOnActivated + public class SectionViewModel : BaseViewModel, INotifyOnActivated, IDisposable { private readonly VkService vkService; private readonly Logger logger; private readonly ISnackbarService _snackbarService; private readonly ConfigService configService; + private readonly SectionEventService _eventService; public ContentState ContentState { get; set; } public bool IsLoadingMore { get; set; } @@ -41,12 +42,37 @@ public class SectionViewModel : BaseViewModel, INotifyOnActivated public ObservableRangeCollection Blocks { get; } = []; public SectionViewModel(VkService vkService, Logger logger, ISnackbarService snackbarService, - ConfigService configService) + ConfigService configService, SectionEventService eventService) { this.vkService = vkService; this.logger = logger; _snackbarService = snackbarService; this.configService = configService; + _eventService = eventService; + + _eventService.Event += EventServiceOnEvent; + } + + private async void EventServiceOnEvent(object? sender, string e) + { + var changed = false; + for (var i = 0; i < Blocks.Count; i++) + { + var block = Blocks[i]; + + if (!block.ListenEvents.Contains(e)) + continue; + + changed = true; + + // не работает хз + // var response = await vkService.GetBlockItems(block.Id); + // + // Blocks[i] = new BlockViewModel(response.Block); + } + + if (changed) + await LoadAsync(); } public async Task LoadAsync() @@ -327,6 +353,13 @@ public void OnActivated() { if (Section is null) LoadAsync().SafeFireAndForget(); + else + _eventService.Event += EventServiceOnEvent; + } + + public void Dispose() + { + _eventService.Event -= EventServiceOnEvent; } } } diff --git a/MusicX/Views/SectionView.xaml.cs b/MusicX/Views/SectionView.xaml.cs index a9818680..97ca612d 100644 --- a/MusicX/Views/SectionView.xaml.cs +++ b/MusicX/Views/SectionView.xaml.cs @@ -39,7 +39,7 @@ private async void SectionScrollViewer_ScrollChanged(object sender, ScrollChange } [Serializable] - private class SectionState : CustomContentState, ISerializable + private class SectionState : CustomContentState, ISerializable, IDisposable { private const string TypeKey = "SectionType"; private const string IdKey = "SectionId"; @@ -77,6 +77,11 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) info.AddValue(TypeKey, (int)_viewModel.SectionType); info.AddValue(IdKey, _viewModel.Section.Id); } + + public void Dispose() + { + _viewModel.Dispose(); + } } public override string ToString() { diff --git a/MusicX/Views/StartingWindow.xaml.cs b/MusicX/Views/StartingWindow.xaml.cs index e2285f6a..dc6c212e 100644 --- a/MusicX/Views/StartingWindow.xaml.cs +++ b/MusicX/Views/StartingWindow.xaml.cs @@ -141,6 +141,7 @@ await Task.Run(async () => collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(); var container = StaticService.Container = collection.BuildServiceProvider();