Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #608 from UWPCommunity/rewrite/main
Browse files Browse the repository at this point in the history
Alpha Release
  • Loading branch information
Avid29 authored May 11, 2022
2 parents b970277 + 38ead3f commit dfc577d
Show file tree
Hide file tree
Showing 19 changed files with 173 additions and 55 deletions.
3 changes: 3 additions & 0 deletions src/API/Discord.API/Rest/IChannelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ internal interface IChannelService
[Get("/v9/channels/{channelId}/messages?limit={limit}")]
Task<JsonMessage[]> GetChannelMessages([AliasAs("channelId")] ulong channelId, [AliasAs("limit")] int limit = 50);

[Get("/v9/channels/{channelId}/messages?limit={limit}&before={before}")]
Task<JsonMessage[]> GetChannelMessagesBefore([AliasAs("channelId")] ulong channelId, [AliasAs("before")] ulong before, [AliasAs("limit")] int limit = 50);

[Post("/v9/channels/{channelId}/messages")]
Task<JsonMessage> CreateMessage([AliasAs("channelId")] ulong channelId, [Body] JsonMessageUpsert message);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Quarrel © 2022

using Quarrel.Markdown.Parsing;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;

namespace Quarrel.Markdown
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Quarrel © 2022

using Quarrel.Markdown.Parsing;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ internal UserMentionElement(UserMention mention, BindableMessage? context) : bas

}

public BindableUser User
public BindableUser? User
{
get => (BindableUser)GetValue(UserProperty);
get => (BindableUser?)GetValue(UserProperty);
set => SetValue(UserProperty, value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,6 @@ public Style? UserMentionStyle
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var messageRenderer = (MessageRenderer)d;

if (messageRenderer.Context is null)
{
// TODO: Allow context free rendering
return;
}

var tree = Parser.ParseAST(messageRenderer.Text, true, false);
var modTree = AdjustTree(tree);
messageRenderer.RenderMarkdown(modTree);
Expand Down
1 change: 0 additions & 1 deletion src/Libs/Quarrel.Markdown/Rendering/MessageRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ private void UpdateOverlays()

private void RenderMarkdown(IList<ASTRoot> tree)
{

if (_richBlock != null)
{
_richBlock.SizeChanged -= RichBlock_SizeChanged;
Expand Down
12 changes: 10 additions & 2 deletions src/Quarrel.Client/QuarrelClient.Methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,19 @@ public partial class QuarrelClient
/// Gets messages in a channel.
/// </summary>
/// <param name="channelId">The channel's id.</param>
public async Task<Message[]> GetMessagesAsync(ulong channelId, ulong? guildId = null)
/// <param name="guildId">The id of the guild the channel belongs to.</param>
/// <param name="beforeId">The message to get the messages from before.</param>
public async Task<Message[]> GetMessagesAsync(ulong channelId, ulong? guildId = null, ulong? beforeId = null)
{
Guard.IsNotNull(_channelService, nameof(_channelService));

JsonMessage[]? jsonMessages = await MakeRefitRequest(() => _channelService.GetChannelMessages(channelId));
Func<Task<JsonMessage[]>> request = () => _channelService.GetChannelMessages(channelId);
if (beforeId.HasValue)
{
request = () => _channelService.GetChannelMessagesBefore(channelId, beforeId.Value);
}

JsonMessage[]? jsonMessages = await MakeRefitRequest(request);
Guard.IsNotNull(jsonMessages, nameof(jsonMessages));

Message[] messages = new Message[jsonMessages.Length];
Expand Down
5 changes: 2 additions & 3 deletions src/Quarrel.ViewModels/Bindables/Messages/BindableMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Quarrel.Bindables.Messages.Embeds;
using Quarrel.Bindables.Users;
using Quarrel.Client.Models.Messages;
using Quarrel.Client.Models.Messages.Embeds;
using Quarrel.Messages.Discord.Messages;
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
Expand Down Expand Up @@ -66,7 +65,7 @@ internal BindableMessage(
{
if (Id == e.Message.Id)
{
Message = e.Message;
_dispatcherService.RunOnUIThread(() => Message = e.Message);
}
});

Expand All @@ -88,7 +87,7 @@ public Message Message
set
{
SetProperty(ref _message, value);
_dispatcherService.RunOnUIThread(AckUpdate);
AckUpdate();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ public void InsertRange(int index, IEnumerable<T> collection, NotifyCollectionCh
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
if (changedItems.Count > 0)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, changedItems, index));
for (int i = changedItems.Count-1; i >= 0; i--)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<T>{ changedItems[i] }, index));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ public BindableGuildFolder[] GetMyGuildFolders()
}

/// <inheritdoc/>
public async Task<Message[]> GetChannelMessagesAsync(IBindableMessageChannel channel)
public async Task<Message[]> GetChannelMessagesAsync(IBindableMessageChannel channel, ulong? beforeId = null)
{
var rawMessages = await _quarrelClient.GetMessagesAsync(channel.Id, channel.GuildId);
var rawMessages = await _quarrelClient.GetMessagesAsync(channel.Id, channel.GuildId, beforeId);
Guard.IsNotNull(rawMessages, nameof(rawMessages));
return rawMessages;
}
Expand Down
5 changes: 3 additions & 2 deletions src/Quarrel.ViewModels/Services/Discord/IDiscordService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ public interface IDiscordService
/// </remarks>
/// <returns>The array of <see cref="BindableGuildFolder"/>s that the current user has.</returns>
BindableGuildFolder[] GetMyGuildFolders();

/// <summary>
/// Gets the messages in a channel.
/// </summary>
/// <param name="channel">The channel to get the messages for.</param>
/// <param name="beforeId">The if of the last message to load messages before, or null.</param>
/// <returns>An array of <see cref="BindableMessage"/>s from the channel.</returns>
Task<Message[]> GetChannelMessagesAsync(IBindableMessageChannel channel);
Task<Message[]> GetChannelMessagesAsync(IBindableMessageChannel channel, ulong? beforeId = null);

/// <summary>
/// Gets the channels in a guild.
Expand Down
99 changes: 73 additions & 26 deletions src/Quarrel.ViewModels/ViewModels/Panels/MessagesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Quarrel.Services.Discord;
using Quarrel.Services.Dispatcher;
using System.Collections.ObjectModel;
using System.Threading;

namespace Quarrel.ViewModels.Panels
{
Expand All @@ -24,6 +25,7 @@ public partial class MessagesViewModel : ObservableRecipient
private readonly IDispatcherService _dispatcherService;

private bool _isLoading;
private SemaphoreSlim _semaphore;
private IBindableSelectableChannel? _selectedChannel;

/// <summary>
Expand All @@ -34,17 +36,16 @@ public MessagesViewModel(IMessenger messenger, IDiscordService discordService, I
_messenger = messenger;
_discordService = discordService;
_dispatcherService = dispatcherService;
_semaphore = new SemaphoreSlim(1,1);

Source = new ObservableRangeCollection<BindableMessage>();
IsLoading = false;

_messenger.Register<NavigateToChannelMessage<IBindableSelectableChannel>>(this, (_, m) => SelectedChannel = m.Channel);
_messenger.Register<MessageCreatedMessage>(this, (_, m) =>
{
if (SelectedChannel?.Id == m.Message.ChannelId)
{
AppendMessage(m.Message);
}
if (SelectedChannel?.Id != m.Message.ChannelId) return;
_dispatcherService.RunOnUIThread(() => AppendMessage(m.Message));
});
}

Expand All @@ -60,7 +61,7 @@ public IBindableSelectableChannel? SelectedChannel
{
if (SetProperty(ref _selectedChannel, value))
{
LoadChannel(value);
LoadChannel();
}
}
}
Expand All @@ -74,47 +75,93 @@ public bool IsLoading
private set => SetProperty(ref _isLoading, value);
}

private void LoadChannel(IBindableSelectableChannel? channel)
/// <remarks>
/// Must be called on the UI thread.
/// </remarks>
public async void LoadOlderMessages()
{
if (channel is IBindableMessageChannel messageChannel)
if (Source.Count == 0) return;
if (IsLoading) return;
await _semaphore.WaitAsync();
IsLoading = true;
try
{
ulong beforeId = Source[0].Message.Id;
IBindableMessageChannel? channel = SelectedChannel as IBindableMessageChannel;
Guard.IsNotNull(channel, nameof(channel));

// Load messages
var messages = await _discordService.GetChannelMessagesAsync(channel, beforeId);
if (messages.Length > 0)
{
var bindableMessages = ParseMessages(messages);

// Add messages to the UI and mark loading as finished
Source.InsertRange(0, bindableMessages);
}
}
finally
{
LoadInitialMessages(messageChannel);
IsLoading = false;
_semaphore.Release();
}
}

private void LoadInitialMessages(IBindableMessageChannel? channel)
/// <remarks>
/// Must be called on the UI thread.
/// </remarks>
private async void LoadInitialMessages()
{
Guard.IsNotNull(channel, nameof(channel));
_dispatcherService.RunOnUIThread(async () =>
await _semaphore.WaitAsync();
try
{
IBindableMessageChannel? channel = SelectedChannel as IBindableMessageChannel;
Guard.IsNotNull(channel, nameof(channel));
// Clear the messages and begin loading
Source.Clear();
IsLoading = true;

// Load messages
IsLoading = true;
var messages = await _discordService.GetChannelMessagesAsync(channel);
BindableMessage[] bindableMessages = new BindableMessage[messages.Length];
if (bindableMessages.Length > 0)
{
bindableMessages[0] = new BindableMessage(_messenger, _discordService, _dispatcherService, messages[messages.Length - 1]);
for (int i = 1; i < messages.Length; i++)
{
bindableMessages[i] = new BindableMessage(_messenger, _discordService, _dispatcherService, messages[messages.Length - 1 - i], messages[messages.Length - i]);
}
}
var bindableMessages = ParseMessages(messages);

// Add messages to the UI and mark loading as finished
Source.AddRange(bindableMessages);
IsLoading = false;
});
}
finally
{
_semaphore.Release();
}
}

private void AppendMessage(Message message)
private void LoadChannel()
{
_dispatcherService.RunOnUIThread(() =>
if (SelectedChannel is IBindableMessageChannel)
{
Source.Add(new BindableMessage(_messenger, _discordService, _dispatcherService, message, Source.Count > 0 ? Source[Source.Count-1].Message : null));
});
LoadInitialMessages();
}
}

private BindableMessage[] ParseMessages(Message[] messages)
{
BindableMessage[] bindableMessages = new BindableMessage[messages.Length];
if (bindableMessages.Length == 0) return bindableMessages;

bindableMessages[0] = new BindableMessage(_messenger, _discordService, _dispatcherService, messages[messages.Length - 1]);
for (int i = 1; i < messages.Length; i++)
{
bindableMessages[i] = new BindableMessage(_messenger, _discordService, _dispatcherService, messages[messages.Length - 1 - i], messages[messages.Length - i]);
}
return bindableMessages;
}

/// <remarks>
/// Must be called on the UI thread.
/// </remarks>
private void AppendMessage(Message message)
{
Source.Add(new BindableMessage(_messenger, _discordService, _dispatcherService, message, Source.Count > 0 ? Source[Source.Count - 1].Message : null));
}
}
}
3 changes: 2 additions & 1 deletion src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
<ListView ItemsSource="{x:Bind ViewModel.Source}"
ItemTemplateSelector="{StaticResource MessageTemplateSelector}"
ItemContainerStyle="{StaticResource MessageListItemStyle}"
ShowsScrollingPlaceholders="False">
ShowsScrollingPlaceholders="False"
Loaded="ListView_Loaded">
<ListView.Header>
<ProgressBar IsIndeterminate="True" Visibility="{x:Bind ViewModel.IsLoading, Mode=OneWay}"/>
</ListView.Header>
Expand Down
27 changes: 27 additions & 0 deletions src/Quarrel/Controls/Panels/Messages/MessagePanel.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
// Quarrel © 2022

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Toolkit.Uwp.UI;
using Quarrel.ViewModels.Panels;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Quarrel.Controls.Panels.Messages
{
public sealed partial class MessagePanel : UserControl
{
private const double ScrollPadding = 100;

public MessagePanel()
{
this.InitializeComponent();
DataContext = App.Current.Services.GetRequiredService<MessagesViewModel>();
}

public MessagesViewModel ViewModel => (MessagesViewModel)DataContext;

private void ListView_Loaded(object sender, RoutedEventArgs e)
{
ListView messageList = (ListView)sender;
var scrollViewer = messageList.FindDescendant<ScrollViewer>();
scrollViewer.ViewChanged += OnViewChanged;
}

private void OnViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
var viewer = (ScrollViewer)sender;
if (viewer.VerticalOffset <= ScrollPadding)
{
if (!ViewModel.IsLoading)
{
ViewModel.LoadOlderMessages();
}
}
else if (viewer.VerticalOffset >= viewer.ScrollableHeight - ScrollPadding)
{
// TODO: Scrolled to bottom
}
}
}
}
4 changes: 3 additions & 1 deletion src/Quarrel/Controls/Shell/QuarrelCommandBar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
xmlns:qc="using:Quarrel.Controls"
xmlns:bchannel="using:Quarrel.Bindables.Channels"
xmlns:cselector="using:Quarrel.Selectors.Channels"
xmlns:cconvert="using:Quarrel.Converters.Discord.Channels"
xmlns:vconvert="using:Quarrel.Converters.Common.Visible"
mc:Ignorable="d"
Background="Transparent"
Expand Down Expand Up @@ -80,7 +81,8 @@
<Button x:Uid="CommandBar/CallBTN"
ToolTipService.ToolTip="Call"
ToolTipService.Placement="Bottom"
Style="{StaticResource CommandBarButton}">
Style="{StaticResource CommandBarButton}"
Visibility="{x:Bind cconvert:IsPrivateChannelVisibleConverter.Convert(ViewModel.SelectedChannel), Mode=OneWay}">
<FontIcon Glyph="&#xE13A;" FontSize="16"/>
</Button>

Expand Down
Loading

0 comments on commit dfc577d

Please sign in to comment.