...
 
Commits (1)
  • Martin Finkel's avatar
    StreamsViewModel refactoring · 585de890
    Martin Finkel authored
    Created base classes for UWP page and ViewModel
    XAML binding now references ViewModel
    Disabled NavigationCacheMode to lower memory footprint
    Refactored MetaServices
    585de890
using VLC.Model.Library;
namespace VLC.Services.RunTime
{
public abstract class MetaService
{
protected readonly MediaLibrary MediaLibrary;
protected readonly NetworkListenerService NetworkListenerService;
protected MetaService(MediaLibrary mediaLibrary, NetworkListenerService networkListenerService)
{
MediaLibrary = mediaLibrary;
NetworkListenerService = networkListenerService;
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Threading.Tasks;
using Windows.UI.Core;
using VLC.Model.Music;
using VLC.MusicMetaFetcher;
using VLC.MusicMetaFetcher.Models.MusicEntities;
using VLC.Utils;
using VLC.ViewModels;
using VLC.Helpers;
using VLC.MediaMetaFetcher;
using VLC.Model.Library;
namespace VLC.Services.RunTime
{
public sealed class MusicMetaService
public sealed class MusicMetaService : MetaService
{
readonly MusicMDFetcher musicMdFetcher = new MusicMDFetcher(App.DeezerAppID, App.ApiKeyLastFm);
private readonly MusicMDFetcher _musicMdFetcher = new MusicMDFetcher(App.DeezerAppID, App.ApiKeyLastFm);
public MusicMetaService(MediaLibrary mediaLibrary, NetworkListenerService networkListenerService)
: base(mediaLibrary, networkListenerService)
{
}
public async Task GetSimilarArtists(ArtistItem artist)
{
var artists = await musicMdFetcher.GetArtistSimilarsArtist(artist.Name);
var artists = await _musicMdFetcher.GetArtistSimilarsArtist(artist.Name);
if (artists == null) return;
await DispatchHelper.InvokeInUIThread(CoreDispatcherPriority.Normal, () =>
{
......@@ -32,7 +31,7 @@ namespace VLC.Services.RunTime
public async Task GetPopularAlbums(ArtistItem artist)
{
var albums = await musicMdFetcher.GetArtistTopAlbums(artist.Name);
var albums = await _musicMdFetcher.GetArtistTopAlbums(artist.Name);
if (albums == null) return;
await DispatchHelper.InvokeInUIThread(CoreDispatcherPriority.Normal, () =>
{
......@@ -43,20 +42,20 @@ namespace VLC.Services.RunTime
public async Task GetArtistBiography(ArtistItem artist)
{
var bio = await musicMdFetcher.GetArtistBiography(artist.Name);
var bio = await _musicMdFetcher.GetArtistBiography(artist.Name);
if (bio == null) return;
await DispatchHelper.InvokeInUIThread(CoreDispatcherPriority.Normal, () =>
{
artist.Biography = bio;
});
Locator.MediaLibrary.Update(artist);
MediaLibrary.Update(artist);
}
public async Task<bool> GetAlbumCover(AlbumItem album)
{
if (NetworkListenerService.IsConnected && !string.IsNullOrEmpty(album.Name))
{
var bytes = await musicMdFetcher.GetAlbumPictureFromInternet(album.Name, album.Artist);
var bytes = await _musicMdFetcher.GetAlbumPictureFromInternet(album.Name, album.Artist);
if (bytes == null)
{
// TODO: Add a TriedWithNoSuccess flag in DB
......@@ -64,7 +63,7 @@ namespace VLC.Services.RunTime
var success = bytes != null && await SaveAlbumImageAsync(album, bytes);
if (success)
{
Locator.MediaLibrary.Update(album);
MediaLibrary.Update(album);
return true;
}
}
......@@ -75,17 +74,15 @@ namespace VLC.Services.RunTime
{
if (NetworkListenerService.IsConnected && !string.IsNullOrEmpty(artist.Name))
{
var bytes = await musicMdFetcher.GetArtistPicture(artist.Name);
var bytes = await _musicMdFetcher.GetArtistPicture(artist.Name);
if (bytes == null)
{
// TODO: Add a TriedWithNoSuccess flag in DB
}
var success = bytes != null && await SaveArtistImageAsync(artist, bytes);
if (success)
{
Locator.MediaLibrary.Update(artist);
return true;
}
if (!success) return false;
MediaLibrary.Update(artist);
return true;
}
return false;
}
......
......@@ -4,7 +4,7 @@ using VLC.Model.Events;
namespace VLC.Services.RunTime
{
class NetworkListenerService
public class NetworkListenerService
{
public event EventHandler<InternetConnectionChangedEventArgs> InternetConnectionChanged;
......@@ -26,14 +26,8 @@ namespace VLC.Services.RunTime
var arg = new InternetConnectionChangedEventArgs(IsConnected);
InternetConnectionChanged(null, arg);
}
public static bool IsConnected
{
get
{
var profile = NetworkInformation.GetInternetConnectionProfile();
return (profile != null && profile.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess);
}
}
public bool IsConnected => NetworkInformation.GetInternetConnectionProfile()?.GetNetworkConnectivityLevel() ==
NetworkConnectivityLevel.InternetAccess;
}
}
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Text;
using System.Xml.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks;
using VLC.MediaMetaFetcher;
using VLC.Model.Video;
using VLC.Utils;
using VLC.ViewModels;
using Windows.Storage;
using System.Linq;
using VLC.Model.Library;
namespace VLC.Services.RunTime
{
public sealed class VideoMetaService
public sealed class VideoMetaService : MetaService
{
readonly VideoMDFetcher videoMdFetcher = new VideoMDFetcher(App.ApiKeyMovieDb);
private readonly VideoMDFetcher _videoMdFetcher = new VideoMDFetcher(App.ApiKeyMovieDb);
public VideoMetaService(MediaLibrary mediaLibrary, NetworkListenerService networkListenerService)
: base(mediaLibrary, networkListenerService)
{
}
public async Task<bool> GetMovieSubtitle(VideoItem video)
{
if (NetworkListenerService.IsConnected && !string.IsNullOrEmpty(video.Path))
{
var bytes = await videoMdFetcher.GetMovieSubtitle(video);
var bytes = await _videoMdFetcher.GetMovieSubtitle(video);
if (bytes != null)
{
......@@ -30,7 +29,7 @@ namespace VLC.Services.RunTime
{
if (video.Id > -1)
{
Locator.MediaLibrary.UpdateVideo(video);
MediaLibrary.UpdateVideo(video);
}
return true;
}
......@@ -56,20 +55,19 @@ namespace VLC.Services.RunTime
}
return false;
}
public async Task<bool> GetMoviePicture(VideoItem video)
{
if (NetworkListenerService.IsConnected && !string.IsNullOrEmpty(video.Name))
{
var bytes = await videoMdFetcher.GetMovieCover(video.Name);
var bytes = await _videoMdFetcher.GetMovieCover(video.Name);
if (bytes != null)
{
var success = await SaveMoviePictureAsync(video, bytes);
if (success)
{
Locator.MediaLibrary.UpdateVideo(video);
MediaLibrary.UpdateVideo(video);
return true;
}
}
......
......@@ -198,6 +198,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\HttpServer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\HttpResponseSender.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\KeyboardListenerService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\MetaService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\NavigationService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\PlaybackService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\RunTime\PlaylistService.cs" />
......@@ -235,6 +236,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\Settings\SettingsViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\VideoVM\VideoLibraryVM.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\VideoVM\VideoPlayerVM.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ViewModelBase.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)Assets\NewStoreLogo.scale-100.png" />
......
......@@ -42,7 +42,6 @@ namespace VLC.ViewModels
private static VideoLibraryVM _videoLibraryVM;
private static VideoPlayerVM _videoPlayer;
private static VLCExplorerViewModel _vlcExplorer;
private static StreamsViewModel _streams;
private static SettingsViewModel _settings;
private static SearchViewModel _search;
private static SpecialThanksViewModel _specialThanks;
......@@ -87,7 +86,6 @@ namespace VLC.ViewModels
public static SettingsViewModel SettingsVM => _settings ?? (_settings = App.Container.Resolve<SettingsViewModel>());
public static SearchViewModel SearchVM => _search ?? (_search = App.Container.Resolve<SearchViewModel>());
public static StreamsViewModel StreamsVM => _streams ?? (_streams = App.Container.Resolve<StreamsViewModel>());
public static SpecialThanksViewModel SpecialThanksVM => _specialThanks ?? (_specialThanks = App.Container.Resolve<SpecialThanksViewModel>());
public static NavigationService NavigationService => _navigationService ?? (_navigationService = App.Container.Resolve<NavigationService>());
......
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Core;
using VLC.Database;
using VLC.Model.Stream;
using VLC.Utils;
using VLC.Commands;
using Windows.UI.Xaml;
using Autofac;
using VLC.Services.RunTime;
using VLC.Commands.StreamsLibrary;
using VLC.Model.Library;
namespace VLC.ViewModels.Others
{
public class StreamsViewModel : BindableBase, IDisposable
public class StreamsViewModel : ViewModelBase
{
public IEnumerable<StreamMedia> StreamsHistoryAndFavoritesGrouped
{
get { return Locator.MediaLibrary.Streams?.OrderBy(x => x.Order); }
}
private MediaLibrary _mediaLibrary;
private NetworkListenerService _networkListenerService;
public bool IsCollectionEmpty
public StreamsViewModel(MediaLibrary mediaLibrary, NetworkListenerService networkListenerService)
{
get { return !Locator.MediaLibrary.Streams.Any(); }
_mediaLibrary = mediaLibrary;
_networkListenerService = networkListenerService;
}
public PlayNetworkMRLCommand PlayStreamCommand { get; private set; } = new PlayNetworkMRLCommand();
public IEnumerable<StreamMedia> StreamsHistoryAndFavoritesGrouped => _mediaLibrary.Streams?.OrderBy(x => x.Order);
public bool IsCollectionEmpty => !_mediaLibrary.Streams.Any();
public Visibility NoInternetPlaceholderEnabled => _networkListenerService.IsConnected ? Visibility.Collapsed : Visibility.Visible;
public Visibility NoInternetPlaceholderEnabled => NetworkListenerService.IsConnected ? Visibility.Collapsed : Visibility.Visible;
public PlayNetworkMRLCommand PlayStreamCommand { get; } = new PlayNetworkMRLCommand();
public void OnNavigatedTo()
public override void Initialize()
{
Task.Run(() => Initialize());
}
_networkListenerService.InternetConnectionChanged += StreamsViewModel_InternetConnectionChanged;
_mediaLibrary.Streams.CollectionChanged += Streams_CollectionChanged;
public void OnNavigatedFrom()
{
Dispose();
Task.Run(async () => await _mediaLibrary.LoadStreamsFromDatabase());
}
async Task Initialize()
public override void Stop()
{
App.Container.Resolve<NetworkListenerService>().InternetConnectionChanged += StreamsViewModel_InternetConnectionChanged;
Locator.MediaLibrary.Streams.CollectionChanged += Streams_CollectionChanged;
await Locator.MediaLibrary.LoadStreamsFromDatabase();
}
_mediaLibrary.Streams.CollectionChanged -= Streams_CollectionChanged;
_networkListenerService.InternetConnectionChanged -= StreamsViewModel_InternetConnectionChanged;
_mediaLibrary = null;
_networkListenerService = null;
PlayStreamCommand = null;
}
private async void StreamsViewModel_InternetConnectionChanged(object sender, Model.Events.InternetConnectionChangedEventArgs e)
{
await DispatchHelper.InvokeInUIThread(CoreDispatcherPriority.Normal, () => OnPropertyChanged(nameof(NoInternetPlaceholderEnabled)));
......@@ -57,11 +57,5 @@ namespace VLC.ViewModels.Others
OnPropertyChanged(nameof(StreamsHistoryAndFavoritesGrouped));
OnPropertyChanged(nameof(IsCollectionEmpty));
}
public void Dispose()
{
Locator.MediaLibrary.Streams.CollectionChanged -= Streams_CollectionChanged;
App.Container.Resolve<NetworkListenerService>().InternetConnectionChanged -= StreamsViewModel_InternetConnectionChanged;
}
}
}
}
\ No newline at end of file
using VLC.Utils;
namespace VLC.ViewModels
{
public abstract class ViewModelBase : BindableBase
{
public virtual void Initialize() { }
public virtual void Stop() { }
}
}
\ No newline at end of file
......@@ -144,6 +144,7 @@
<Compile Include="Views\MainPages\MusicPanes\SongCollectionBase.xaml.cs">
<DependentUpon>SongCollectionBase.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MainPages\VlcPage.cs" />
<Compile Include="Views\MusicPages\AlbumPageControls\AlbumPageBase.xaml.cs">
<DependentUpon>AlbumPageBase.xaml</DependentUpon>
</Compile>
......
<Page x:Class="VLC.UI.Views.MainPages.MainPageNetwork"
<local:StreamsPage x:Class="VLC.UI.Views.MainPages.MainPageNetwork"
NavigationCacheMode="Disabled"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VLC.UI.Views.MainPages"
......@@ -8,11 +9,11 @@
xmlns:placeholder="using:VLC.UI.Views.UserControls.Placeholder"
xmlns:triggers="using:WinRT.Triggers"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}, Path=StreamsVM}">
DataContext="{x:Bind ViewModel}">
<Page.Resources>
<CollectionViewSource x:Key="StreamsHistoryAndFavoritesGroupedResource"
Source="{Binding StreamsHistoryAndFavoritesGrouped}"
Source="{x:Bind ViewModel.StreamsHistoryAndFavoritesGrouped}"
IsSourceGrouped="False" />
</Page.Resources>
......@@ -52,7 +53,7 @@
Style="{StaticResource TextBlockButtonStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Command="{Binding Source={StaticResource Locator}, Path=StreamsVM.PlayStreamCommand}"
Command="{x:Bind ViewModel.PlayStreamCommand}"
CommandParameter="{Binding ElementName=MrlTextBox, Path=Text}">
<Button.Content>
<FontIcon Glyph="{StaticResource CheckSymbol}"
......@@ -61,7 +62,7 @@
</Button>
</Grid>
<placeholder:NothingToSeeHere Grid.Row="1"
Visibility="{Binding IsCollectionEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" />
Visibility="{x:Bind ViewModel.IsCollectionEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" />
<ListView Grid.Row="1"
ItemsSource="{Binding Source={StaticResource StreamsHistoryAndFavoritesGroupedResource}}"
IsItemClickEnabled="True"
......@@ -69,7 +70,7 @@
ItemContainerStyle="{StaticResource ListViewItemStyle}">
<triggers:Interactions.Triggers>
<triggers:EventTrigger EventName="ItemClick">
<triggers:InvokeCommandAction Command="{Binding Source={StaticResource Locator}, Path=StreamsVM.PlayStreamCommand}"
<triggers:InvokeCommandAction Command="{x:Bind ViewModel.PlayStreamCommand}"
PassEventArgsToCommand="True" />
</triggers:EventTrigger>
</triggers:Interactions.Triggers>
......@@ -121,7 +122,7 @@
</ListView>
<Grid Grid.Row="1"
Background="{ThemeResource ApplicationChromeThemeBrush}"
Visibility="{Binding NoInternetPlaceholderEnabled}">
Visibility="{x:Bind ViewModel.NoInternetPlaceholderEnabled}">
<TextBlock Text="{Binding Source={StaticResource Strings}, Path=NoInternetConnection}"
Style="{StaticResource SubheaderTextBlockStyle}"
VerticalAlignment="Center"
......@@ -139,4 +140,4 @@
Width="100" />
</Grid>
</Grid>
</Page>
\ No newline at end of file
</local:StreamsPage>
\ No newline at end of file
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using VLC.Services.RunTime;
using VLC.ViewModels;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using VLC.ViewModels.Others;
namespace VLC.UI.Views.MainPages
{
public sealed partial class MainPageNetwork : Page
public sealed partial class MainPageNetwork : StreamsPage
{
public MainPageNetwork()
{
......@@ -20,21 +18,19 @@ namespace VLC.UI.Views.MainPages
{
base.OnNavigatedTo(e);
CoreWindow.GetForCurrentThread().KeyDown += KeyboardListenerService_KeyDown;
Locator.StreamsVM.OnNavigatedTo();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
CoreWindow.GetForCurrentThread().KeyDown -= KeyboardListenerService_KeyDown;
Locator.StreamsVM.OnNavigatedFrom();
}
private void KeyboardListenerService_KeyDown(CoreWindow sender, KeyEventArgs args)
{
if (args.VirtualKey == VirtualKey.Enter)
{
Locator.StreamsVM.PlayStreamCommand.Execute(MrlTextBox.Text);
ViewModel.PlayStreamCommand.Execute(MrlTextBox.Text);
}
}
......@@ -43,4 +39,11 @@ namespace VLC.UI.Views.MainPages
MrlTextBox.Foreground = App.Current.Resources["MainColor"] as SolidColorBrush;
}
}
/// <summary>
/// Mandatory intermediate class as partial page classes inheriting generic abstract classes do not play well with XAML
/// </summary>
public class StreamsPage : VlcPage<StreamsViewModel>
{
}
}
\ No newline at end of file
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Autofac;
using VLC.ViewModels;
namespace VLC.UI.Views.MainPages
{
public abstract class VlcPage<TViewModelBase> : Page where TViewModelBase : ViewModelBase
{
private TViewModelBase _viewModel;
protected virtual TViewModelBase ViewModel => _viewModel ?? (_viewModel = App.Container.Resolve<TViewModelBase>());
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
ViewModel.Initialize();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
ViewModel.Stop();
_viewModel = null;
}
}
}
\ No newline at end of file