Massennachricht hinzugefügt

Optik an die vom Android- und Webclient angepasst
Asynchrone Methoden verbessert
This commit is contained in:
LynJet
2022-07-11 16:01:14 +02:00
parent 6daa1ce73a
commit 410945af20
17 changed files with 929 additions and 171 deletions

View File

@@ -67,6 +67,7 @@
<DependentUpon>ChatMainControl.xaml</DependentUpon>
</Compile>
<Compile Include="Converter\BoolToVisibilityConverter.cs" />
<Compile Include="Converter\BroadcastCheckBoxVisibilityMultiConverter.cs" />
<Compile Include="Converter\StringEmptyToVisibilityConverter.cs" />
<Compile Include="Converter\StringToBoolConverter.cs" />
<Compile Include="Converter\UserProfilePictureVisibilityConverter.cs" />
@@ -99,10 +100,14 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
<Compile Include="Utilities\BroadcastMessage.cs" />
<Compile Include="Utilities\BroadcastProgressReportModel.cs" />
<Compile Include="Utilities\Constants.cs" />
<Compile Include="Utilities\Extensions\ControlExtensions.cs" />
<Compile Include="Utilities\Extensions\DateTimeExtensions.cs" />
<Compile Include="Utilities\Extensions\ObservableSortCollection.cs" />
<Compile Include="Utilities\FileUtils.cs" />
<Compile Include="Utilities\ListItemHelper.cs" />
<Compile Include="Utilities\OwnChatEnums.cs" />
<Compile Include="Utilities\SyncFileInfoStruct.cs" />
<Compile Include="Utilities\Utils.cs" />
@@ -148,6 +153,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="ownchat_favicon.ico" />
<Resource Include="Ressourcen\TasksSolid.png" />
<Resource Include="Ressourcen\ownchat_image_placeholder.png" />
<Resource Include="Ressourcen\warning-exclamation-mark.png" />
<None Include="packages.config" />

View File

@@ -4,10 +4,11 @@ using System.ComponentModel;
using System.Windows.Documents;
using System.Windows.Media;
using ChatController.Core;
using ChatController.HauptKlassen;
using ChatController.Utilities;
using static System.Windows.HorizontalAlignment;
using Application = System.Windows.Application;
using Brush = System.Windows.Media.Brush;
using Color = System.Windows.Media.Color;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
namespace ChatController.ChatKlassen
@@ -147,9 +148,11 @@ namespace ChatController.ChatKlassen
public string SendTimeString => SendTime.Date == DateTime.Today ? $"Heute {SendTime:HH:mm}" : SendTime.ToString("dd. MMM HH:mm");
public Brush BorderBrush => IsSeparator ? new SolidColorBrush(Colors.Transparent) : IsMyMessage ? new SolidColorBrush(Color.FromRgb(255, 90, 0)) : new SolidColorBrush(Color.FromRgb(229, 229, 229));
public Brush BorderBrush => IsSeparator ? new SolidColorBrush(Colors.Transparent) : IsMyMessage ? new SolidColorBrush(Color.FromRgb(255, 90, 0)) : new SolidColorBrush(Color.FromRgb(255, 255, 255));
public Brush HighlightedBorderBrush => IsSeparator ? new SolidColorBrush(Colors.Transparent) : IsMyMessage ? new SolidColorBrush(Color.FromRgb(255, 153, 153)) : new SolidColorBrush(Color.FromRgb(247, 247, 247));
public Brush HighlightedBorderBrush => IsSeparator ? new SolidColorBrush(Colors.Transparent) : IsMyMessage ? new SolidColorBrush(Color.FromRgb(255, 152, 143)) : new SolidColorBrush(Color.FromRgb(247, 247, 247));
public Brush TextColor => !IsMyMessage && !IsSeparator ? new SolidColorBrush(Colors.Black) : new SolidColorBrush(Colors.White);
public Brush Foreground => new BrushConverter().ConvertFromString("#505050") as SolidColorBrush;

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using ChatController.Core;
using ChatController.LoginKlassen;
@@ -179,4 +180,14 @@ namespace ChatController.ChatKlassen
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ContactDependencyObject : DependencyObject
{
public Contact Contact { get; set; }
public ContactDependencyObject(Contact contact)
{
Contact = contact;
}
}
}

View File

@@ -7,18 +7,132 @@
xmlns:chatKlassen="clr-namespace:ChatController.ChatKlassen"
xmlns:core="clr-namespace:ChatController.Core"
xmlns:chatController="clr-namespace:ChatController"
mc:Ignorable="d" x:Name="ChatControlling"
xmlns:utilities="clr-namespace:ChatController.Utilities"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="600"
Loaded="ChatMainControl_OnLoaded"
SnapsToDevicePixels="True" d:DataContext="{d:DesignData ChatMainControl}">
<UserControl.Resources>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converter:StringEmptyToVisibilityConverter x:Key="StringEmptyToVisibilityConverter" />
<converter:StringToBoolConverter x:Key="StringToBoolConverter" />
<converter:UserProfilePictureVisibilityConverter x:Key="UserProfilePictureVisibilityConverter" />
<converter:BroadcastCheckBoxVisibilityMultiConverter x:Key="BroadcastCheckBoxVisibilityMultiConverter" />
<SolidColorBrush x:Key="DarkBackColor" Color="#FFA9B8C2" />
<SolidColorBrush x:Key="LightBackColor" Color="#E8EFF4" />
<!--<SolidColorBrush x:Key="DarkBackColor" Color="#A9B8C2" />-->
<SolidColorBrush x:Key="DarkBackColor" Color="#A9B8C2" />
<SolidColorBrush x:Key="LightBackColor" Color="#F3F3F3" />
<Style x:Key="OrangeButtonStyle" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="#FF5A00" />
<Setter Property="Background" Value="#FF5A00" />
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border" Background="#FF5A00" CornerRadius="5" Padding="5,2">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF988F" TargetName="Border" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#FF7654" TargetName="Border" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="LightGray" TargetName="Border" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CloseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="Width" Value="Auto" />
<Setter Property="Height" Value="Auto" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Storyboard x:Key="Timeline1">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" To="1.3" Duration="0:0:0.2" />
<DoubleAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" To="1.3" Duration="0:0:0.2" />
</Storyboard>
<Storyboard x:Key="Timeline2">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" Duration="0:0:0.2" />
<DoubleAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" Duration="0:0:0.2" />
</Storyboard>
</ControlTemplate.Resources>
<Grid SnapsToDevicePixels="true" x:Name="grid" MinWidth="20" MinHeight="20">
<Border x:Name="border" BorderBrush="#FF000000" BorderThickness="1,1,1,1" CornerRadius="3,3,3,3" Padding="0,0,0,0" Margin="0,0,0,0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF450202" Offset="0" />
<GradientStop Color="#FFC61A1A" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<Border Opacity="0" HorizontalAlignment="Stretch" x:Name="glow" Width="Auto" Grid.RowSpan="2" CornerRadius="3,3,3,3">
<Border.Background>
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.702" ScaleY="2.243" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="-0.368" Y="-0.152" />
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#B2FFFFFF" Offset="0" />
<GradientStop Color="#00FF9E9A" Offset="1" />
</RadialGradientBrush>
</Border.Background>
</Border>
<Border Grid.Row="0" HorizontalAlignment="Stretch" Margin="0,0,0,0" x:Name="shine" Width="Auto" CornerRadius="3,3,0,0">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99FFFFFF" Offset="0" />
<GradientStop Color="#33FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Webdings" FontSize="16" Foreground="#FFFFFFFF" TextWrapping="Wrap"
Grid.Row="0" Grid.RowSpan="2">
<Run Text="r" />
</TextBlock>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Timeline1}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard x:Name="Timeline2_BeginStoryboard" Storyboard="{StaticResource Timeline2}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MainNavigationScrollViewer" TargetType="{x:Type ScrollViewer}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
@@ -77,21 +191,38 @@
<Setter.Value>
<ControlTemplate>
<Grid>
<Border x:Name="ItemBorder" MinHeight="20" Background="White" BorderThickness="0,0,0,1" BorderBrush="{StaticResource LightBackColor}">
<Border x:Name="ItemBorder" MinHeight="20" Background="White" BorderThickness="0,0,0,0" BorderBrush="{StaticResource LightBackColor}">
</Border>
<Border x:Name="ItemContent" MinHeight="20">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" VerticalAlignment="Center" Margin="0,0,7,0"
Click="ContactCheckBox_OnClick" Checked="ContactCheckBox_OnChecked" Unchecked="ContactCheckBox_OnChecked"
IsChecked="{Binding Path=(utilities:ListItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<CheckBox.Visibility>
<MultiBinding Converter="{StaticResource BroadcastCheckBoxVisibilityMultiConverter}">
<Binding Path="Chat.IsInBroadcastMode" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type chatController:ChatMainControl}}" UpdateSourceTrigger="PropertyChanged" />
<Binding Path="Contact.IsChatMessageInputGridVisible" />
</MultiBinding>
</CheckBox.Visibility>
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(utilities:ListItemHelper.IsChecked), Mode=TwoWay}" Value="False" />
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<Ellipse Grid.Column="1" Width='32' Height='32' RenderOptions.BitmapScalingMode="HighQuality">
<Ellipse.Fill>
<ImageBrush ImageSource='{Binding Image, UpdateSourceTrigger=PropertyChanged}' Stretch='UniformToFill' RenderOptions.BitmapScalingMode="HighQuality" />
<ImageBrush ImageSource='{Binding Contact.Image, UpdateSourceTrigger=PropertyChanged}' Stretch='UniformToFill' RenderOptions.BitmapScalingMode="HighQuality" />
</Ellipse.Fill>
</Ellipse>
<Grid Grid.Column="3">
@@ -99,8 +230,8 @@
<RowDefinition Height="*" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Path=Name, FallbackValue=FirstName}" Foreground="{Binding Path=AccentColorBrush}" FontSize="16" Margin="1" />
<TextBlock Text="{Binding Path=ReceivedMessage.Text}" Grid.Row="1" FontSize="14" Foreground="{Binding Path=Color}" Margin="1" />
<TextBlock Text="{Binding Path=Contact.Name, FallbackValue=FirstName}" Foreground="{Binding Path=Contact.AccentColorBrush}" FontSize="16" Margin="1" />
<TextBlock Text="{Binding Path=Contact.ReceivedMessage.Text}" Grid.Row="1" FontSize="14" Foreground="{Binding Path=Contact.Color}" Margin="1" />
</Grid>
</Grid>
</Border>
@@ -188,9 +319,16 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="ReloadGruppen" Grid.Row="0" Grid.Column="1" Height="25" Width="25" HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center" Visibility="Visible" Margin="0,0,3,0">
<Button Background="Transparent" HorizontalAlignment="Right" BorderThickness="0" VerticalAlignment="Center" VerticalContentAlignment="Center" Width="25" Height="25" Click="ButtonReloadGruppen_OnClick" >
<Image ToolTip="Gruppen Aktualisieren" Margin="0,0,0,0" Width="20" Height="20" Source="pack://application:,,,/ChatController;component/Ressourcen/SymbolRefresh32.png" RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Center" />
<StackPanel x:Name="ReloadGruppen" Grid.Row="0" Grid.Column="1" Height="25" HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center" Visibility="Visible" Margin="0,0,3,0">
<Button Background="Transparent" HorizontalAlignment="Right" BorderThickness="0"
VerticalAlignment="Center" VerticalContentAlignment="Center" Width="25" Height="25" Click="ButtonReloadGruppen_OnClick" >
<Image ToolTip="Gruppen Aktualisieren" Margin="0,0,0,0" Width="20" Height="20"
Source="pack://application:,,,/ChatController;component/Ressourcen/SymbolRefresh32.png" RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Center" />
</Button>
<Button HorizontalAlignment="Right" Background="Transparent" VerticalAlignment="Center" VerticalContentAlignment="Center"
Click="BroadcastButton_OnClick" Style="{StaticResource OrangeButtonStyle}" Margin="5,0,0,0">
<Image ToolTip="Nachricht an mehrere Empfänger schicken" Margin="0" Width="20" Height="20"
Source="pack://application:,,,/ChatController;component/Ressourcen/TasksSolid.png" RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Center" />
</Button>
</StackPanel>
@@ -201,12 +339,16 @@
<!-- region Kontaktliste -->
<Grid Grid.Column="0" Grid.Row="1" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView x:Name="Clientlist" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" BorderThickness="0" Background="White"
<CheckBox Grid.Row="0" Margin="5" x:Name="SelectAllContactsCheckBox" FontSize="16" Content="Alle auswählen" VerticalContentAlignment="Center" VerticalAlignment="Center" Height="35"
Click="SelectAllContacts_OnClick"
Visibility="{Binding Path=Chat.IsInBroadcastMode, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=reverse}" />
<ListView x:Name="Clientlist" HorizontalAlignment="Stretch" Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch" BorderThickness="0" Background="White"
ItemsSource="{Binding ContactList, UpdateSourceTrigger=PropertyChanged}"
ItemContainerStyle="{StaticResource ContactListBoxItemStyle}" SelectionChanged="Clientlist_OnSelectionChanged" Style="{StaticResource ContactListStyle}">
</ListView>
@@ -254,6 +396,7 @@
Background="{StaticResource LightBackColor}"
ContextMenuOpening="Chat_OnContextMenuOpening"
Padding="20"
Visibility="{Binding Path=Chat.IsInBroadcastMode, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type chatController:ChatMainControl}}, Converter={StaticResource BoolToVisibilityConverter}}"
d:DataContext="{d:DesignData ChatMessage}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
@@ -334,11 +477,15 @@
<DockPanel Grid.Column="1" Grid.ColumnSpan="3" MinHeight="15" Margin="5" LastChildFill="True" Visibility="{Binding IsSeparator, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel DockPanel.Dock="Bottom" Orientation="Vertical">
<Image ToolTip="Dokument öffnen" Height="{Binding ThumbnailPlaceholderHeight, UpdateSourceTrigger=PropertyChanged}" Width="150" Source="{Binding Path=Thumbnail, UpdateSourceTrigger=PropertyChanged}" Stretch="Uniform" VerticalAlignment="Center" HorizontalAlignment="Center" />
<Image MaxWidth="300" Height="{Binding PicturePlaceholderHeight, UpdateSourceTrigger=PropertyChanged}" Source="{Binding Path=PictureSource, UpdateSourceTrigger=PropertyChanged}" x:Name="imgChatMessage" Stretch="UniformToFill" />
<Image ToolTip="Dokument öffnen" Height="{Binding ThumbnailPlaceholderHeight, UpdateSourceTrigger=PropertyChanged}" Width="150"
Source="{Binding Path=Thumbnail, UpdateSourceTrigger=PropertyChanged}"
Stretch="Uniform" VerticalAlignment="Center" HorizontalAlignment="Center" />
<Image MaxHeight="300"
Source="{Binding Path=PictureSource, UpdateSourceTrigger=PropertyChanged}"
x:Name="imgChatMessage" Stretch="Uniform" RenderOptions.BitmapScalingMode="HighQuality" />
<core:OwnChatRichTextBox VerticalAlignment="Center" InlineList="{Binding MessageInlines, UpdateSourceTrigger=PropertyChanged}"
MinWidth="0" MaxWidth="{Binding MessageMaxWidth}" FontSize="14" IsReadOnly="True"
HorizontalAlignment="{Binding HorizontalAlignmentValue}"
HorizontalAlignment="{Binding HorizontalAlignmentValue}" Foreground="{Binding TextColor, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
BorderThickness="0" Background="Transparent" IsDocumentEnabled="True" Margin="-5,0,0,0" />
</StackPanel>
<StackPanel DockPanel.Dock="Left" Margin="0,0,0,0">
@@ -368,6 +515,24 @@
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Row="1" Grid.Column="0" Visibility="{Binding Path=Chat.IsInBroadcastMode, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=reverse}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" Height="20" Width="20" HorizontalAlignment="Right" Style="{DynamicResource CloseButtonStyle}" Click="AbortBroadcastButton_OnClick" />
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="5" VerticalAlignment="Center">
<TextBlock Text="{Binding BroadcastInfoText, UpdateSourceTrigger=PropertyChanged}" Foreground="Black"
HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center" FontSize="16" Margin="20, 0" />
<ProgressBar Margin="20, 5" Value="{Binding BroadcastProgressValue, UpdateSourceTrigger=PropertyChanged}" Height="20" />
<Image MaxHeight="300" RenderOptions.BitmapScalingMode="HighQuality"
Source="{Binding Path=BroadcastMessage.BroadcastMessageImageSource, UpdateSourceTrigger=PropertyChanged}" Stretch="Uniform"
/>
<Button Content="Abbrechen" Width="75" Style="{StaticResource OrangeButtonStyle}" Height="25" Margin="0, 5"
Click="CancelBroadcastButton_OnClick" />
</StackPanel>
</Grid>
<Grid Grid.Row="2" Visibility="{Binding ChatMessageInputGridVisibility}" VerticalAlignment="Stretch" MinHeight="25" MaxHeight="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
@@ -392,6 +557,7 @@
GotFocus="Chatbox_OnGotFocus"
AcceptsReturn="True"
KeyDown="Chatbox_OnKeyDownHandler"
KeyUp="Chatbox_OnKeyUpHandler"
TextChanged="Chatbox_OnTextChanged">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
@@ -417,62 +583,29 @@
</Style>
</TextBlock.Resources>
</TextBlock>
<Button Grid.Column="1"
Margin="2"
x:Name="MediaButton"
Background="Transparent"
Width="28"
Height="28"
BorderThickness="0"
Padding="2"
VerticalAlignment="Bottom"
ToolTip="Datei einfügen"
Click="MediaButton_OnClick" >
<Button Grid.Column="1" Margin="2" x:Name="MediaButton" Background="Transparent"
Width="28" Height="28" BorderThickness="0" Padding="2"
Visibility="{Binding Chat.IsInBroadcastMode, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}}"
VerticalAlignment="Bottom" ToolTip="Datei einfügen" Click="MediaButton_OnClick" >
<Image Width="22" Height="22" Source='pack://application:,,,/ChatController;component/Ressourcen/paperclip2.png' RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Center"/>
</Button>
<Button Grid.Column="2"
Width="28"
Height="28"
BorderThickness="0"
Background="Transparent"
x:Name="EmojiButton"
Margin="2"
Padding="0"
VerticalAlignment="Bottom"
ToolTip="Emoji einfügen"
Click="EmojiButton_OnClick">
<Button Grid.Column="1" Margin="2" Background="Transparent"
Width="28" Height="28" BorderThickness="0" Padding="2"
Visibility="{Binding Path=Chat.IsInBroadcastMode, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=reverse}"
VerticalAlignment="Bottom" ToolTip="Datei einfügen" Click="AddMediaFileToBroadcastMessage_OnClick">
<Image Width="22" Height="22" Source="pack://application:,,,/ChatController;component/Ressourcen/paperclip2.png" RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Center" />
</Button>
<Button Grid.Column="2" Width="28" Height="28" BorderThickness="0"
Background="Transparent" x:Name="EmojiButton" Margin="2" Padding="0"
VerticalAlignment="Bottom" ToolTip="Emoji einfügen" Click="EmojiButton_OnClick">
<Image Width="24" Height="24" Source='pack://application:,,,/ChatController;component/Ressourcen/glucklicher.png' RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Center" />
</Button>
<Button x:Name="SendButton" Height="25" Content="Senden" Margin="3" Grid.Column="3" VerticalAlignment="Bottom"
Click="SendButton_OnClick" IsEnabled="{Binding ElementName=Chatbox, Path=Text, Converter={StaticResource StringToBoolConverter}}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="#ff5e00" />
<Setter Property="Background" Value="#ff5e00" />
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border" Background="#ff5300" CornerRadius="5" Padding="5,2">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#ff9999" TargetName="Border" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#ff3a00" TargetName="Border" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="LightGray" TargetName="Border" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
<Button x:Name="SendButton" Height="25" Content="Senden" Margin="3" Grid.Column="3" VerticalAlignment="Bottom" Style="{StaticResource OrangeButtonStyle}"
Visibility="{Binding Chat.IsInBroadcastMode, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}}"
Click="SendButton_OnClick" IsEnabled="{Binding IsSendButtonEnabled, UpdateSourceTrigger=PropertyChanged}" />
<Button Height="25" Content="Senden" Margin="3" Grid.Column="3" VerticalAlignment="Bottom" Style="{StaticResource OrangeButtonStyle}"
Visibility="{Binding Path=Chat.IsInBroadcastMode, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=reverse}"
Click="SendBroatcastButton_OnClick" IsEnabled="{Binding IsBroadcastButtonEnabled, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Grid>
</Grid>

View File

@@ -8,6 +8,7 @@ using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
@@ -25,6 +26,7 @@ using ChatController.Utilities;
using ChatController.Utilities.Extensions;
using Application = System.Windows.Forms.Application;
using Button = System.Windows.Controls.Button;
using CheckBox = System.Windows.Controls.CheckBox;
using Cursors = System.Windows.Input.Cursors;
using DataFormats = System.Windows.DataFormats;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
@@ -112,11 +114,17 @@ namespace ChatController
}
}
public ObservableCollection<Contact> ContactList
// ToDo: Hier die ContactDepenencyObject-Klasse benutzen wie im Kalender des BeWoPlaners!
public ObservableSortCollection<ContactDependencyObject> ContactList
{
get
get => _ContactList ?? (_ContactList = new ObservableSortCollection<ContactDependencyObject>());
set
{
return _ContactList == null ? new ObservableCollection<Contact>() : new ObservableCollection<Contact>(_ContactList.OrderByDescending(contact => contact.TimeStamp));
_ContactList = new ObservableSortCollection<ContactDependencyObject>(value);
_ContactList.Sort((x, y) => DateTime.Compare(y.Contact.TimeStamp, x.Contact.TimeStamp));
OnPropertyChanged(nameof(ContactList));
}
}
@@ -124,16 +132,21 @@ namespace ChatController
{
get
{
if(_CurrentContact is null)
if(_CurrentContact is null && Chat?.IsInBroadcastMode == false)
{
return Visibility.Collapsed;
}
if(false == (Chat?.IsInBroadcastMode ?? false) && !(_CurrentContact is null))
{
return _CurrentContact.IsChatMessageInputGridVisible ? Visibility.Visible : Visibility.Collapsed;
}
return Chat?.IsInBroadcastMode ?? false ? Visibility.Visible : Visibility.Collapsed;
}
}
private List<Contact> _ContactList;
private ObservableSortCollection<ContactDependencyObject> _ContactList;
private bool _ScrollPrueferAktivieren;
@@ -155,14 +168,13 @@ namespace ChatController
_ChatMessages = new ObservableCollection<ChatMessage>();
ChatMessages = CollectionViewSource.GetDefaultView(_ChatMessages) as ListCollectionView;
if (!(ChatMessages is null))
{
ChatMessages.CustomSort = new ChatMessageComparer();
}
DataContext = this;
ReloadGruppen.Visibility = Visibility.Collapsed;
}
private void ContainingWindowOnDeactivated(object sender, EventArgs e)
@@ -202,20 +214,27 @@ namespace ChatController
OnPropertyChanged(nameof(Chat));
_ContactList = Chat.AddContacts();
_ContactList = new ObservableSortCollection<ContactDependencyObject>();
foreach(var contact in Chat.AddContacts())
{
ContactList.Add(new ContactDependencyObject(contact));
}
ContactList.Sort((x, y) => DateTime.Compare(y.Contact.TimeStamp, x.Contact.TimeStamp));
OnPropertyChanged(nameof(ContactList));
ReadNewSyncFile();
foreach (var contact in _ContactList)
foreach (var contactDependencyObject in _ContactList)
{
if (_GroupId2DateTime.ContainsKey(contact.GroupId))
if (_GroupId2DateTime.ContainsKey(contactDependencyObject.Contact.GroupId))
{
var isUnread = _GroupId2DateTime[contact.GroupId].IsUnread;
var isUnread = _GroupId2DateTime[contactDependencyObject.Contact.GroupId].IsUnread;
contact.IsNewMessage = isUnread;
contact.HasUnreadMessages = contact.IsNewMessage;
contactDependencyObject.Contact.IsNewMessage = isUnread;
contactDependencyObject.Contact.HasUnreadMessages = contactDependencyObject.Contact.IsNewMessage;
}
}
@@ -230,11 +249,11 @@ namespace ChatController
{
var notificationIcon = Resource.ownchat_favicon;
var contact = _ContactList.FirstOrDefault(a => a.GroupId == pGroupId);
var contact = _ContactList.FirstOrDefault(a => a.Contact.GroupId == pGroupId);
if (contact != null)
{
notificationIcon = Utils.ImageSourceToIcon(contact.Image);
notificationIcon = Utils.ImageSourceToIcon(contact.Contact.Image);
}
var notifyIcon = new NotifyIcon { Icon = notificationIcon, Visible = true, Tag = pMessage };
@@ -255,10 +274,10 @@ namespace ChatController
_ContainingWindow.Activate();
var selectedContact = _ContactList?.FirstOrDefault(f => f?.GroupId == pGroupId);
var selectedContact = _ContactList?.FirstOrDefault(f => f?.Contact.GroupId == pGroupId);
if(selectedContact != null)
{
SelectContact(selectedContact);
SelectContact(selectedContact.Contact);
}
};
@@ -314,9 +333,14 @@ namespace ChatController
private void Clientlist_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(Clientlist?.SelectedItem is Contact selectedContact)
if(Chat.IsInBroadcastMode)
{
SelectContact(selectedContact);
return;
}
if(Clientlist?.SelectedItem is ContactDependencyObject selectedContactDependencyObject)
{
SelectContact(selectedContactDependencyObject.Contact);
}
}
@@ -324,7 +348,7 @@ namespace ChatController
{
try
{
if (pContact == null)
if (pContact is null)
{
return;
}
@@ -346,7 +370,7 @@ namespace ChatController
var currentContact = pContact;
pContact.IsNewMessage = false;
var shouldChangeIcon = _ContactList.Any(contact => contact.IsNewMessage);
var shouldChangeIcon = _ContactList.Any(contact => contact.Contact.IsNewMessage);
if (shouldChangeIcon)
{
ContainingWindow.Icon = Utils.ConvertIconToImageSource(Resource.ownchat_favicon);
@@ -354,9 +378,12 @@ namespace ChatController
CurrentContact = currentContact;
if (Clientlist.Items.Contains(pContact))
foreach(ContactDependencyObject item in Clientlist.Items)
{
Clientlist.SelectedItem = pContact;
if(item.Contact.Equals(pContact))
{
Clientlist.SelectedItem = item;
}
}
_ChatMessages.Clear();
@@ -460,9 +487,9 @@ namespace ChatController
}
}
private void PasteOnClick(object sender, RoutedEventArgs routedEventArgs)
private async void PasteOnClick(object sender, RoutedEventArgs routedEventArgs)
{
Chat.Paste(CurrentContact.GroupId,this);
await Chat.Paste(CurrentContact.GroupId,this);
}
private void CopyOnClick(object sender, RoutedEventArgs routedEventArgs)
@@ -582,7 +609,7 @@ namespace ChatController
}
}
private void MediaButton_OnClick(object sender, RoutedEventArgs e)
private async void MediaButton_OnClick(object sender, RoutedEventArgs e)
{
if(CurrentContact != null)
{
@@ -600,7 +627,7 @@ namespace ChatController
return;
}
if (!string.IsNullOrWhiteSpace(pathToScaledImage))
if (File.Exists(pathToScaledImage))
{
_ChatMessages.AddRangeIfElementsNotIn(Chat.AddNewFile(pathToScaledImage, pathToOriginalImage, CurrentContact.GroupId, GetFirstMessage()));
@@ -610,7 +637,7 @@ namespace ChatController
ChatListBox.ScrollIntoView(currentChatMessage);
Chat.SendFileToContact(CurrentContact, pathToScaledImage,pathToOriginalImage);
await Chat.SendFileToContact(CurrentContact, pathToScaledImage, pathToOriginalImage, Chatbox.Text);
if (!string.IsNullOrWhiteSpace(pathToScaledImage) && !pathToScaledImage.Equals(pathToOriginalImage) && File.Exists(pathToScaledImage))
{
@@ -625,8 +652,14 @@ namespace ChatController
}
}
private void SendButton_OnClick(object sender, RoutedEventArgs e)
private async void SendButton_OnClick(object sender, RoutedEventArgs e)
{
if(Chat.IsInBroadcastMode)
{
SendBroadcastMessage();
return;
}
if(CurrentContact != null && !string.IsNullOrEmpty(Chatbox.Text))
{
var messages2Add = Chat.AddNewMessage(Chatbox.Text, CurrentContact.GroupId, GetFirstMessage());
@@ -639,12 +672,10 @@ namespace ChatController
WpfUtils.ScrollToBottomOfListBox(ChatListBox);
Chat.SendMessage(Chatbox.Text, CurrentContact.GroupId);
await Chat.SendMessage(Chatbox.Text, CurrentContact.GroupId);
Chatbox.Text = string.Empty;
Thread.Sleep(500);
DoSynchro();
}
}
@@ -678,6 +709,9 @@ namespace ChatController
// Chatbox.Text = string.Empty;
// }
//}
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
OnPropertyChanged(nameof(IsSendButtonEnabled));
}
catch (Exception ed)
{
@@ -685,6 +719,12 @@ namespace ChatController
}
}
private void Chatbox_OnKeyUpHandler(object sender, KeyEventArgs e)
{
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
OnPropertyChanged(nameof(IsSendButtonEnabled));
}
public delegate void EmojiiDelegate(Button button);
public event EmojiiDelegate OnEmojii;
@@ -726,7 +766,9 @@ namespace ChatController
var currentChatMessage = ChatMessages.CurrentItem;
var selectedContact = (Contact) Clientlist.SelectedItem;
if(!(Clientlist.SelectedItem is null))
{
var selectedContact = ((ContactDependencyObject) Clientlist.SelectedItem).Contact;
Chat.LoadMoreMessagesAsync(selectedContact, GetFirstMessage(), chatMessages =>
{
@@ -742,6 +784,7 @@ namespace ChatController
}
}
}
}
private void ListenForMessages()
{
@@ -782,19 +825,25 @@ namespace ChatController
{
foreach (var newContact in updatedContacts)
{
if (contact.GroupId == newContact.GroupId)
if (contact.Contact.GroupId == newContact.GroupId)
{
// ReceivedMessage kann null sein!
if (contact.ReceivedMessage != null && !contact.ReceivedMessage.Id.Equals(newContact.ReceivedMessage?.Id))
if (contact.Contact.ReceivedMessage != null && !contact.Contact.ReceivedMessage.Id.Equals(newContact.ReceivedMessage?.Id))
{
contact.ReceivedMessage = newContact.ReceivedMessage;
contact.TimeStamp = newContact.TimeStamp;
contact.Contact.ReceivedMessage = newContact.ReceivedMessage;
contact.Contact.TimeStamp = newContact.TimeStamp;
Contact selectedContact = null;
if(Clientlist.SelectedItem is ContactDependencyObject selectedContactDependencyObject)
{
selectedContact = selectedContactDependencyObject.Contact;
}
var selectedContact = (Contact)Clientlist.SelectedItem;
// Angemeldeter Benutzer
var userOid = Chat.ChatDaten.LoggedInUser.Response.User.Oid;
var senderId = contact.ReceivedMessage?.UserId;
var senderId = contact.Contact.ReceivedMessage?.UserId;
var receiverId = userOid;
var receiverGroupId = newContact.GroupId;
var selectedGroupId = selectedContact?.GroupId;
@@ -812,18 +861,18 @@ namespace ChatController
// Wenn der momentan ausgewählte Kontakt der aktuelle Kontakt in der Schleife ist, werden die Nachrichten nicht als ungelesen angezeigt, sonst schon.
if (CurrentContact != null && newContact.GroupId == CurrentContact.GroupId)
{
contact.HasUnreadMessages = false;
contact.Contact.HasUnreadMessages = false;
}
else
{
contact.HasUnreadMessages = true;
contact.IsNewMessage = true;
contact.Contact.HasUnreadMessages = true;
contact.Contact.IsNewMessage = true;
}
}
}
}
if (!updatedContacts.Contains(contact))
if (!updatedContacts.Contains(contact.Contact))
{
_ContactList.ToList().Remove(contact);
}
@@ -853,7 +902,7 @@ namespace ChatController
private void ListenForMessagesForCurrentContact(Contact pCurrentContact)
{
if (!ShouldInterruptContactsThread)
if (!ShouldInterruptContactsThread && !(CurrentContact is null))
{
Chat.CheckIfNewMessagesExistAsync(CurrentContact.GroupId, hasNewMessages =>
{
@@ -888,7 +937,12 @@ namespace ChatController
return true;
}
return (item as Contact).Name.IndexOf(Suche.Text, StringComparison.OrdinalIgnoreCase) >= 0;
if(item is ContactDependencyObject contactDependencyObject)
{
return contactDependencyObject.Contact.Name.IndexOf(Suche.Text, StringComparison.OrdinalIgnoreCase) >= 0;
}
return false;
}
private void Chat_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
@@ -1021,7 +1075,13 @@ namespace ChatController
{
this.Dispatch(() =>
{
_ContactList = Chat.UpdateContacts(data); // <- dauert eine Sekunde!
ContactList = new ObservableSortCollection<ContactDependencyObject>();
foreach(var contact in Chat.UpdateContacts(data))// <- dauert eine Sekunde!
{
ContactList.Add(new ContactDependencyObject(contact));
}
ContactList.Sort((x, y) => DateTime.Compare(y.Contact.TimeStamp, x.Contact.TimeStamp));
OnPropertyChanged(nameof(ContactList));
ReadNewSyncFile();
@@ -1054,9 +1114,9 @@ namespace ChatController
{
Encoding enc = new UTF8Encoding();
foreach (var contact in _ContactList.ToList().Where(contact => contact.ReceivedMessage != null))
foreach (var contact in _ContactList.ToList().Where(contact => contact.Contact.ReceivedMessage != null))
{
var text = contact.GroupId + ";" + contact.TimeStamp.ToUniversalTime() + ";" + contact.IsNewMessage + ";";
var text = contact.Contact.GroupId + ";" + contact.Contact.TimeStamp.ToUniversalTime() + ";" + contact.Contact.IsNewMessage + ";";
var bytes = enc.GetBytes(text);
var base64String = Convert.ToBase64String(bytes);
@@ -1066,7 +1126,7 @@ namespace ChatController
File.SetAttributes(Path.Combine(Utils.GetAndCreateUserAppDataPath(), Resource.SyncFile2Name), FileAttributes.ReadOnly);
}
}
catch (Exception exception)
catch (Exception)
{
}
@@ -1113,7 +1173,7 @@ namespace ChatController
Chat.LastTimeStamp = latestDateTime.GetUnixTimeStamp();
}
}
catch (Exception e)
catch(Exception)
{
}
@@ -1128,9 +1188,9 @@ namespace ChatController
foreach(var contactItem in Clientlist.Items)
{
if(contactItem is Contact contact && contact.HasUnreadMessages && !string.IsNullOrEmpty(contact.ReceivedMessage?.Text))
if(contactItem is ContactDependencyObject contactDependencyObject && contactDependencyObject.Contact.HasUnreadMessages && !string.IsNullOrEmpty(contactDependencyObject.Contact.ReceivedMessage?.Text))
{
contacts.Add(contact);
contacts.Add(contactDependencyObject.Contact);
}
}
@@ -1146,9 +1206,9 @@ namespace ChatController
{
foreach(var groupId2DateTime in pGroupId2DateTime)
{
if(contact.GroupId == groupId2DateTime.Key)
if(contact.Contact.GroupId == groupId2DateTime.Key)
{
contact.HasUnreadMessages = false;
contact.Contact.HasUnreadMessages = false;
}
}
}
@@ -1195,9 +1255,9 @@ namespace ChatController
File.Delete(file);
}
}
catch (Exception e)
catch (Exception)
{
//ignore
//ignore okeee
}
}
}
@@ -1227,6 +1287,9 @@ namespace ChatController
{
Chatbox.Height = 25;
}
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
OnPropertyChanged(nameof(IsSendButtonEnabled));
}
public void AddMessages(List<ChatMessage> newMessages)
@@ -1238,5 +1301,272 @@ namespace ChatController
{
return _ChatMessages.FirstOrDefault();
}
#region Broadcast
public bool IsSendButtonEnabled => !string.IsNullOrEmpty(Chatbox.Text);
public bool IsBroadcastButtonEnabled
{
get
{
var isInBroadcastMode = Chat.IsInBroadcastMode;
var hasSelectedContacts = GetSelectedContacts().Any();
var hasTextOrFile = !string.IsNullOrEmpty(Chatbox.Text) || !(BroadcastMessage?.BroadcastMessageImageSource is null);
return isInBroadcastMode && hasSelectedContacts && hasTextOrFile;
}
}
private Contact _PreviousContact;
private CancellationTokenSource _CancellationTokenSource;
private string _DefaultBroadcastInfoText = "Dies ist eine Nachricht, die als Broadcast an alle ausgewählten Kontakte geschickt wird.";
private string _BroadcastInfoText;
public string BroadcastInfoText
{
get => _BroadcastInfoText ?? (_BroadcastInfoText = _DefaultBroadcastInfoText);
set
{
_BroadcastInfoText = $"{_DefaultBroadcastInfoText}{Environment.NewLine}{value}";
OnPropertyChanged(BroadcastInfoText);
}
}
private double _BroadcastProgressValue;
public double BroadcastProgressValue
{
get => _BroadcastProgressValue;
set
{
_BroadcastProgressValue = value;
OnPropertyChanged(nameof(BroadcastProgressValue));
}
}
private BroadcastMessage _BroadcastMessage;
public BroadcastMessage BroadcastMessage
{
get => _BroadcastMessage;
set
{
_BroadcastMessage = value;
OnPropertyChanged(nameof(BroadcastMessage));
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
}
}
private void BroadcastButton_OnClick(object sender, RoutedEventArgs e)
{
Chat.IsInBroadcastMode = !Chat.IsInBroadcastMode;
BroadcastProgressValue = 0;
DeselectAllContacts();
if (Chat.IsInBroadcastMode)
{
_CancellationTokenSource = new CancellationTokenSource();
_PreviousContact = CurrentContact;
CurrentContact = null;
}
else
{
CloseBroadcastMode();
}
OnPropertyChanged(nameof(IsSendButtonEnabled));
OnPropertyChanged(nameof(ChatMessageInputGridVisibility));
OnPropertyChanged(nameof(BroadcastMessage));
}
private void AbortBroadcastButton_OnClick(object sender, RoutedEventArgs e)
{
CloseBroadcastMode();
}
private async void SendBroadcastMessage()
{
var selectedContacts = GetSelectedContacts();
if (selectedContacts.Count == 0 || string.IsNullOrEmpty(Chatbox.Text) && BroadcastMessage.BroadcastMessageImageSource is null)
{
return;
}
var progress = new Progress<BroadcastProgressReportModel>();
progress.ProgressChanged += ReportProgress;
try
{
await SendBroadcast(progress, _CancellationTokenSource.Token);
}
catch(OperationCanceledException)
{
BroadcastInfoText = "Der Broadcast wurde abgebrochen.";
}
DoSynchro();
CloseBroadcastMode();
}
private async Task SendBroadcast(IProgress<BroadcastProgressReportModel> progress, CancellationToken cancellationToken)
{
var count = 0;
var report = new BroadcastProgressReportModel();
var selectedContacts = GetSelectedContacts();
foreach (var contact in selectedContacts.Where(selectedContact => selectedContact.IsChatMessageInputGridVisible))
{
if(BroadcastMessage is null)
{
await Chat.SendMessage(Chatbox.Text, contact.GroupId);
}
else
{
await Chat.SendFileToContact(contact, BroadcastMessage.ScaledFilePath, BroadcastMessage.OriginalFilePath, Chatbox.Text);
}
cancellationToken.ThrowIfCancellationRequested();
count++;
report.PercentageComplete = count * 100 / selectedContacts.Count;
progress.Report(report);
}
}
private void ReportProgress(object sender, BroadcastProgressReportModel e)
{
BroadcastProgressValue = e.PercentageComplete;
}
private void SelectAllContacts_OnClick(object sender, RoutedEventArgs e)
{
if(sender is CheckBox checkBox)
{
var isChecked = checkBox.IsChecked ?? false;
foreach (var contactDependencyObject in ContactList)
{
contactDependencyObject.SetValue(ListItemHelper.IsCheckedProperty, isChecked);
}
OnPropertyChanged(nameof(ContactList));
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
}
}
private void SendBroatcastButton_OnClick(object sender, RoutedEventArgs e)
{
SendBroadcastMessage();
}
private void CancelBroadcastButton_OnClick(object sender, RoutedEventArgs e)
{
_CancellationTokenSource?.Cancel();
BroadcastMessage = null;
Chatbox.Text = string.Empty;
}
private void AddMediaFileToBroadcastMessage_OnClick(object sender, RoutedEventArgs e)
{
if(Chat.IsInBroadcastMode)
{
var originalFilePath = Chat.OpenFile();
if(File.Exists(originalFilePath))
{
var scaledImagePath = FileUtils.ScaleImage(originalFilePath, Path.GetExtension(originalFilePath.ToUpperInvariant()), Chat.ChatDaten.MaxUploadSize);
var isFileSizeTooLarge = FileUtils.CheckFileSize(scaledImagePath, Chat.ChatDaten.MaxUploadSize);
if(isFileSizeTooLarge)
{
MessageBox.Show($"Die ausgewählte Datei ist zu groß. Die maximale Größe beträgt {Chat.ChatDaten.MaxUploadSize / 1000 / 1000} MB", "Senden nicht möglich", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if(File.Exists(scaledImagePath))
{
if (BroadcastMessage is null)
{
BroadcastMessage = new BroadcastMessage(originalFilePath, scaledImagePath);
}
}
}
}
}
private void CloseBroadcastMode()
{
Chatbox.Text = string.Empty;
if(!(_PreviousContact is null))
{
SelectContact(_PreviousContact);
}
_CancellationTokenSource = null;
BroadcastMessage = null;
BroadcastProgressValue = 0;
DeselectAllContacts();
OnPropertyChanged(nameof(IsSendButtonEnabled));
OnPropertyChanged(nameof(ChatMessageInputGridVisibility));
OnPropertyChanged(nameof(BroadcastMessage));
Chat.IsInBroadcastMode = false;
}
#endregion
private void ContactCheckBox_OnClick(object sender, RoutedEventArgs e)
{
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
}
private void ContactCheckBox_OnChecked(object sender, RoutedEventArgs e)
{
UpdateContactSelection();
}
private void UpdateContactSelection()
{
OnPropertyChanged(nameof(ContactList));
OnPropertyChanged(nameof(IsBroadcastButtonEnabled));
SelectAllContactsCheckBox.IsChecked = GetSelectedContacts().Count == ContactList.Where(contactDependencyObject => contactDependencyObject.Contact.IsChatMessageInputGridVisible).ToList().Count;
}
private List<Contact> GetSelectedContacts()
{
var result = new List<Contact>();
foreach(var contactDependencyObject in ContactList.Where(contactDependencyObject => contactDependencyObject.Contact.IsChatMessageInputGridVisible))
{
if(contactDependencyObject.GetValue(ListItemHelper.IsCheckedProperty) is bool isChecked && isChecked)
{
result.AddIfNotIn(contactDependencyObject.Contact);
}
}
return result;
}
private void DeselectAllContacts()
{
foreach (var contactDependencyObject in ContactList)
{
contactDependencyObject.SetValue(ListItemHelper.IsCheckedProperty, false);
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace ChatController.Converter
{
public class BroadcastCheckBoxVisibilityMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if(values.Length == 2 && values[0] is bool isInBroadcastMode && values[1] is bool isChatMessageInputGridVisible)
{
if(isInBroadcastMode)
{
return isChatMessageInputGridVisible ? Visibility.Visible : Visibility.Hidden;
}
return Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -3,6 +3,7 @@ using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
@@ -10,8 +11,10 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Windows;
using System.Windows.Controls;
@@ -19,6 +22,7 @@ using System.Windows.Data;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ChatController.Annotations;
using ChatController.Core;
using ChatController.Extensions;
using ChatController.LoginKlassen;
@@ -35,7 +39,7 @@ using MessageBox = System.Windows.MessageBox;
namespace ChatController.HauptKlassen
{
// Ist quasi das ViewModel
public class Chat
public class Chat : INotifyPropertyChanged
{
public Action<Exception> ExceptionCallback { get; set; }
public Action<Exception> ThreadExceptionCallback { get; set; }
@@ -451,7 +455,7 @@ namespace ChatController.HauptKlassen
}
}
public async void SendMessage(string message, long groupId)
public async Task SendMessage(string message, long groupId)
{
try
{
@@ -466,14 +470,12 @@ namespace ChatController.HauptKlassen
var httpRequest = new HttpRequestMessage {Method = HttpMethod.Post, RequestUri = requestUri, Content = multiPartContent};
//wegen Kontent nachschauen
httpRequest.Headers.Add("Token", ChatDaten.AuthToken);
httpRequest.Headers.Add("CustomerID", ChatDaten.Kundennummer);
var httpClient = new HttpClient();
await httpClient.SendAsync(httpRequest, CancellationToken.None).ConfigureAwait(false);
}
}
catch (Exception exception)
{
@@ -501,13 +503,13 @@ namespace ChatController.HauptKlassen
}
}
public List<ChatMessage> AddNewFile(string pathToFile, string originalFilePath, long groupId, ChatMessage previousMessage)
public List<ChatMessage> AddNewFile(string pathToScaledFile, string originalFilePath, long groupId, ChatMessage previousMessage)
{
var result = new List<ChatMessage>();
try
{
if (string.IsNullOrEmpty(pathToFile) || string.IsNullOrEmpty(originalFilePath))
if(string.IsNullOrEmpty(pathToScaledFile) || string.IsNullOrEmpty(originalFilePath))
{
return result;
}
@@ -516,10 +518,10 @@ namespace ChatController.HauptKlassen
var sendTime = DateTime.Now;
if (Constants.ImageFileExtensions.Contains(Path.GetExtension(pathToFile).ToUpperInvariant()))
if (Constants.ImageFileExtensions.Contains(Path.GetExtension(pathToScaledFile).ToUpperInvariant()))
{
byte[] file;
using (Stream reader = File.OpenRead(pathToFile))
using (Stream reader = File.OpenRead(pathToScaledFile))
{
file = Utils.ReadFully(reader);
}
@@ -558,7 +560,8 @@ namespace ChatController.HauptKlassen
bitmapImage.EndInit();
bitmapImage.Freeze();
var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(pathToFile), sendTime, true, memoryStream.Length, null, pathToFile, Path.GetFileName(pathToFile), null, bitmapImage, ChatMessageType.Image, ChatDaten.LoggedInUser.Response.User.Oid);
var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(pathToScaledFile), sendTime, true, memoryStream.Length, null, pathToScaledFile, Path.GetFileName(pathToScaledFile), null, bitmapImage, ChatMessageType.Image, ChatDaten.LoggedInUser.Response.User.Oid);
result.Add(chatMessage);
}
}
@@ -568,7 +571,7 @@ namespace ChatController.HauptKlassen
{
var linkToThumbnail = $"{ChatDaten.ServerUrl}/document.png";
var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(pathToFile), sendTime, true, 0, pathToFile, null, null, linkToThumbnail, null, ChatMessageType.Document, ChatDaten.LoggedInUser.Response.User.Oid);
var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(pathToScaledFile), sendTime, true, 0, pathToScaledFile, null, null, linkToThumbnail, null, ChatMessageType.Document, ChatDaten.LoggedInUser.Response.User.Oid);
result.Add(chatMessage);
}
@@ -628,11 +631,11 @@ namespace ChatController.HauptKlassen
return AddSeparators(result);
}
public void SendFileToContact(Contact currentContact, string pFile, string pOriginalFilePath)
public async Task SendFileToContact(Contact currentContact, string scaledImagePath, string originalFilePath, string message)
{
try
{
SendFile(pFile, currentContact, pOriginalFilePath);
await SendFile(scaledImagePath, currentContact, originalFilePath, message);
}
catch (Exception exception)
{
@@ -641,7 +644,7 @@ namespace ChatController.HauptKlassen
}
// WebRequest
private void SendFile(string pFile, Contact currentContact, string pOriginalFilePath)
private async Task SendFile(string pFile, Contact currentContact, string pOriginalFilePath, string message)
{
if(string.IsNullOrEmpty(pOriginalFilePath))
{
@@ -660,18 +663,18 @@ namespace ChatController.HauptKlassen
{
fileName = fileName.Replace(".bmp", ".jpg");
SendMediaMessage(fileName, currentContact.GroupId, mediaFile);
await SendMediaMessage(fileName, currentContact.GroupId, mediaFile, message);
}
else
{
SendMediaMessage(fileName, currentContact.GroupId, mediaFile);
await SendMediaMessage(fileName, currentContact.GroupId, mediaFile, message);
}
}
private HttpRequestMessage _HttpRequest;
// WebRequest
private async void SendMediaMessage(string pMessage, long pGroupId, byte[] pMediaFile)
private async Task SendMediaMessage(string fileName, long groupId, byte[] mediaFile, string message)
{
try
{
@@ -679,8 +682,13 @@ namespace ChatController.HauptKlassen
{
var requestUri = new Uri(ChatDaten.ServerUrl + Constants.SendMessageUrl);
multiPartContent.Add(new ByteArrayContent(pMediaFile, 0, pMediaFile.Length), "file", pMessage);
multiPartContent.Add(new StringContent(pGroupId.ToString()), "groupid");
multiPartContent.Add(new ByteArrayContent(mediaFile, 0, mediaFile.Length), "file", fileName);
multiPartContent.Add(new StringContent(groupId.ToString()), "groupid");
if(!string.IsNullOrWhiteSpace(message))
{
multiPartContent.Add(new StringContent(message), "text");
}
_HttpRequest = new HttpRequestMessage
{
@@ -693,7 +701,7 @@ namespace ChatController.HauptKlassen
_HttpRequest.Headers.Add(Constants.CustomerId, ChatDaten.Kundennummer);
var httpClient = new HttpClient();
var httpResponse = await httpClient.SendAsync(_HttpRequest, CancellationToken.None).ConfigureAwait(false);
var httpResponse = await httpClient.SendAsync(_HttpRequest, CancellationToken.None);//.ConfigureAwait(false);
var antwortResponse = await httpResponse.Content.ReadAsStringAsync();
}
@@ -800,7 +808,7 @@ namespace ChatController.HauptKlassen
}
}
public void Paste(long pGroupOid, ChatMainControl pChatMainControl)
public async Task Paste(long pGroupOid, ChatMainControl pChatMainControl)
{
var dataObject = Clipboard.GetDataObject();
@@ -828,7 +836,7 @@ namespace ChatController.HauptKlassen
pChatMainControl.ChatListBox.Items.MoveCurrentToLast();
pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem);
SendMediaMessage(fileName, pGroupOid, mediaFile);
await SendMediaMessage(fileName, pGroupOid, mediaFile, null);
}
}
}
@@ -850,7 +858,7 @@ namespace ChatController.HauptKlassen
pChatMainControl.ChatListBox.Items.MoveCurrentToLast();
pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem);
SendMessage(text, pGroupOid);
await SendMessage(text, pGroupOid);
}
else if (dataObject.GetDataPresent(DataFormats.Bitmap))
{
@@ -867,7 +875,7 @@ namespace ChatController.HauptKlassen
pChatMainControl.ChatListBox.Items.MoveCurrentToLast();
pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem);
SendMediaMessage(imageName, pGroupOid, Utils.ImageToByteArray(image));
await SendMediaMessage(imageName, pGroupOid, Utils.ImageToByteArray(image), null);
}
else
{
@@ -1189,6 +1197,34 @@ namespace ChatController.HauptKlassen
ExceptionCallback?.Invoke(exception);
}
}
private bool _IsInBroadcastMode;
public bool IsInBroadcastMode
{
get => _IsInBroadcastMode;
set
{
_IsInBroadcastMode = value;
OnPropertyChanged(nameof(IsInBroadcastMode));
}
}
public void SendBroadcastMessage()
{
throw new NotImplementedException("SendBroadcastMessage implementieren!");
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ChatMessageComparer : IComparer

View File

@@ -53,21 +53,21 @@
<Button FontSize="15" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="5" VerticalContentAlignment="Center" Click="AnmeldenButton_OnClick" Content="Anmelden" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="3" Width="100" Height="40" Background="#ff5e00" HorizontalContentAlignment="Center" >
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="#ff5e00" />
<Setter Property="Background" Value="#ff5e00" />
<Setter Property="BorderBrush" Value="#FF5A00" />
<Setter Property="Background" Value="#FF5A00" />
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border" Background="#ff5300" CornerRadius="5" Padding="1">
<Border x:Name="Border" Background="#FF5A00" CornerRadius="5" Padding="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#ff9999" TargetName="Border" />
<Setter Property="Background" Value="#FF988F" TargetName="Border" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#ff3a00" TargetName="Border" />
<Setter Property="Background" Value="#FF7654" TargetName="Border" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

View File

@@ -0,0 +1,68 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ChatController.Annotations;
namespace ChatController.Utilities
{
public class BroadcastMessage : INotifyPropertyChanged
{
private string _OriginalFilePath;
public string OriginalFilePath
{
get => _OriginalFilePath;
set
{
_OriginalFilePath = value;
OnPropertyChanged(nameof(OriginalFilePath));
}
}
private string _ScaledFilePath;
public string ScaledFilePath
{
get => _ScaledFilePath;
set
{
_ScaledFilePath = value;
OnPropertyChanged(nameof(ScaledFilePath));
}
}
private ImageSource _BroadcastMessageImageSource;
public ImageSource BroadcastMessageImageSource
{
get => _BroadcastMessageImageSource;
set
{
_BroadcastMessageImageSource = value;
OnPropertyChanged(nameof(BroadcastMessageImageSource));
}
}
public BroadcastMessage(string originalFilePath, string scaledFilePath)
{
OriginalFilePath = originalFilePath;
ScaledFilePath = scaledFilePath;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(scaledFilePath);
bitmap.EndInit();
BroadcastMessageImageSource = bitmap;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,7 @@
namespace ChatController.Utilities
{
public class BroadcastProgressReportModel
{
public int PercentageComplete { get; set; } = 0;
}
}

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
namespace ChatController.Utilities.Extensions
{
public class ObservableSortCollection<T> : ObservableCollection<T>
{
private readonly List<NotifyCollectionChangedEventHandler> _ChangedHandler = new List<NotifyCollectionChangedEventHandler>();
private readonly Comparison<T> _Comparer;
public ObservableSortCollection()
{
}
public ObservableSortCollection(IEnumerable<T> pList) : base(pList.ToList())
{
}
public ObservableSortCollection(Comparison<T> pComparer) : this()
{
_Comparer = pComparer;
Sort();
}
public ObservableSortCollection(IEnumerable<T> pList, Comparison<T> pComparer) : this(pList)
{
_Comparer = pComparer;
Sort();
}
public override event NotifyCollectionChangedEventHandler CollectionChanged
{
add
{
_ChangedHandler.Add(value);
base.CollectionChanged += value;
}
remove
{
_ChangedHandler.Remove(value);
base.CollectionChanged -= value;
}
}
public void Sort()
{
if (_Comparer != null)
{
DisconnectHandler();
var lTemp = this.ToList();
lTemp.Sort(_Comparer);
for (var i = 0; i < Count; i++)
{
this[i] = lTemp[i];
}
ReconnectHandler();
NotifyHandlerAfterSort();
}
}
public void Sort(Comparison<T> pComparer)
{
DisconnectHandler();
var lTemp = this.ToList();
lTemp.Sort(pComparer);
for (var i = 0; i < Count; i++)
{
this[i] = lTemp[i];
}
ReconnectHandler();
NotifyHandlerAfterSort();
}
private void DisconnectHandler()
{
foreach (var iHandler in _ChangedHandler)
{
base.CollectionChanged -= iHandler;
}
}
private void NotifyHandlerAfterSort()
{
foreach (var iHandler in _ChangedHandler)
{
iHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
private void ReconnectHandler()
{
foreach (var iHandler in _ChangedHandler)
{
base.CollectionChanged += iHandler;
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Windows;
namespace ChatController.Utilities
{
public class ListItemHelper : DependencyObject
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(ListItemHelper), new PropertyMetadata(false, null));
public static void SetIsChecked(DependencyObject element, bool? IsChecked)
{
element.SetValue(IsCheckedProperty, IsChecked);
}
public static bool? GetIsChecked(DependencyObject element)
{
return (bool?)element.GetValue(IsCheckedProperty);
}
}
}

View File

@@ -14,11 +14,14 @@ using System.Windows;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using ChatController.Core;
using RestSharp;
using MessageBox = System.Windows.MessageBox;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using Point = System.Drawing.Point;
using Size = System.Drawing.Size;
namespace ChatController.Utilities
{

View File

@@ -5,6 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:cc="clr-namespace:ChatController;assembly=ChatController"
mc:Ignorable="d" WindowStartupLocation="CenterScreen" Icon="pack://application:,,,/ChatController;component/Ressourcen/ownchat_icon.png"
SizeChanged="MainWindow_OnSizeChanged" MinHeight="610"
Title="ownChat Desktop" Height="700" Width="900" x:Name="MainView" Closed="MainWindow_OnClosed">
<Grid>
<cc:ChatMainControl x:Name="ChatMainControl" OnEmojii="ChatMainControl_OnOnEmojii"></cc:ChatMainControl>

View File

@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
@@ -49,5 +50,10 @@ namespace ownChat
Environment.Exit(0);
}
private void MainWindow_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
Debug.WriteLine($"+++>ActualHeight: {ActualHeight}");
}
}
}