Kontaktliste wird bei neuer Nachricht aktualisiert
Text ist markierbar
This commit is contained in:
@@ -71,7 +71,9 @@
|
||||
<Compile Include="Converter\StringToBoolConverter.cs" />
|
||||
<Compile Include="Converter\UserProfilePictureVisibilityConverter.cs" />
|
||||
<Compile Include="Core\BindableTextBlock.cs" />
|
||||
<Compile Include="Core\FlowDocumentExtensions.cs" />
|
||||
<Compile Include="Core\OwnChatCache.cs" />
|
||||
<Compile Include="Core\OwnChatRichTextBox.cs" />
|
||||
<Compile Include="Data\LookupResult.cs" />
|
||||
<Compile Include="Data\OwnChatApi.cs" />
|
||||
<Compile Include="Extensions\IDictionaryTExtensions.cs" />
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace ChatController.ChatKlassen
|
||||
|
||||
public int TimeStringMaxWidth => IsSeparator ? int.MaxValue : 350;
|
||||
|
||||
public int MessageMaxWidth => IsSeparator ? int.MaxValue : 500;
|
||||
public int MessageMaxWidth => IsSeparator ? int.MaxValue : 450;
|
||||
|
||||
public string SeparatorTimeString => SendTime.ToString("dd. MMMM yyyy");
|
||||
|
||||
|
||||
@@ -94,9 +94,11 @@ namespace ChatController.ChatKlassen
|
||||
|
||||
IsChatMessageInputGridVisible = isChatMessageInputGridVisible;
|
||||
|
||||
if(accentColorBrushString == null)
|
||||
Utils.DownloadUserProfilePicturesAsync(userId2Uri);
|
||||
|
||||
if (accentColorBrushString is null)
|
||||
{
|
||||
if(pUserIdManage != null)
|
||||
if(!(pUserIdManage is null))
|
||||
{
|
||||
accentColorBrushString = "3B7799";
|
||||
}
|
||||
@@ -114,7 +116,7 @@ namespace ChatController.ChatKlassen
|
||||
|
||||
IsGroupChat = pUserCount > 2;
|
||||
|
||||
Utils.DownloadProfilePictureAsync(profilePicturePath, key, delegate(ImageSource imageSource)
|
||||
Utils.DownloadGroupProfilePictureAsync(profilePicturePath, key, delegate(ImageSource imageSource)
|
||||
{
|
||||
Image = imageSource;
|
||||
});
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<Setter Property="Template" Value="{StaticResource ContactListBoxTemplate}" />
|
||||
</Style>
|
||||
|
||||
<!-- Kontaktliste -->
|
||||
<!-- region Styling Kontaktliste -->
|
||||
<Style x:Key="ContactListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
|
||||
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
|
||||
@@ -126,8 +126,9 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<!-- endregion Styling Kontaktliste -->
|
||||
|
||||
<!-- Gruppensuchtemplate -->
|
||||
<!-- region Styling Gruppensuchtemplate -->
|
||||
<ControlTemplate x:Key="SearchTextBoxTemplate" TargetType="{x:Type TextBox}">
|
||||
<Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="2,2,2,2">
|
||||
<Grid>
|
||||
@@ -149,7 +150,7 @@
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
<!-- /Gruppensuchtemplate -->
|
||||
<!-- endregion Styling Gruppensuchtemplate -->
|
||||
|
||||
<Style TargetType="{x:Type Rectangle}">
|
||||
<Setter Property="Fill" Value="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
|
||||
@@ -177,7 +178,7 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Gruppensuche und Gruppenliste aktualisieren -->
|
||||
<!-- region Gruppensuche und Gruppenliste aktualisieren -->
|
||||
<Grid Grid.Column="0" Grid.Row="0" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
@@ -195,9 +196,9 @@
|
||||
|
||||
<TextBox Grid.Column="0" x:Name="Suche" Height="22" HorizontalAlignment="Stretch" Margin="5" TabIndex="0" Template="{DynamicResource SearchTextBoxTemplate}" BorderThickness="0,0,0,0" TextChanged="Suche_OnTextChanged" />
|
||||
</Grid>
|
||||
<!-- /Gruppensuche und Gruppenliste aktualisieren -->
|
||||
<!-- endregion Gruppensuche und Gruppenliste aktualisieren -->
|
||||
|
||||
<!-- Kontaktliste -->
|
||||
<!-- region Kontaktliste -->
|
||||
<Grid Grid.Column="0" Grid.Row="1" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
@@ -210,7 +211,7 @@
|
||||
ItemContainerStyle="{StaticResource ContactListBoxItemStyle}" SelectionChanged="Clientlist_OnSelectionChanged" Style="{StaticResource ContactListStyle}">
|
||||
</ListView>
|
||||
</Grid>
|
||||
<!-- /Kontaktliste -->
|
||||
<!-- endregion Kontaktliste -->
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1" Grid.Row="0" x:Name="GridRechts">
|
||||
@@ -335,7 +336,10 @@
|
||||
<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" />
|
||||
<core:BindableTextBlock VerticalAlignment="Center" InlineList="{Binding MessageInlines, UpdateSourceTrigger=PropertyChanged}" MinWidth="0" MaxWidth="{Binding MessageMaxWidth}" TextWrapping="Wrap" FontSize="14" />
|
||||
<core:OwnChatRichTextBox VerticalAlignment="Center" InlineList="{Binding MessageInlines, UpdateSourceTrigger=PropertyChanged}"
|
||||
MinWidth="0" MaxWidth="{Binding MessageMaxWidth}" FontSize="14" IsReadOnly="True"
|
||||
HorizontalAlignment="{Binding HorizontalAlignmentValue}"
|
||||
BorderThickness="0" Background="Transparent" IsDocumentEnabled="True" Margin="-5,0,0,0" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Left" Margin="0,0,0,0">
|
||||
<TextBlock Text="{Binding UserTimeStringLeft}" MaxWidth="{Binding TimeStringMaxWidth}" FontSize="11" HorizontalAlignment="Left" TextAlignment="Left" VerticalAlignment="Center" Foreground="{Binding Foreground}" />
|
||||
|
||||
@@ -14,7 +14,6 @@ using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Threading;
|
||||
using ChatController.Annotations;
|
||||
using ChatController.ChatKlassen;
|
||||
@@ -124,7 +123,7 @@ namespace ChatController
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_CurrentContact == null)
|
||||
if(_CurrentContact is null)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
@@ -155,7 +154,7 @@ namespace ChatController
|
||||
|
||||
_ChatMessages = new ObservableCollection<ChatMessage>();
|
||||
ChatMessages = CollectionViewSource.GetDefaultView(_ChatMessages) as ListCollectionView;
|
||||
if (ChatMessages != null)
|
||||
if (!(ChatMessages is null))
|
||||
{
|
||||
ChatMessages.CustomSort = new ChatMessageComparer();
|
||||
}
|
||||
@@ -191,7 +190,7 @@ namespace ChatController
|
||||
exception => {
|
||||
this.Dispatch(
|
||||
() => {
|
||||
if(exception == null)
|
||||
if(exception is null)
|
||||
{
|
||||
ThreadExceptionMessage = null;
|
||||
}
|
||||
@@ -340,6 +339,7 @@ namespace ChatController
|
||||
pContact.HasUnreadMessages = false;
|
||||
|
||||
Clientlist.Items.Refresh();
|
||||
OnPropertyChanged(nameof(ContactList));
|
||||
}
|
||||
|
||||
var currentContact = pContact;
|
||||
@@ -359,12 +359,15 @@ namespace ChatController
|
||||
}
|
||||
|
||||
_ChatMessages.Clear();
|
||||
OnPropertyChanged(nameof(_ChatMessages));
|
||||
|
||||
Chat.LoadChatMessagesForContactAsync(currentContact, GetFirstMessage(), chatMessages =>
|
||||
{
|
||||
this.Dispatch(() =>
|
||||
{
|
||||
_ChatMessages.Clear();
|
||||
_ChatMessages.AddRangeIfElementsNotIn(chatMessages);
|
||||
OnPropertyChanged(nameof(_ChatMessages));
|
||||
|
||||
WpfUtils.ScrollToBottomOfListBox(ChatListBox);
|
||||
|
||||
@@ -821,7 +824,9 @@ namespace ChatController
|
||||
}
|
||||
}
|
||||
|
||||
Clientlist.Items.Refresh();
|
||||
//Clientlist.Items.Refresh();
|
||||
OnPropertyChanged(nameof(ChatMessages));
|
||||
OnPropertyChanged(nameof(ContactList));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
79
ChatController/Core/FlowDocumentExtensions.cs
Normal file
79
ChatController/Core/FlowDocumentExtensions.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace ChatController.Core
|
||||
{
|
||||
public static class FlowDocumentExtensions
|
||||
{
|
||||
private static IEnumerable<TextElement> GetRunsAndParagraphs(FlowDocument doc)
|
||||
{
|
||||
for (var position = doc.ContentStart; !(position is null) && position.CompareTo(doc.ContentEnd) <= 0; position = position.GetNextContextPosition(LogicalDirection.Forward))
|
||||
{
|
||||
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)
|
||||
{
|
||||
switch (position.Parent)
|
||||
{
|
||||
case Run run:
|
||||
yield return run;
|
||||
break;
|
||||
case Paragraph paragraph:
|
||||
yield return paragraph;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FormattedText GetFormattedText(this FlowDocument flowDocument)
|
||||
{
|
||||
if (flowDocument is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(flowDocument));
|
||||
}
|
||||
|
||||
var output = new FormattedText(GetText(flowDocument), CultureInfo.CurrentCulture, flowDocument.FlowDirection, new Typeface(flowDocument.FontFamily, flowDocument.FontStyle, flowDocument.FontWeight, flowDocument.FontStretch), flowDocument.FontSize, flowDocument.Foreground);
|
||||
|
||||
var offset = 0;
|
||||
|
||||
foreach (var textElement in GetRunsAndParagraphs(flowDocument))
|
||||
{
|
||||
if (textElement is Run run)
|
||||
{
|
||||
var count = run.Text.Length;
|
||||
|
||||
output.SetFontFamily(run.FontFamily, offset, count);
|
||||
output.SetFontStyle(run.FontStyle, offset, count);
|
||||
output.SetFontWeight(run.FontWeight, offset, count);
|
||||
output.SetFontSize(run.FontSize, offset, count);
|
||||
output.SetForegroundBrush(run.Foreground, offset, count);
|
||||
output.SetFontStretch(run.FontStretch, offset, count);
|
||||
output.SetTextDecorations(run.TextDecorations, offset, count);
|
||||
|
||||
offset += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += Environment.NewLine.Length;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static string GetText(FlowDocument flowDocument)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
foreach (var textElement in GetRunsAndParagraphs(flowDocument))
|
||||
{
|
||||
stringBuilder.Append(!(textElement is Run run) ? Environment.NewLine : run.Text);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,14 @@ namespace ChatController.Core
|
||||
return _UserProfilePictures.ContainsKey(userId) ? _UserProfilePictures[userId] : null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsUserProfilePictureInCache(long userId)
|
||||
{
|
||||
lock(_Lock)
|
||||
{
|
||||
return _UserProfilePictures.ContainsKey(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ProfilePictureObject
|
||||
|
||||
50
ChatController/Core/OwnChatRichTextBox.cs
Normal file
50
ChatController/Core/OwnChatRichTextBox.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace ChatController.Core
|
||||
{
|
||||
public class OwnChatRichTextBox : RichTextBox
|
||||
{
|
||||
public ObservableCollection<Inline> InlineList
|
||||
{
|
||||
get => (ObservableCollection<Inline>)GetValue(InlineListProperty);
|
||||
set => SetValue(InlineListProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty InlineListProperty = DependencyProperty.Register("InlineList", typeof(ObservableCollection<Inline>), typeof(OwnChatRichTextBox), new UIPropertyMetadata(null, OnPropertyChanged));
|
||||
|
||||
public static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
((OwnChatRichTextBox)sender).Document = GetCustomDocument(e.NewValue as ObservableCollection<Inline>);
|
||||
|
||||
if(sender is OwnChatRichTextBox ownChatRichTextBox)
|
||||
{
|
||||
ownChatRichTextBox.Document = GetCustomDocument(e.NewValue as ObservableCollection<Inline>);
|
||||
ownChatRichTextBox.Width = ownChatRichTextBox.Document.GetFormattedText().WidthIncludingTrailingWhitespace + 20;
|
||||
}
|
||||
}
|
||||
|
||||
private static FlowDocument GetCustomDocument(IEnumerable<Inline> inlines)
|
||||
{
|
||||
var flowDocument = new FlowDocument();
|
||||
var paragraph = new Paragraph
|
||||
{
|
||||
Margin = new Thickness(0) // remove indent between paragraphs
|
||||
};
|
||||
|
||||
paragraph.Inlines.AddRange(inlines);
|
||||
|
||||
flowDocument.Blocks.Add(paragraph);
|
||||
|
||||
return flowDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ namespace ChatController.HauptKlassen
|
||||
// Führt zu doppelter neuester Nachricht, wenn man vorher eine verschickt hat!
|
||||
public void LoadChatMessagesForContactAsync(Contact contact, ChatMessage previousMessage, Action<List<ChatMessage>> callback)
|
||||
{
|
||||
if(contact != null)
|
||||
if(!(contact is null))
|
||||
{
|
||||
LoadMessagesFromServerAsync(contact.GroupId, delegate
|
||||
{
|
||||
@@ -146,7 +146,7 @@ namespace ChatController.HauptKlassen
|
||||
{
|
||||
_UserMessages = JsonConvert.DeserializeObject<UserMessages>(response.Content);
|
||||
|
||||
if (_UserMessages.Response.HasMorePages)
|
||||
if (_UserMessages?.Response?.HasMorePages ?? false)
|
||||
{
|
||||
_NextPage = _UserMessages.Response.NextPage;
|
||||
_HasNextPage = true;
|
||||
@@ -177,7 +177,7 @@ namespace ChatController.HauptKlassen
|
||||
{
|
||||
try
|
||||
{
|
||||
if(page == null || !page.Contains("="))
|
||||
if(page is null || !page.Contains("="))
|
||||
{
|
||||
callback?.Invoke();
|
||||
return;
|
||||
@@ -195,18 +195,15 @@ namespace ChatController.HauptKlassen
|
||||
|
||||
client.ExecuteAsync(request, response =>
|
||||
{
|
||||
// TODO: Entfernen
|
||||
Debug.WriteLine(response.Content);
|
||||
|
||||
_AdditionalUserMessages = null;
|
||||
_AdditionalUserMessages = JsonConvert.DeserializeObject<UserMessages>(response.Content);
|
||||
|
||||
if (_AdditionalUserMessages.Response.HasMorePages)
|
||||
if (_AdditionalUserMessages?.Response?.HasMorePages ?? false)
|
||||
{
|
||||
_NextPage = _AdditionalUserMessages.Response.NextPage;
|
||||
}
|
||||
|
||||
_HasNextPage = _AdditionalUserMessages.Response.HasMorePages;
|
||||
_HasNextPage = _AdditionalUserMessages?.Response?.HasMorePages ?? false;
|
||||
|
||||
callback?.Invoke();
|
||||
});
|
||||
@@ -1076,8 +1073,6 @@ namespace ChatController.HauptKlassen
|
||||
|
||||
var key = $"group-{groupInput.Oid}";
|
||||
|
||||
|
||||
|
||||
contacts.Add(new Contact(
|
||||
groupInput.Name,
|
||||
groupInput.LastMessage,
|
||||
|
||||
@@ -90,18 +90,6 @@ namespace ChatController
|
||||
DataContext = this;
|
||||
|
||||
LeseDateiFallsVorhanden();
|
||||
|
||||
#if DEBUG
|
||||
//_Kundennummer = "4368658436";
|
||||
//_ChatCode = "ZMCKb-BckTt";
|
||||
//_Benutzername = "muellerp";
|
||||
//Password = "F5aTk9Co47JFJCWB2Z7Y";
|
||||
|
||||
//_Kundennummer = "9988776655";
|
||||
//_ChatCode = "K2UPV-qrirb";
|
||||
//_Benutzername = "lyndon";
|
||||
//Password = "lyndon2travemünde";
|
||||
#endif
|
||||
}
|
||||
|
||||
private void AnmeldenButton_OnClick(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -30,13 +30,13 @@ namespace ChatController.Utilities
|
||||
|
||||
public static DateTime DefaultDate = new DateTime(1, 1, 1);
|
||||
|
||||
public static void DownloadProfilePictureAsync(string pathToProfilePicture, string key, Action<ImageSource> callback)
|
||||
public static void DownloadGroupProfilePictureAsync(string pathToProfilePicture, string key, Action<ImageSource> callback)
|
||||
{
|
||||
var cache = OwnChatCache.GetInstance();
|
||||
|
||||
var cachedProfileImage = cache.GetCachedProfilePicture(key, pathToProfilePicture);
|
||||
|
||||
if (cachedProfileImage != null)
|
||||
if (!(cachedProfileImage is null))
|
||||
{
|
||||
callback?.Invoke(cachedProfileImage);
|
||||
return;
|
||||
@@ -49,6 +49,24 @@ namespace ChatController.Utilities
|
||||
});
|
||||
}
|
||||
|
||||
public static void DownloadUserProfilePicturesAsync(Dictionary<long, string> userIds2Uris)
|
||||
{
|
||||
var cache = OwnChatCache.GetInstance();
|
||||
|
||||
foreach(var userId2Uri in userIds2Uris)
|
||||
{
|
||||
if(cache.IsUserProfilePictureInCache(userId2Uri.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DownloadImage(userId2Uri.Value, imageSource =>
|
||||
{
|
||||
cache.AddUserProfilePictureToCache(imageSource, userId2Uri.Key, userId2Uri.Value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void DownloadImage(string uri, Action<ImageSource> callback)
|
||||
{
|
||||
var client = new RestClient(uri);
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user