From 767cdc1f6f6a63ce997fc9476911e2c361f9d402 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Wed, 20 Feb 2013 20:33:05 -0500 Subject: Pushing missing changes --- .../ViewModels/BaseItemPersonViewModel.cs | 27 +++ MediaBrowser.UI/ViewModels/BaseViewModel.cs | 27 +++ .../ViewModels/ChapterInfoDtoViewModel.cs | 182 ++++++++++++++++++++ MediaBrowser.UI/ViewModels/DtoBaseItemViewModel.cs | 184 +++++++++++++++++++++ .../ViewModels/ItemCollectionViewModel.cs | 158 ++++++++++++++++++ .../ViewModels/SpecialFeatureViewModel.cs | 135 +++++++++++++++ 6 files changed, 713 insertions(+) create mode 100644 MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs create mode 100644 MediaBrowser.UI/ViewModels/BaseViewModel.cs create mode 100644 MediaBrowser.UI/ViewModels/ChapterInfoDtoViewModel.cs create mode 100644 MediaBrowser.UI/ViewModels/DtoBaseItemViewModel.cs create mode 100644 MediaBrowser.UI/ViewModels/ItemCollectionViewModel.cs create mode 100644 MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs (limited to 'MediaBrowser.UI/ViewModels') diff --git a/MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs b/MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs new file mode 100644 index 0000000000..95ff86094c --- /dev/null +++ b/MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Model.DTO; + +namespace MediaBrowser.UI.ViewModels +{ + public class BaseItemPersonViewModel : BaseViewModel + { + /// + /// The _item + /// + private BaseItemPerson _item; + /// + /// Gets or sets the item. + /// + /// The item. + public BaseItemPerson Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + OnPropertyChanged("Image"); + } + } + } +} diff --git a/MediaBrowser.UI/ViewModels/BaseViewModel.cs b/MediaBrowser.UI/ViewModels/BaseViewModel.cs new file mode 100644 index 0000000000..03ac9d18a0 --- /dev/null +++ b/MediaBrowser.UI/ViewModels/BaseViewModel.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; + +namespace MediaBrowser.UI.ViewModels +{ + /// + /// Represents a base ViewModel + /// + public abstract class BaseViewModel : INotifyPropertyChanged + { + /// + /// Occurs when [property changed]. + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Called when [property changed]. + /// + /// The name. + public virtual void OnPropertyChanged(string name) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(name)); + } + } + } +} diff --git a/MediaBrowser.UI/ViewModels/ChapterInfoDtoViewModel.cs b/MediaBrowser.UI/ViewModels/ChapterInfoDtoViewModel.cs new file mode 100644 index 0000000000..53ab787c48 --- /dev/null +++ b/MediaBrowser.UI/ViewModels/ChapterInfoDtoViewModel.cs @@ -0,0 +1,182 @@ +using MediaBrowser.Model.DTO; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Net; +using System; +using System.Linq; +using System.Windows.Media.Imaging; + +namespace MediaBrowser.UI.ViewModels +{ + /// + /// Class ChapterInfoDtoViewModel + /// + public class ChapterInfoDtoViewModel : BaseViewModel + { + /// + /// Gets or sets the image download options. + /// + /// The image download options. + public ImageOptions ImageDownloadOptions { get; set; } + + /// + /// The _image width + /// + private double _imageWidth; + /// + /// Gets or sets the width of the image. + /// + /// The width of the image. + public double ImageWidth + { + get { return _imageWidth; } + + set + { + _imageWidth = value; + OnPropertyChanged("ImageWidth"); + } + } + + /// + /// The _image height + /// + private double _imageHeight; + /// + /// Gets or sets the height of the image. + /// + /// The height of the image. + public double ImageHeight + { + get { return _imageHeight; } + + set + { + _imageHeight = value; + OnPropertyChanged("ImageHeight"); + } + } + + /// + /// The _item + /// + private ChapterInfoDto _chapter; + /// + /// Gets or sets the item. + /// + /// The item. + public ChapterInfoDto Chapter + { + get { return _chapter; } + + set + { + _chapter = value; + OnPropertyChanged("Chapter"); + OnPropertyChanged("TimeString"); + OnChapterChanged(); + } + } + + /// + /// The _item + /// + private DtoBaseItem _item; + /// + /// Gets or sets the item. + /// + /// The item. + public DtoBaseItem Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + } + } + + /// + /// Gets the time string. + /// + /// The time string. + public string TimeString + { + get + { + var time = TimeSpan.FromTicks(Chapter.StartPositionTicks); + + return time.ToString(time.TotalHours < 1 ? "m':'ss" : "h':'mm':'ss"); + } + } + + /// + /// The _image + /// + private BitmapImage _image; + /// + /// Gets the image. + /// + /// The image. + public BitmapImage Image + { + get { return _image; } + set + { + _image = value; + OnPropertyChanged("Image"); + } + } + + /// + /// Called when [item changed]. + /// + private async void OnChapterChanged() + { + var options = ImageDownloadOptions ?? new ImageOptions { }; + + options.ImageType = ImageType.ChapterImage; + options.ImageIndex = Item.Chapters.IndexOf(Chapter); + + try + { + Image = await App.Instance.GetRemoteBitmapAsync(App.Instance.ApiClient.GetImageUrl(Item, options)); + } + catch (HttpException) + { + } + } + + /// + /// Gets the height of the chapter image. + /// + /// The item. + /// The height. + /// The default width. + /// System.Double. + public static double GetChapterImageWidth(DtoBaseItem item, double height, double defaultWidth) + { + var width = defaultWidth; + + if (item.MediaStreams != null) + { + var videoStream = item.MediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); + + if (videoStream != null) + { + double streamHeight = videoStream.Height ?? 0; + double streamWidth = videoStream.Width ?? 0; + + if (streamHeight > 0 && streamWidth > 0) + { + var aspectRatio = streamWidth / streamHeight; + + width = height * aspectRatio; + } + } + } + + return width; + } + } +} diff --git a/MediaBrowser.UI/ViewModels/DtoBaseItemViewModel.cs b/MediaBrowser.UI/ViewModels/DtoBaseItemViewModel.cs new file mode 100644 index 0000000000..0c9e27db32 --- /dev/null +++ b/MediaBrowser.UI/ViewModels/DtoBaseItemViewModel.cs @@ -0,0 +1,184 @@ +using MediaBrowser.Common.Logging; +using MediaBrowser.Model.DTO; +using MediaBrowser.Model.Entities; +using MediaBrowser.UI.Pages; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace MediaBrowser.UI.ViewModels +{ + /// + /// Class DtoBaseItemViewModel + /// + public class DtoBaseItemViewModel : BaseViewModel + { + /// + /// The _average primary image aspect ratio + /// + private double _averagePrimaryImageAspectRatio; + /// + /// Gets the aspect ratio that should be used if displaying the primary image + /// + /// The average primary image aspect ratio. + public double AveragePrimaryImageAspectRatio + { + get { return _averagePrimaryImageAspectRatio; } + + set + { + _averagePrimaryImageAspectRatio = value; + OnPropertyChanged("AveragePrimaryImageAspectRatio"); + } + } + + /// + /// The _parent display preferences + /// + private DisplayPreferences _parentDisplayPreferences; + /// + /// Gets of sets the current DisplayPreferences + /// + /// The parent display preferences. + public DisplayPreferences ParentDisplayPreferences + { + get { return _parentDisplayPreferences; } + + set + { + _parentDisplayPreferences = value; + NotifyDisplayPreferencesChanged(); + } + } + + /// + /// The _item + /// + private DtoBaseItem _item; + /// + /// Gets or sets the item. + /// + /// The item. + public DtoBaseItem Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + } + } + + /// + /// Notifies the display preferences changed. + /// + public void NotifyDisplayPreferencesChanged() + { + OnPropertyChanged("DisplayPreferences"); + } + + /// + /// Gets an image url that can be used to download an image from the api + /// + /// The type of image requested + /// The image index, if there are multiple. Currently only applies to backdrops. Supply null or 0 for first backdrop. + /// System.String. + public string GetImageUrl(ImageType imageType, int? imageIndex = null) + { + var height = ParentDisplayPreferences.PrimaryImageHeight; + + var averageAspectRatio = BaseFolderPage.GetAspectRatio(imageType, AveragePrimaryImageAspectRatio); + + var width = height * averageAspectRatio; + + var imageOptions = new ImageOptions + { + ImageType = imageType, + ImageIndex = imageIndex, + Height = height + }; + + if (imageType == ImageType.Primary) + { + var currentAspectRatio = imageType == ImageType.Primary ? Item.PrimaryImageAspectRatio ?? width / height : width / height; + + // Preserve the exact AR if it deviates from the average significantly + var preserveExactAspectRatio = Math.Abs(currentAspectRatio - averageAspectRatio) > .10; + + if (!preserveExactAspectRatio) + { + imageOptions.Width = Convert.ToInt32(width); + } + } + + return App.Instance.ApiClient.GetImageUrl(Item, imageOptions); + } + + /// + /// Gets the average primary image aspect ratio. + /// + /// The items. + /// System.Double. + /// items + public static double GetAveragePrimaryImageAspectRatio(IEnumerable items) + { + if (items == null) + { + throw new ArgumentNullException("items"); + } + + double total = 0; + var count = 0; + + foreach (var child in items) + { + var ratio = child.PrimaryImageAspectRatio ?? 0; + + if (ratio.Equals(0)) + { + continue; + } + + total += ratio; + count++; + } + + return count == 0 ? 1 : total / count; + } + + /// + /// Gets the observable items. + /// + /// The items. + /// ObservableCollection{DtoBaseItemViewModel}. + public static ObservableCollection GetObservableItems(DtoBaseItem[] items) + { + return GetObservableItems(items, GetAveragePrimaryImageAspectRatio(items)); + } + + /// + /// Gets the observable items. + /// + /// The items. + /// The average primary image aspect ratio. + /// The parent display preferences. + /// ObservableCollection{DtoBaseItemViewModel}. + /// items + public static ObservableCollection GetObservableItems(IEnumerable items, double averagePrimaryImageAspectRatio, DisplayPreferences parentDisplayPreferences = null) + { + if (items == null) + { + throw new ArgumentNullException("items"); + } + + return new ObservableCollection(items.Select(i => new DtoBaseItemViewModel + { + Item = i, + ParentDisplayPreferences = parentDisplayPreferences, + AveragePrimaryImageAspectRatio = averagePrimaryImageAspectRatio + })); + } + } +} diff --git a/MediaBrowser.UI/ViewModels/ItemCollectionViewModel.cs b/MediaBrowser.UI/ViewModels/ItemCollectionViewModel.cs new file mode 100644 index 0000000000..82feedbd70 --- /dev/null +++ b/MediaBrowser.UI/ViewModels/ItemCollectionViewModel.cs @@ -0,0 +1,158 @@ +using MediaBrowser.Model.DTO; +using System; +using System.Threading; +using System.Windows; + +namespace MediaBrowser.UI.ViewModels +{ + /// + /// Represents a view model that contains multiple items. + /// This should be used if you want to display a button or list item that holds more than one item, + /// and cycle through them periodically. + /// + public class ItemCollectionViewModel : BaseViewModel, IDisposable + { + private int RotationPeriodMs { get; set; } + + public ItemCollectionViewModel(int rotationPeriodMs = 10000, int rotationDevaiationMs = 2000) + : base() + { + if (rotationDevaiationMs > 0) + { + rotationPeriodMs += new Random(Guid.NewGuid().GetHashCode()).Next(0 - rotationDevaiationMs, rotationDevaiationMs); + } + + RotationPeriodMs = rotationPeriodMs; + } + + /// + /// Gets the timer that updates the current item + /// + private Timer CurrentItemTimer { get; set; } + + private string _name; + /// + /// Gets or sets the name of the collection + /// + public string Name + { + get { return _name; } + set + { + _name = value; + OnPropertyChanged("Name"); + } + } + + private DtoBaseItem[] _items; + /// + /// Gets or sets the list of items + /// + public DtoBaseItem[] Items + { + get { return _items; } + set + { + _items = value ?? new DtoBaseItem[] { }; + OnPropertyChanged("Items"); + CurrentItemIndex = Items.Length == 0 ? -1 : 0; + + ReloadTimer(); + } + } + + private int _currentItemIndex; + /// + /// Gets or sets the index of the current item + /// + public int CurrentItemIndex + { + get { return _currentItemIndex; } + set + { + _currentItemIndex = value; + OnPropertyChanged("CurrentItemIndex"); + OnPropertyChanged("CurrentItem"); + OnPropertyChanged("NextItem"); + } + } + + /// + /// Gets the current item + /// + public DtoBaseItem CurrentItem + { + get { return CurrentItemIndex == -1 ? null : Items[CurrentItemIndex]; } + } + + /// + /// Gets the next item + /// + public DtoBaseItem NextItem + { + get + { + if (CurrentItem == null || CurrentItemIndex == -1) + { + return null; + } + var index = CurrentItemIndex + 1; + + if (index >= Items.Length) + { + index = 0; + } + + return Items[index]; + } + } + + /// + /// Disposes the timer + /// + private void DisposeTimer() + { + if (CurrentItemTimer != null) + { + CurrentItemTimer.Dispose(); + } + } + + /// + /// Reloads the timer + /// + private void ReloadTimer() + { + DisposeTimer(); + + // Don't bother unless there's at least two items + if (Items.Length > 1) + { + CurrentItemTimer = new Timer(state => Application.Current.Dispatcher.InvokeAsync(IncrementCurrentItemIndex), null, RotationPeriodMs, RotationPeriodMs); + } + } + + /// + /// Increments current item index, or resets it back to zero if we're at the end of the list + /// + private void IncrementCurrentItemIndex() + { + var newIndex = CurrentItemIndex + 1; + + if (newIndex >= Items.Length) + { + newIndex = 0; + } + + CurrentItemIndex = newIndex; + } + + /// + /// Disposes the collection + /// + public void Dispose() + { + DisposeTimer(); + } + } +} diff --git a/MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs b/MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs new file mode 100644 index 0000000000..9d7b9d39db --- /dev/null +++ b/MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs @@ -0,0 +1,135 @@ +using MediaBrowser.Model.DTO; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Net; +using System; +using System.Windows.Media.Imaging; + +namespace MediaBrowser.UI.ViewModels +{ + /// + /// Class SpecialFeatureViewModel + /// + public class SpecialFeatureViewModel : BaseViewModel + { + /// + /// Gets or sets the image download options. + /// + /// The image download options. + public ImageOptions ImageDownloadOptions { get; set; } + + /// + /// The _image width + /// + private double _imageWidth; + /// + /// Gets or sets the width of the image. + /// + /// The width of the image. + public double ImageWidth + { + get { return _imageWidth; } + + set + { + _imageWidth = value; + OnPropertyChanged("ImageWidth"); + } + } + + /// + /// The _image height + /// + private double _imageHeight; + /// + /// Gets or sets the height of the image. + /// + /// The height of the image. + public double ImageHeight + { + get { return _imageHeight; } + + set + { + _imageHeight = value; + OnPropertyChanged("ImageHeight"); + } + } + + /// + /// The _item + /// + private DtoBaseItem _item; + /// + /// Gets or sets the item. + /// + /// The item. + public DtoBaseItem Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + OnItemChanged(); + } + } + + /// + /// Gets the time string. + /// + /// The time string. + public string MinutesString + { + get + { + var time = TimeSpan.FromTicks(Item.RunTimeTicks ?? 0); + + var minutes = Math.Round(time.TotalMinutes); + + if (minutes <= 1) + { + return "1 minute"; + } + + return string.Format("{0} minutes", minutes); + } + } + + /// + /// The _image + /// + private BitmapImage _image; + /// + /// Gets the image. + /// + /// The image. + public BitmapImage Image + { + get { return _image; } + set + { + _image = value; + OnPropertyChanged("Image"); + } + } + + /// + /// Called when [item changed]. + /// + private async void OnItemChanged() + { + var options = ImageDownloadOptions ?? new ImageOptions { }; + + options.ImageType = ImageType.Primary; + + try + { + Image = await App.Instance.GetRemoteBitmapAsync(App.Instance.ApiClient.GetImageUrl(Item, options)); + } + catch (HttpException) + { + } + } + } +} -- cgit v1.2.3