Added base decoding logic + notification logic.
This commit is contained in:
178
BodyshopUploader/Utils/Growls/GrowlNotification.xaml
Normal file
178
BodyshopUploader/Utils/Growls/GrowlNotification.xaml
Normal file
@@ -0,0 +1,178 @@
|
||||
<Window x:Class="BodyshopUploader.Utils.Growls.GrowlNotification"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BodyshopUploader.Utils.Growls"
|
||||
mc:Ignorable="d"
|
||||
SizeToContent="WidthAndHeight"
|
||||
|
||||
AllowsTransparency="True"
|
||||
WindowStyle="None"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
UseLayoutRounding="True"
|
||||
|
||||
Title="BodyshopUploader Notification"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextElement.FontWeight="Regular"
|
||||
TextElement.FontSize="13"
|
||||
TextOptions.TextFormattingMode="Ideal"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
Background="Transparent"
|
||||
FontFamily="{DynamicResource MaterialDesignFont}">
|
||||
<Window.Resources>
|
||||
<Storyboard x:Key="CollapseStoryboard">
|
||||
<DoubleAnimation From="100"
|
||||
To="0"
|
||||
Storyboard.TargetProperty="Height"
|
||||
Duration="0:0:0.5" />
|
||||
</Storyboard>
|
||||
<DataTemplate x:Key="MessageTemplate"
|
||||
DataType="Model:Notification">
|
||||
<Grid x:Name="NotificationWindow"
|
||||
Tag="{Binding Path=Id}"
|
||||
MouseLeftButtonDown="NotificationWindow_MouseLeftButtonDown"
|
||||
Background="Transparent"
|
||||
SizeChanged="NotificationWindowSizeChanged">
|
||||
<Border Name="border"
|
||||
Background="#2a3345"
|
||||
BorderThickness="0"
|
||||
CornerRadius="10"
|
||||
Margin="10">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect ShadowDepth="0"
|
||||
Opacity="0.8"
|
||||
BlurRadius="10" />
|
||||
</Border.Effect>
|
||||
<Grid Height="100"
|
||||
Width="380"
|
||||
Margin="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"></RowDefinition>
|
||||
<RowDefinition Height="Auto"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image Grid.RowSpan="2"
|
||||
Source="../../favicon.ico"
|
||||
Margin="4"
|
||||
Width="24"></Image>
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding Path=Title}"
|
||||
TextOptions.TextRenderingMode="ClearType"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
Foreground="White"
|
||||
FontFamily="Arial"
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,4,4,2"
|
||||
TextWrapping="Wrap"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<!--<Button x:Name="CloseButton" Grid.Column="1" Width="16" Height="16" HorizontalAlignment="Right" Margin="0,0,12,0" />-->
|
||||
|
||||
<Button x:Name="CloseButton"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}"
|
||||
HorizontalAlignment="Right"
|
||||
Width="24"
|
||||
Height="24">
|
||||
<materialDesign:PackIcon Kind="Close"
|
||||
Height="16"
|
||||
Width="16" />
|
||||
</Button>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Text="{Binding Path=Subtitle}"
|
||||
TextOptions.TextRenderingMode="ClearType"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
Foreground="White"
|
||||
FontFamily="Arial"
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,4,4,2"
|
||||
TextWrapping="Wrap"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<TextBlock Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Text="{Binding Path=Message}"
|
||||
TextOptions.TextRenderingMode="ClearType"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
Foreground="White"
|
||||
FontFamily="Arial"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,2,4,4"
|
||||
TextWrapping="Wrap"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<DataTemplate.Triggers>
|
||||
<EventTrigger RoutedEvent="Window.Loaded"
|
||||
SourceName="NotificationWindow">
|
||||
<BeginStoryboard x:Name="FadeInStoryBoard">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="NotificationWindow"
|
||||
From="0.01"
|
||||
To="1"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
Duration="0:0:1" />
|
||||
<DoubleAnimation Storyboard.TargetName="NotificationWindow"
|
||||
From="1"
|
||||
To="0"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
Duration="0:0:2"
|
||||
BeginTime="0:0:3" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<Trigger Property="IsMouseOver"
|
||||
Value="True">
|
||||
<Trigger.EnterActions>
|
||||
<SeekStoryboard Offset="0:0:1"
|
||||
BeginStoryboardName="FadeInStoryBoard" />
|
||||
<PauseStoryboard BeginStoryboardName="FadeInStoryBoard" />
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<SeekStoryboard Offset="0:0:1"
|
||||
BeginStoryboardName="FadeInStoryBoard" />
|
||||
<ResumeStoryboard BeginStoryboardName="FadeInStoryBoard"></ResumeStoryboard>
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
<EventTrigger RoutedEvent="Button.Click"
|
||||
SourceName="CloseButton">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="NotificationWindow"
|
||||
From="1"
|
||||
To="0"
|
||||
Storyboard.TargetProperty="(Grid.Opacity)"
|
||||
Duration="0:0:0" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<Trigger SourceName="NotificationWindow"
|
||||
Property="Opacity"
|
||||
Value="0">
|
||||
<Setter TargetName="NotificationWindow"
|
||||
Property="Visibility"
|
||||
Value="Hidden"></Setter>
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard Storyboard="{StaticResource CollapseStoryboard}" />
|
||||
</Trigger.EnterActions>
|
||||
</Trigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</Window.Resources>
|
||||
<ItemsControl x:Name="NotificationsControl"
|
||||
FocusVisualStyle="{x:Null}"
|
||||
ItemsSource="{Binding .}"
|
||||
ItemTemplate="{StaticResource MessageTemplate}" />
|
||||
</Window>
|
||||
91
BodyshopUploader/Utils/Growls/GrowlNotification.xaml.cs
Normal file
91
BodyshopUploader/Utils/Growls/GrowlNotification.xaml.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
|
||||
namespace BodyshopUploader.Utils.Growls
|
||||
{
|
||||
public partial class GrowlNotification
|
||||
{
|
||||
private const byte MAX_NOTIFICATIONS = 4;
|
||||
private int count;
|
||||
public Notifications Notifications = new Notifications();
|
||||
private readonly Notifications buffer = new Notifications();
|
||||
public ViewModels.MainViewModel ShellVm;
|
||||
public GrowlNotification(ViewModels.MainViewModel shellViewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
ShellVm = shellViewModel;
|
||||
NotificationsControl.DataContext = Notifications;
|
||||
var desktopWorkingArea = System.Windows.SystemParameters.WorkArea;
|
||||
this.Left = desktopWorkingArea.Right - 425;
|
||||
//this.Top = desktopWorkingArea.Bottom - 425;
|
||||
this.Top = 50;
|
||||
}
|
||||
|
||||
public void AddNotification(Notification notification)
|
||||
{
|
||||
notification.Id = count++;
|
||||
if (Notifications.Count + 1 > MAX_NOTIFICATIONS)
|
||||
buffer.Add(notification);
|
||||
else
|
||||
Notifications.Add(notification);
|
||||
//Show window if there're notifications
|
||||
if (Notifications.Count > 0 && !IsActive)
|
||||
Show();
|
||||
}
|
||||
public void RemoveNotification(Notification notification)
|
||||
{
|
||||
if (Notifications.Contains(notification))
|
||||
Notifications.Remove(notification);
|
||||
if (buffer.Count > 0)
|
||||
{
|
||||
Notifications.Add(buffer[0]);
|
||||
buffer.RemoveAt(0);
|
||||
}
|
||||
//Close window if there's nothing to show
|
||||
if (Notifications.Count < 1)
|
||||
Hide();
|
||||
}
|
||||
private void NotificationWindowSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (e.NewSize.Height != 0.0)
|
||||
return;
|
||||
var element = sender as Grid;
|
||||
RemoveNotification(Notifications.First(
|
||||
n => n.Id == Int32.Parse(element.Tag.ToString())));
|
||||
}
|
||||
|
||||
private void NotificationWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Notification n = (Notification)((Grid)sender).DataContext;
|
||||
BringWindowToFront();
|
||||
RemoveNotification(n);
|
||||
}
|
||||
|
||||
static void BringWindowToFront()
|
||||
{
|
||||
var currentProcess = Process.GetCurrentProcess();
|
||||
var processes = Process.GetProcessesByName(currentProcess.ProcessName);
|
||||
var process = processes.FirstOrDefault(p => p.Id == currentProcess.Id);
|
||||
if (process == null) return;
|
||||
|
||||
SetForegroundWindow(process.MainWindowHandle);
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
}
|
||||
}
|
||||
102
BodyshopUploader/Utils/Growls/Notification.cs
Normal file
102
BodyshopUploader/Utils/Growls/Notification.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BodyshopUploader.Utils.Growls
|
||||
{
|
||||
public class Notification : INotifyPropertyChanged
|
||||
{
|
||||
private string message;
|
||||
public string Message
|
||||
{
|
||||
get { return message; }
|
||||
|
||||
set
|
||||
{
|
||||
if (message == value) return;
|
||||
message = value;
|
||||
OnPropertyChanged("Message");
|
||||
}
|
||||
}
|
||||
|
||||
private int id;
|
||||
public int Id
|
||||
{
|
||||
get { return id; }
|
||||
|
||||
set
|
||||
{
|
||||
if (id == value) return;
|
||||
id = value;
|
||||
OnPropertyChanged("Id");
|
||||
}
|
||||
}
|
||||
|
||||
private int threadid;
|
||||
public int ThreadId
|
||||
{
|
||||
get { return threadid; }
|
||||
|
||||
set
|
||||
{
|
||||
if (threadid == value) return;
|
||||
threadid = value;
|
||||
OnPropertyChanged("ThreadId");
|
||||
}
|
||||
}
|
||||
|
||||
private string imageUrl;
|
||||
public string ImageUrl
|
||||
{
|
||||
get { return imageUrl; }
|
||||
|
||||
set
|
||||
{
|
||||
if (imageUrl == value) return;
|
||||
imageUrl = value;
|
||||
OnPropertyChanged("ImageUrl");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string title;
|
||||
public string Title
|
||||
{
|
||||
get { return title; }
|
||||
|
||||
set
|
||||
{
|
||||
if (title == value) return;
|
||||
title = value;
|
||||
OnPropertyChanged("Title");
|
||||
}
|
||||
}
|
||||
|
||||
private string subtitle;
|
||||
public string Subtitle
|
||||
{
|
||||
get { return subtitle; }
|
||||
|
||||
set
|
||||
{
|
||||
if (subtitle == value) return;
|
||||
subtitle = value;
|
||||
OnPropertyChanged("Subtitle");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
var handler = PropertyChanged;
|
||||
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
}
|
||||
|
||||
public class Notifications : ObservableCollection<Notification> { }
|
||||
}
|
||||
Reference in New Issue
Block a user