fixes #223 - New Content Localhost Popups Repeat 'Old' 'New Content' on Media Changes

This commit is contained in:
Luke Pulverenti
2013-05-03 00:10:11 -04:00
parent b79840e20f
commit 6481688d2a
20 changed files with 287 additions and 811 deletions

View File

@@ -1,63 +0,0 @@
<UserControl x:Class="MediaBrowser.ServerApplication.Controls.ItemUpdateNotification"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid MaxHeight="280" MaxWidth="600" Margin="20">
<Border BorderThickness="0" Background="#333333">
<Border.Effect>
<DropShadowEffect BlurRadius="25" ShadowDepth="0">
</DropShadowEffect>
</Border.Effect>
</Border>
<Grid>
<Grid.Background>
<LinearGradientBrush SpreadMethod="Reflect" ColorInterpolationMode="SRgbLinearInterpolation" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="#ff222222" Offset="0" />
<GradientStop Color="#ffbbbbbb" Offset="1.0" />
</LinearGradientBrush>
</Grid.Background>
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0">
<Image x:Name="imgParentLogo" Stretch="Uniform" Height="40" RenderOptions.BitmapScalingMode="Fant" HorizontalAlignment="Left"></Image>
<TextBlock x:Name="txtParentName" FontSize="26" Foreground="White"></TextBlock>
<TextBlock x:Name="txtName" FontSize="26" Foreground="White"></TextBlock>
</StackPanel>
<Grid Grid.Row="1" Margin="0 20 0 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Column="0" Grid.RowSpan="4" Margin="0 0 20 0" VerticalAlignment="Top">
<Image x:Name="img" Stretch="Uniform" RenderOptions.BitmapScalingMode="Fant" Height="150"></Image>
</StackPanel>
<TextBlock x:Name="txtTagline" Foreground="White" Grid.Column="1" Grid.Row="0" Margin="0 0 0 20" TextWrapping="Wrap" FontStyle="Italic"></TextBlock>
<StackPanel x:Name="pnlRating" Orientation="Horizontal" Margin="0 2 0 20" Grid.Column="1" Grid.Row="1"></StackPanel>
<TextBlock x:Name="txtOverview" Foreground="White" Grid.Column="1" Grid.Row="2" TextWrapping="Wrap" Margin="0 0 0 20"></TextBlock>
<TextBlock x:Name="txtPremeireDate" Foreground="White" Grid.Column="1" Grid.Row="3"></TextBlock>
</Grid>
</Grid>
</Grid>
</Grid>
</UserControl>

View File

@@ -1,294 +0,0 @@
using System.Linq;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MediaBrowser.ServerApplication.Controls
{
/// <summary>
/// Interaction logic for ItemUpdateNotification.xaml
/// </summary>
public partial class ItemUpdateNotification : UserControl
{
/// <summary>
/// The logger
/// </summary>
private readonly ILogger Logger;
/// <summary>
/// Gets the children changed event args.
/// </summary>
/// <value>The children changed event args.</value>
private BaseItem Item
{
get { return DataContext as BaseItem; }
}
/// <summary>
/// Initializes a new instance of the <see cref="ItemUpdateNotification" /> class.
/// </summary>
public ItemUpdateNotification(ILogger logger)
{
if (logger == null)
{
throw new ArgumentNullException("logger");
}
Logger = logger;
InitializeComponent();
Loaded += ItemUpdateNotification_Loaded;
}
/// <summary>
/// Handles the Loaded event of the ItemUpdateNotification control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
void ItemUpdateNotification_Loaded(object sender, RoutedEventArgs e)
{
DisplayItem(Item);
}
/// <summary>
/// Gets the display name.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="includeParentName">if set to <c>true</c> [include parent name].</param>
/// <returns>System.String.</returns>
internal static string GetDisplayName(BaseItem item, bool includeParentName)
{
var name = item.Name;
if (item.ProductionYear.HasValue && !(item is Episode))
{
name += string.Format(" ({0})", item.ProductionYear);
}
var episode = item as Episode;
if (episode != null)
{
var indexNumbers = new List<int>();
if (episode.Season.IndexNumber.HasValue)
{
indexNumbers.Add(episode.Season.IndexNumber.Value);
}
if (episode.IndexNumber.HasValue)
{
indexNumbers.Add(episode.IndexNumber.Value);
}
var indexNumber = string.Join(".", indexNumbers.ToArray());
name = string.Format("{0} - {1}", indexNumber, name);
if (includeParentName)
{
name = episode.Series.Name + " - " + name;
}
}
if (includeParentName)
{
var season = item as Season;
if (season != null)
{
name = season.Series.Name + " - " + name;
}
}
return name;
}
/// <summary>
/// Displays the parent title.
/// </summary>
/// <param name="item">The item.</param>
private void DisplayParentTitle(BaseItem item)
{
if (!(item is Episode || item is Season))
{
txtParentName.Visibility = Visibility.Collapsed;
imgParentLogo.Visibility = Visibility.Collapsed;
return;
}
var series = item is Episode ? (item as Episode).Series : (item as Season).Series;
var logo = series.GetImage(ImageType.Logo);
if (string.IsNullOrEmpty(logo))
{
imgParentLogo.Visibility = Visibility.Collapsed;
txtParentName.Visibility = Visibility.Visible;
}
else
{
imgParentLogo.Visibility = Visibility.Visible;
txtParentName.Visibility = Visibility.Collapsed;
imgParentLogo.Source = App.Instance.GetBitmapImage(logo);
}
txtParentName.Text = series.Name;
}
/// <summary>
/// Displays the title.
/// </summary>
/// <param name="item">The item.</param>
private void DisplayTitle(BaseItem item)
{
txtName.Text = GetDisplayName(item, false);
}
/// <summary>
/// Displays the item.
/// </summary>
/// <param name="item">The item.</param>
private void DisplayItem(BaseItem item)
{
DisplayParentTitle(item);
DisplayTitle(item);
DisplayRating(item);
var path = GetImagePath(item);
if (string.IsNullOrEmpty(path))
{
img.Visibility = Visibility.Collapsed;
}
else
{
img.Visibility = Visibility.Visible;
try
{
img.Source = App.Instance.GetBitmapImage(path);
}
catch (FileNotFoundException)
{
Logger.Error("Image file not found {0}", path);
}
}
if (string.IsNullOrEmpty(item.Overview))
{
txtOverview.Visibility = Visibility.Collapsed;
}
else
{
txtOverview.Visibility = Visibility.Visible;
txtOverview.Text = item.Overview;
}
if (item.Taglines == null || item.Taglines.Count == 0)
{
txtTagline.Visibility = Visibility.Collapsed;
}
else
{
txtTagline.Visibility = Visibility.Visible;
txtTagline.Text = item.Taglines[0];
}
if (!item.PremiereDate.HasValue)
{
txtPremeireDate.Visibility = Visibility.Collapsed;
}
else
{
txtPremeireDate.Visibility = Visibility.Visible;
txtPremeireDate.Text = "Premiered " + item.PremiereDate.Value.ToLocalTime().ToShortDateString();
}
}
/// <summary>
/// Gets the image path.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
internal static string GetImagePath(BaseItem item)
{
// Try our best to find an image
var path = item.PrimaryImagePath;
if (string.IsNullOrEmpty(path) && item.BackdropImagePaths != null)
{
path = item.BackdropImagePaths.FirstOrDefault();
}
if (string.IsNullOrEmpty(path))
{
path = item.GetImage(ImageType.Thumb);
}
if (string.IsNullOrEmpty(path))
{
path = item.GetImage(ImageType.Art);
}
if (string.IsNullOrEmpty(path))
{
path = item.GetImage(ImageType.Logo);
}
if (string.IsNullOrEmpty(path))
{
path = item.GetImage(ImageType.Disc);
}
return path;
}
/// <summary>
/// Displays the rating.
/// </summary>
/// <param name="item">The item.</param>
private void DisplayRating(BaseItem item)
{
if (!item.CommunityRating.HasValue)
{
pnlRating.Visibility = Visibility.Collapsed;
return;
}
pnlRating.Children.Clear();
pnlRating.Visibility = Visibility.Visible;
var rating = item.CommunityRating.Value;
for (var i = 0; i < 10; i++)
{
Image image;
if (rating < i - 1)
{
image = App.Instance.GetImage(new Uri("../Resources/Images/starEmpty.png", UriKind.Relative));
}
else if (rating < i)
{
image = App.Instance.GetImage(new Uri("../Resources/Images/starHalf.png", UriKind.Relative));
}
else
{
image = App.Instance.GetImage(new Uri("../Resources/Images/starFull.png", UriKind.Relative));
}
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.Fant);
image.Stretch = Stretch.Uniform;
image.Height = 16;
pnlRating.Children.Add(image);
}
}
}
}

View File

@@ -1,135 +0,0 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
using MediaBrowser.ServerApplication.Controls;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace MediaBrowser.ServerApplication.EntryPoints
{
/// <summary>
/// Class NewItemNotifier
/// </summary>
public class NewItemNotifier
{
/// <summary>
/// Holds the list of new items to display when the NewItemTimer expires
/// </summary>
private readonly List<BaseItem> _newlyAddedItems = new List<BaseItem>();
/// <summary>
/// The amount of time to wait before showing a new item notification
/// This allows us to group items together into one notification
/// </summary>
private const int NewItemDelay = 60000;
/// <summary>
/// The current new item timer
/// </summary>
/// <value>The new item timer.</value>
private Timer NewItemTimer { get; set; }
/// <summary>
/// The _library manager
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The _logger
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="NewItemNotifier" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logManager">The log manager.</param>
public NewItemNotifier(ILibraryManager libraryManager, ILogManager logManager)
{
_logger = logManager.GetLogger("NewItemNotifier");
_libraryManager = libraryManager;
}
/// <summary>
/// Runs this instance.
/// </summary>
public void Run()
{
_libraryManager.LibraryChanged += libraryManager_LibraryChanged;
}
/// <summary>
/// Handles the LibraryChanged event of the libraryManager control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
{
var newItems = e.ItemsAdded.Where(i => !i.IsFolder).ToList();
// Use a timer to prevent lots of these notifications from showing in a short period of time
if (newItems.Count > 0)
{
lock (_newlyAddedItems)
{
_newlyAddedItems.AddRange(newItems);
if (NewItemTimer == null)
{
NewItemTimer = new Timer(NewItemTimerCallback, null, NewItemDelay, Timeout.Infinite);
}
else
{
NewItemTimer.Change(NewItemDelay, Timeout.Infinite);
}
}
}
}
/// <summary>
/// Called when the new item timer expires
/// </summary>
/// <param name="state">The state.</param>
private void NewItemTimerCallback(object state)
{
List<BaseItem> newItems;
// Lock the list and release all resources
lock (_newlyAddedItems)
{
newItems = _newlyAddedItems.ToList();
_newlyAddedItems.Clear();
NewItemTimer.Dispose();
NewItemTimer = null;
}
// Show the notification
if (newItems.Count > 0)
{
Application.Current.Dispatcher.InvokeAsync(() =>
{
var window = Application.Current.Windows.OfType<MainWindow>().First();
window.Dispatcher.InvokeAsync(() => window.MbTaskbarIcon.ShowCustomBalloon(new ItemUpdateNotification(_logger)
{
DataContext = newItems[0]
}, PopupAnimation.Slide, 6000));
});
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
_libraryManager.LibraryChanged -= libraryManager_LibraryChanged;
}
}
}

View File

@@ -101,10 +101,12 @@ namespace MediaBrowser.ServerApplication.EntryPoints
_userManager.UserDeleted += userManager_UserDeleted;
_userManager.UserUpdated += userManager_UserUpdated;
_libraryManager.LibraryChanged += libraryManager_LibraryChanged;
_appHost.HasPendingRestartChanged += kernel_HasPendingRestartChanged;
_libraryManager.ItemAdded += libraryManager_ItemAdded;
_libraryManager.ItemUpdated += libraryManager_ItemUpdated;
_libraryManager.ItemRemoved += libraryManager_ItemRemoved;
_installationManager.PluginUninstalled += InstallationManager_PluginUninstalled;
_installationManager.PackageInstalling += installationManager_PackageInstalling;
_installationManager.PackageInstallationCancelled += installationManager_PackageInstallationCancelled;
@@ -122,7 +124,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
void _taskManager_TaskExecuting(object sender, EventArgs e)
{
var task = (IScheduledTask) sender;
var task = (IScheduledTask)sender;
_serverManager.SendWebSocketMessage("ScheduledTaskStarted", task.Name);
}
@@ -167,11 +169,11 @@ namespace MediaBrowser.ServerApplication.EntryPoints
}
/// <summary>
/// Handles the LibraryChanged event of the libraryManager control.
/// Handles the ItemAdded event of the libraryManager control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
{
lock (_libraryChangedSyncLock)
{
@@ -190,11 +192,78 @@ namespace MediaBrowser.ServerApplication.EntryPoints
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
}
LibraryUpdateInfo.Folders.Add(e.Folder.Id);
if (e.Item.Parent != null)
{
LibraryUpdateInfo.Folders.Add(e.Item.Parent.Id);
}
LibraryUpdateInfo.ItemsAdded.AddRange(e.ItemsAdded.Select(i => i.Id));
LibraryUpdateInfo.ItemsUpdated.AddRange(e.ItemsUpdated.Select(i => i.Id));
LibraryUpdateInfo.ItemsRemoved.AddRange(e.ItemsRemoved.Select(i => i.Id));
LibraryUpdateInfo.ItemsAdded.Add(e.Item.Id);
}
}
/// <summary>
/// Handles the ItemUpdated event of the libraryManager control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemUpdated(object sender, ItemChangeEventArgs e)
{
lock (_libraryChangedSyncLock)
{
if (LibraryUpdateInfo == null)
{
LibraryUpdateInfo = new LibraryUpdateInfo();
}
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
{
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
}
if (e.Item.Parent != null)
{
LibraryUpdateInfo.Folders.Add(e.Item.Parent.Id);
}
LibraryUpdateInfo.ItemsUpdated.Add(e.Item.Id);
}
}
/// <summary>
/// Handles the ItemRemoved event of the libraryManager control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemRemoved(object sender, ItemChangeEventArgs e)
{
lock (_libraryChangedSyncLock)
{
if (LibraryUpdateInfo == null)
{
LibraryUpdateInfo = new LibraryUpdateInfo();
}
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
{
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
}
if (e.Item.Parent != null)
{
LibraryUpdateInfo.Folders.Add(e.Item.Parent.Id);
}
LibraryUpdateInfo.ItemsRemoved.Add(e.Item.Id);
}
}
@@ -281,12 +350,14 @@ namespace MediaBrowser.ServerApplication.EntryPoints
LibraryUpdateTimer.Dispose();
LibraryUpdateTimer = null;
}
_libraryManager.ItemAdded -= libraryManager_ItemAdded;
_libraryManager.ItemUpdated -= libraryManager_ItemUpdated;
_libraryManager.ItemRemoved -= libraryManager_ItemRemoved;
_userManager.UserDeleted -= userManager_UserDeleted;
_userManager.UserUpdated -= userManager_UserUpdated;
_libraryManager.LibraryChanged -= libraryManager_LibraryChanged;
_installationManager.PluginUninstalled -= InstallationManager_PluginUninstalled;
_installationManager.PackageInstalling -= installationManager_PackageInstalling;
_installationManager.PackageInstallationCancelled -= installationManager_PackageInstallationCancelled;

View File

@@ -170,7 +170,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="EntryPoints\LoadRegistrations.cs" />
<Compile Include="EntryPoints\NewItemNotifier.cs" />
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
<Compile Include="EntryPoints\StartupWizard.cs" />
<Compile Include="EntryPoints\WebSocketEvents.cs" />
@@ -181,10 +180,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Controls\ItemUpdateNotification.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="LibraryExplorer.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -205,9 +200,6 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ApplicationHost.cs" />
<Compile Include="Controls\ItemUpdateNotification.xaml.cs">
<DependentUpon>ItemUpdateNotification.xaml</DependentUpon>
</Compile>
<Compile Include="Implementations\DotNetZipClient.cs" />
<Compile Include="LibraryExplorer.xaml.cs">
<DependentUpon>LibraryExplorer.xaml</DependentUpon>