diff options
Diffstat (limited to 'MediaBrowser.UI/ViewModels')
| -rw-r--r-- | MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.UI/ViewModels/BaseViewModel.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.UI/ViewModels/ChapterInfoDtoViewModel.cs | 182 | ||||
| -rw-r--r-- | MediaBrowser.UI/ViewModels/DtoBaseItemViewModel.cs | 184 | ||||
| -rw-r--r-- | MediaBrowser.UI/ViewModels/ItemCollectionViewModel.cs | 158 | ||||
| -rw-r--r-- | MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs | 135 |
6 files changed, 713 insertions, 0 deletions
diff --git a/MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs b/MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs new file mode 100644 index 000000000..95ff86094 --- /dev/null +++ b/MediaBrowser.UI/ViewModels/BaseItemPersonViewModel.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Model.DTO; + +namespace MediaBrowser.UI.ViewModels +{ + public class BaseItemPersonViewModel : BaseViewModel + { + /// <summary> + /// The _item + /// </summary> + private BaseItemPerson _item; + /// <summary> + /// Gets or sets the item. + /// </summary> + /// <value>The item.</value> + 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 000000000..03ac9d18a --- /dev/null +++ b/MediaBrowser.UI/ViewModels/BaseViewModel.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; + +namespace MediaBrowser.UI.ViewModels +{ + /// <summary> + /// Represents a base ViewModel + /// </summary> + public abstract class BaseViewModel : INotifyPropertyChanged + { + /// <summary> + /// Occurs when [property changed]. + /// </summary> + public event PropertyChangedEventHandler PropertyChanged; + + /// <summary> + /// Called when [property changed]. + /// </summary> + /// <param name="name">The name.</param> + 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 000000000..53ab787c4 --- /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 +{ + /// <summary> + /// Class ChapterInfoDtoViewModel + /// </summary> + public class ChapterInfoDtoViewModel : BaseViewModel + { + /// <summary> + /// Gets or sets the image download options. + /// </summary> + /// <value>The image download options.</value> + public ImageOptions ImageDownloadOptions { get; set; } + + /// <summary> + /// The _image width + /// </summary> + private double _imageWidth; + /// <summary> + /// Gets or sets the width of the image. + /// </summary> + /// <value>The width of the image.</value> + public double ImageWidth + { + get { return _imageWidth; } + + set + { + _imageWidth = value; + OnPropertyChanged("ImageWidth"); + } + } + + /// <summary> + /// The _image height + /// </summary> + private double _imageHeight; + /// <summary> + /// Gets or sets the height of the image. + /// </summary> + /// <value>The height of the image.</value> + public double ImageHeight + { + get { return _imageHeight; } + + set + { + _imageHeight = value; + OnPropertyChanged("ImageHeight"); + } + } + + /// <summary> + /// The _item + /// </summary> + private ChapterInfoDto _chapter; + /// <summary> + /// Gets or sets the item. + /// </summary> + /// <value>The item.</value> + public ChapterInfoDto Chapter + { + get { return _chapter; } + + set + { + _chapter = value; + OnPropertyChanged("Chapter"); + OnPropertyChanged("TimeString"); + OnChapterChanged(); + } + } + + /// <summary> + /// The _item + /// </summary> + private DtoBaseItem _item; + /// <summary> + /// Gets or sets the item. + /// </summary> + /// <value>The item.</value> + public DtoBaseItem Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + } + } + + /// <summary> + /// Gets the time string. + /// </summary> + /// <value>The time string.</value> + public string TimeString + { + get + { + var time = TimeSpan.FromTicks(Chapter.StartPositionTicks); + + return time.ToString(time.TotalHours < 1 ? "m':'ss" : "h':'mm':'ss"); + } + } + + /// <summary> + /// The _image + /// </summary> + private BitmapImage _image; + /// <summary> + /// Gets the image. + /// </summary> + /// <value>The image.</value> + public BitmapImage Image + { + get { return _image; } + set + { + _image = value; + OnPropertyChanged("Image"); + } + } + + /// <summary> + /// Called when [item changed]. + /// </summary> + 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) + { + } + } + + /// <summary> + /// Gets the height of the chapter image. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="height">The height.</param> + /// <param name="defaultWidth">The default width.</param> + /// <returns>System.Double.</returns> + 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 000000000..0c9e27db3 --- /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 +{ + /// <summary> + /// Class DtoBaseItemViewModel + /// </summary> + public class DtoBaseItemViewModel : BaseViewModel + { + /// <summary> + /// The _average primary image aspect ratio + /// </summary> + private double _averagePrimaryImageAspectRatio; + /// <summary> + /// Gets the aspect ratio that should be used if displaying the primary image + /// </summary> + /// <value>The average primary image aspect ratio.</value> + public double AveragePrimaryImageAspectRatio + { + get { return _averagePrimaryImageAspectRatio; } + + set + { + _averagePrimaryImageAspectRatio = value; + OnPropertyChanged("AveragePrimaryImageAspectRatio"); + } + } + + /// <summary> + /// The _parent display preferences + /// </summary> + private DisplayPreferences _parentDisplayPreferences; + /// <summary> + /// Gets of sets the current DisplayPreferences + /// </summary> + /// <value>The parent display preferences.</value> + public DisplayPreferences ParentDisplayPreferences + { + get { return _parentDisplayPreferences; } + + set + { + _parentDisplayPreferences = value; + NotifyDisplayPreferencesChanged(); + } + } + + /// <summary> + /// The _item + /// </summary> + private DtoBaseItem _item; + /// <summary> + /// Gets or sets the item. + /// </summary> + /// <value>The item.</value> + public DtoBaseItem Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + } + } + + /// <summary> + /// Notifies the display preferences changed. + /// </summary> + public void NotifyDisplayPreferencesChanged() + { + OnPropertyChanged("DisplayPreferences"); + } + + /// <summary> + /// Gets an image url that can be used to download an image from the api + /// </summary> + /// <param name="imageType">The type of image requested</param> + /// <param name="imageIndex">The image index, if there are multiple. Currently only applies to backdrops. Supply null or 0 for first backdrop.</param> + /// <returns>System.String.</returns> + 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); + } + + /// <summary> + /// Gets the average primary image aspect ratio. + /// </summary> + /// <param name="items">The items.</param> + /// <returns>System.Double.</returns> + /// <exception cref="System.ArgumentNullException">items</exception> + public static double GetAveragePrimaryImageAspectRatio(IEnumerable<DtoBaseItem> 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; + } + + /// <summary> + /// Gets the observable items. + /// </summary> + /// <param name="items">The items.</param> + /// <returns>ObservableCollection{DtoBaseItemViewModel}.</returns> + public static ObservableCollection<DtoBaseItemViewModel> GetObservableItems(DtoBaseItem[] items) + { + return GetObservableItems(items, GetAveragePrimaryImageAspectRatio(items)); + } + + /// <summary> + /// Gets the observable items. + /// </summary> + /// <param name="items">The items.</param> + /// <param name="averagePrimaryImageAspectRatio">The average primary image aspect ratio.</param> + /// <param name="parentDisplayPreferences">The parent display preferences.</param> + /// <returns>ObservableCollection{DtoBaseItemViewModel}.</returns> + /// <exception cref="System.ArgumentNullException">items</exception> + public static ObservableCollection<DtoBaseItemViewModel> GetObservableItems(IEnumerable<DtoBaseItem> items, double averagePrimaryImageAspectRatio, DisplayPreferences parentDisplayPreferences = null) + { + if (items == null) + { + throw new ArgumentNullException("items"); + } + + return new ObservableCollection<DtoBaseItemViewModel>(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 000000000..82feedbd7 --- /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 +{ + /// <summary> + /// 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. + /// </summary> + 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; + } + + /// <summary> + /// Gets the timer that updates the current item + /// </summary> + private Timer CurrentItemTimer { get; set; } + + private string _name; + /// <summary> + /// Gets or sets the name of the collection + /// </summary> + public string Name + { + get { return _name; } + set + { + _name = value; + OnPropertyChanged("Name"); + } + } + + private DtoBaseItem[] _items; + /// <summary> + /// Gets or sets the list of items + /// </summary> + public DtoBaseItem[] Items + { + get { return _items; } + set + { + _items = value ?? new DtoBaseItem[] { }; + OnPropertyChanged("Items"); + CurrentItemIndex = Items.Length == 0 ? -1 : 0; + + ReloadTimer(); + } + } + + private int _currentItemIndex; + /// <summary> + /// Gets or sets the index of the current item + /// </summary> + public int CurrentItemIndex + { + get { return _currentItemIndex; } + set + { + _currentItemIndex = value; + OnPropertyChanged("CurrentItemIndex"); + OnPropertyChanged("CurrentItem"); + OnPropertyChanged("NextItem"); + } + } + + /// <summary> + /// Gets the current item + /// </summary> + public DtoBaseItem CurrentItem + { + get { return CurrentItemIndex == -1 ? null : Items[CurrentItemIndex]; } + } + + /// <summary> + /// Gets the next item + /// </summary> + public DtoBaseItem NextItem + { + get + { + if (CurrentItem == null || CurrentItemIndex == -1) + { + return null; + } + var index = CurrentItemIndex + 1; + + if (index >= Items.Length) + { + index = 0; + } + + return Items[index]; + } + } + + /// <summary> + /// Disposes the timer + /// </summary> + private void DisposeTimer() + { + if (CurrentItemTimer != null) + { + CurrentItemTimer.Dispose(); + } + } + + /// <summary> + /// Reloads the timer + /// </summary> + 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); + } + } + + /// <summary> + /// Increments current item index, or resets it back to zero if we're at the end of the list + /// </summary> + private void IncrementCurrentItemIndex() + { + var newIndex = CurrentItemIndex + 1; + + if (newIndex >= Items.Length) + { + newIndex = 0; + } + + CurrentItemIndex = newIndex; + } + + /// <summary> + /// Disposes the collection + /// </summary> + public void Dispose() + { + DisposeTimer(); + } + } +} diff --git a/MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs b/MediaBrowser.UI/ViewModels/SpecialFeatureViewModel.cs new file mode 100644 index 000000000..9d7b9d39d --- /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 +{ + /// <summary> + /// Class SpecialFeatureViewModel + /// </summary> + public class SpecialFeatureViewModel : BaseViewModel + { + /// <summary> + /// Gets or sets the image download options. + /// </summary> + /// <value>The image download options.</value> + public ImageOptions ImageDownloadOptions { get; set; } + + /// <summary> + /// The _image width + /// </summary> + private double _imageWidth; + /// <summary> + /// Gets or sets the width of the image. + /// </summary> + /// <value>The width of the image.</value> + public double ImageWidth + { + get { return _imageWidth; } + + set + { + _imageWidth = value; + OnPropertyChanged("ImageWidth"); + } + } + + /// <summary> + /// The _image height + /// </summary> + private double _imageHeight; + /// <summary> + /// Gets or sets the height of the image. + /// </summary> + /// <value>The height of the image.</value> + public double ImageHeight + { + get { return _imageHeight; } + + set + { + _imageHeight = value; + OnPropertyChanged("ImageHeight"); + } + } + + /// <summary> + /// The _item + /// </summary> + private DtoBaseItem _item; + /// <summary> + /// Gets or sets the item. + /// </summary> + /// <value>The item.</value> + public DtoBaseItem Item + { + get { return _item; } + + set + { + _item = value; + OnPropertyChanged("Item"); + OnItemChanged(); + } + } + + /// <summary> + /// Gets the time string. + /// </summary> + /// <value>The time string.</value> + 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); + } + } + + /// <summary> + /// The _image + /// </summary> + private BitmapImage _image; + /// <summary> + /// Gets the image. + /// </summary> + /// <value>The image.</value> + public BitmapImage Image + { + get { return _image; } + set + { + _image = value; + OnPropertyChanged("Image"); + } + } + + /// <summary> + /// Called when [item changed]. + /// </summary> + 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) + { + } + } + } +} |
