From f869b1c29c5185681217bb125d1a976aaedd84e7 Mon Sep 17 00:00:00 2001 From: Thomas May Date: Sat, 7 Dec 2024 02:11:23 +0000 Subject: [PATCH 1/5] Honestly not a fan of any of this --- UniSky/Package.appxmanifest | 2 +- UniSky/Pages/NotificationsPage.xaml | 147 +++++++++++++++ UniSky/Pages/NotificationsPage.xaml.cs | 77 ++++++++ UniSky/Pages/SearchPage.xaml | 2 +- UniSky/Resources/en-GB/Resources.resw | 27 +++ .../en-GB/custom-twitter/Resources.resw | 15 ++ UniSky/UniSky.csproj | 20 ++- UniSky/ViewModels/HomeViewModel.cs | 2 + .../Notifications/NotificationViewModel.cs | 169 ++++++++++++++++++ .../Notifications/NotificationsCollection.cs | 139 ++++++++++++++ .../NotificationsPageViewModel.cs | 26 +++ .../PostEmbedImageViewModel.cs | 5 + .../PostEmbedImagesViewModel.cs | 28 +++ .../PostEmbedVideoViewModel.cs | 0 .../{Post => Posts}/PostEmbedViewModel.cs | 0 .../{Post => Posts}/PostViewModel.cs | 4 - 16 files changed, 652 insertions(+), 11 deletions(-) create mode 100644 UniSky/Pages/NotificationsPage.xaml create mode 100644 UniSky/Pages/NotificationsPage.xaml.cs create mode 100644 UniSky/ViewModels/Notifications/NotificationViewModel.cs create mode 100644 UniSky/ViewModels/Notifications/NotificationsCollection.cs create mode 100644 UniSky/ViewModels/Notifications/NotificationsPageViewModel.cs rename UniSky/ViewModels/{Post => Posts}/PostEmbedImageViewModel.cs (66%) rename UniSky/ViewModels/{Post => Posts}/PostEmbedImagesViewModel.cs (69%) rename UniSky/ViewModels/{Post => Posts}/PostEmbedVideoViewModel.cs (100%) rename UniSky/ViewModels/{Post => Posts}/PostEmbedViewModel.cs (100%) rename UniSky/ViewModels/{Post => Posts}/PostViewModel.cs (98%) diff --git a/UniSky/Package.appxmanifest b/UniSky/Package.appxmanifest index a478ff6..1b729b4 100644 --- a/UniSky/Package.appxmanifest +++ b/UniSky/Package.appxmanifest @@ -11,7 +11,7 @@ + Version="1.0.154.0" /> diff --git a/UniSky/Pages/NotificationsPage.xaml b/UniSky/Pages/NotificationsPage.xaml new file mode 100644 index 0000000..cddf834 --- /dev/null +++ b/UniSky/Pages/NotificationsPage.xaml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + diff --git a/UniSky/Pages/NotificationsPage.xaml.cs b/UniSky/Pages/NotificationsPage.xaml.cs new file mode 100644 index 0000000..9e561db --- /dev/null +++ b/UniSky/Pages/NotificationsPage.xaml.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Toolkit.Uwp.UI.Extensions; +using UniSky.Services; +using UniSky.ViewModels.Notifications; +using UniSky.ViewModels.Profile; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.Foundation.Metadata; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace UniSky.Pages; + +public sealed partial class NotificationsPage : Page +{ + public NotificationsPageViewModel ViewModel + { + get { return (NotificationsPageViewModel)GetValue(ViewModelProperty); } + set { SetValue(ViewModelProperty, value); } + } + + public static readonly DependencyProperty ViewModelProperty = + DependencyProperty.Register("ViewModel", typeof(NotificationsPageViewModel), typeof(NotificationsPage), new PropertyMetadata(null)); + + public NotificationsPage() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + + var safeAreaService = ServiceContainer.Scoped.GetRequiredService(); + safeAreaService.SafeAreaUpdated += OnSafeAreaUpdated; + + if (this.ViewModel == null) + this.DataContext = this.ViewModel = ActivatorUtilities.CreateInstance(ServiceContainer.Scoped); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + base.OnNavigatedFrom(e); + + var safeAreaService = ServiceContainer.Scoped.GetRequiredService(); + safeAreaService.SafeAreaUpdated -= OnSafeAreaUpdated; + } + + private void OnSafeAreaUpdated(object sender, SafeAreaUpdatedEventArgs e) + { + TitleBarPadding.Height = new GridLength(e.SafeArea.Bounds.Top); + } + + private void RootList_ItemClick(object sender, ItemClickEventArgs e) + { + + } + + private void RootList_Loaded(object sender, RoutedEventArgs e) + { + if (ApiInformation.IsApiContractPresent(typeof(UniversalApiContract).FullName, 7)) + { + var scrollViewer = RootList.FindDescendant(); + scrollViewer.CanContentRenderOutsideBounds = true; + } + } +} diff --git a/UniSky/Pages/SearchPage.xaml b/UniSky/Pages/SearchPage.xaml index 07995cf..071d4cf 100644 --- a/UniSky/Pages/SearchPage.xaml +++ b/UniSky/Pages/SearchPage.xaml @@ -96,7 +96,7 @@ Following + + {0} liked your post + + + {0} and {1} liked your post + + + {0} followed you + + + {0} mentioned you + + + other + + + {0} quoted your post + + + {0} replied to you + + + {0} and {1} reposted + + + {0} reposted + \ No newline at end of file diff --git a/UniSky/Resources/en-GB/custom-twitter/Resources.resw b/UniSky/Resources/en-GB/custom-twitter/Resources.resw index 9eea7ef..c5394cf 100644 --- a/UniSky/Resources/en-GB/custom-twitter/Resources.resw +++ b/UniSky/Resources/en-GB/custom-twitter/Resources.resw @@ -162,4 +162,19 @@ NEW TWEET + + {0} and {1} liked your tweet + + + {0} liked your tweet + + + {0} and {1} retweeted + + + {0} retweeted + + + {0} quoted your tweet + \ No newline at end of file diff --git a/UniSky/UniSky.csproj b/UniSky/UniSky.csproj index d64bd46..d9db2c3 100644 --- a/UniSky/UniSky.csproj +++ b/UniSky/UniSky.csproj @@ -219,6 +219,9 @@ + + NotificationsPage.xaml + ProfilePage.xaml @@ -250,14 +253,17 @@ - + + + + - - - - + + + + @@ -441,6 +447,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/UniSky/ViewModels/HomeViewModel.cs b/UniSky/ViewModels/HomeViewModel.cs index 0575e17..4304c10 100644 --- a/UniSky/ViewModels/HomeViewModel.cs +++ b/UniSky/ViewModels/HomeViewModel.cs @@ -284,6 +284,8 @@ private void NavigateToPage() this.homeNavigationService.Navigate(); break; case HomePages.Notifications: + this.homeNavigationService.Navigate(); + break; case HomePages.Chat: this.homeNavigationService.Navigate(); break; diff --git a/UniSky/ViewModels/Notifications/NotificationViewModel.cs b/UniSky/ViewModels/Notifications/NotificationViewModel.cs new file mode 100644 index 0000000..3dd7689 --- /dev/null +++ b/UniSky/ViewModels/Notifications/NotificationViewModel.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.ComponentModel; +using FishyFlip.Lexicon.App.Bsky.Embed; +using FishyFlip.Lexicon.App.Bsky.Feed; +using FishyFlip.Lexicon.App.Bsky.Notification; +using FishyFlip.Models; +using Humanizer; +using UniSky.ViewModels.Posts; +using UniSky.ViewModels.Profile; +using Windows.ApplicationModel.Resources; + +namespace UniSky.ViewModels.Notifications; + +public static class NotificationReason +{ + public const string Like = "like", + Repost = "repost", + Follow = "follow", + Mention = "mention", + Reply = "reply", + Quote = "quote", + StarterpackJoined = "starterpack-joined"; +} + +public partial class NotificationViewModel : ViewModelBase, IComparable, IComparable +{ + private class NotificationComparer : IEqualityComparer + { + public bool Equals(Notification x, Notification y) + { + return x?.Cid == y?.Cid; + } + + public int GetHashCode(Notification obj) + { + return obj.Cid.GetHashCode(); + } + } + + private readonly Post subjectPost; + private readonly ATIdentifier subjectPostAuthor; + + [ObservableProperty] + private string notificationTitle; + [ObservableProperty] + private string notificationSubtitle; + [ObservableProperty] + private DateTime timestamp; + [ObservableProperty] + private PostEmbedViewModel notificationEmbed; + [ObservableProperty] + private string avatarUrl; + + public ATUri Subject { get; } + public string Reason { get; } + + public bool ShowAvatar + => Reason is (NotificationReason.Follow or NotificationReason.Reply or NotificationReason.Quote); + public bool IsRetweet + => Reason == NotificationReason.Repost; + public bool IsLike + => Reason == NotificationReason.Like; + + public string Key => + string.Join('-', Reason, Subject); + public int Count => + Notifications.Count; + + public HashSet Notifications { get; } + = new HashSet(new NotificationComparer()); + + private Notification MostRecent + => Notifications.OrderByDescending(d => d.IndexedAt.Value) + .FirstOrDefault(); + + public NotificationViewModel(Notification notification, PostView post = null) + { + this.subjectPost = post?.Record as Post ?? notification.Record as Post; + this.subjectPostAuthor = post?.Author?.Did ?? notification.Author.Did; + Subject = notification.ReasonSubject; + Notifications.Add(notification); + Timestamp = notification.IndexedAt.Value; + Reason = notification.Reason; + Update(); + } + + public NotificationViewModel(IEnumerable notifications, PostView post = null) + : this(notifications.FirstOrDefault(), post) + { + foreach (var item in notifications) + Notifications.Add(item); + + Timestamp = MostRecent.IndexedAt.Value; + Update(); + } + + internal void Add(IEnumerable items) + { + foreach (var item in items) + Notifications.Add(item); + + Timestamp = MostRecent.IndexedAt.Value; + Update(); + } + + private void Update() + { + var resources = ResourceLoader.GetForCurrentView(); + var other = resources.GetString("NotificationOther"); + var mostRecentAuthor = new ProfileViewModel(MostRecent.Author); + + switch (Reason) + { + case NotificationReason.Like: + { + if (Count == 1) + NotificationTitle = string.Format(resources.GetString("NotificationLikedTweetSingle"), mostRecentAuthor.Name); + else + NotificationTitle = string.Format(resources.GetString("NotificationLikedTweetMultiple"), mostRecentAuthor.Name, other.ToQuantity(Count - 1)); + + break; + } + case NotificationReason.Repost: + { + if (Count == 1) + NotificationTitle = string.Format(resources.GetString("NotificationRetweetSingle"), mostRecentAuthor.Name); + else + NotificationTitle = string.Format(resources.GetString("NotificationRetweetMultiple"), mostRecentAuthor.Name, other.ToQuantity(Count - 1)); + + break; + } + case NotificationReason.Follow: + NotificationTitle = string.Format(resources.GetString("NotificationFollow"), mostRecentAuthor.Name); + break; + case NotificationReason.Reply: + NotificationTitle = string.Format(resources.GetString("NotificationReply"), mostRecentAuthor.Name); + break; + case NotificationReason.Mention: + NotificationTitle = string.Format(resources.GetString("NotificationMention"), mostRecentAuthor.Name); + break; + case NotificationReason.Quote: + NotificationTitle = string.Format(resources.GetString("NotificationQuote"), mostRecentAuthor.Name); + break; + } + + AvatarUrl = mostRecentAuthor.AvatarUrl; + NotificationSubtitle = subjectPost?.Text; + if (subjectPost is { Embed: EmbedImages and { } images }) + { + NotificationEmbed = new PostEmbedImagesViewModel(subjectPostAuthor, images); + } + } + + public int CompareTo(object obj) + { + return -((IComparable)Timestamp).CompareTo(((NotificationViewModel)obj).Timestamp); + } + + public int CompareTo(NotificationViewModel other) + { + return Timestamp.CompareTo(other.Timestamp); + } +} diff --git a/UniSky/ViewModels/Notifications/NotificationsCollection.cs b/UniSky/ViewModels/Notifications/NotificationsCollection.cs new file mode 100644 index 0000000..b42181a --- /dev/null +++ b/UniSky/ViewModels/Notifications/NotificationsCollection.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using FishyFlip.Lexicon.App.Bsky.Feed; +using FishyFlip.Models; +using System.Web; +using UniSky.Services; +using UniSky.ViewModels.Feeds; +using UniSky.ViewModels.Posts; +using UniSky.ViewModels.Profile; +using Windows.Foundation; +using Windows.UI.Core; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml; +using FishyFlip.Lexicon.App.Bsky.Notification; +using FishyFlip.Tools; +using System.Collections; +using Windows.UI.Notifications; +using FishyFlip.Lexicon.App.Bsky.Actor; + +namespace UniSky.ViewModels.Notifications; + +public class NotificationsCollection : ObservableCollection, ISupportIncrementalLoading +{ + private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); + private readonly CoreDispatcher dispatcher = Window.Current.Dispatcher; + + private readonly NotificationsPageViewModel parent; + private readonly IProtocolService protocolService; + + private string cursor; + + public NotificationsCollection(NotificationsPageViewModel parent, IProtocolService protocolService) + { + this.parent = parent; + this.protocolService = protocolService; + } + public bool HasMoreItems { get; private set; } = true; + + + public IAsyncOperation LoadMoreItemsAsync(uint count) + { + return Task.Run(async () => + { + try + { + await semaphore.WaitAsync(); + return await InternalLoadMoreItemsAsync((int)count); + } + finally + { + semaphore.Release(); + } + }).AsAsyncOperation(); + } + + private async Task InternalLoadMoreItemsAsync(int count) + { + var service = protocolService.Protocol; + var viewModel = parent; + viewModel.Error = null; + + count = Math.Clamp(count, 5, 25); + + using var context = viewModel.GetLoadingContext(); + + try + { + var notifications = (await service.ListNotificationsAsync(count, cursor: cursor) + .ConfigureAwait(false)) + .HandleResult(); + + this.cursor = notifications.Cursor; + + var hydratePostIds = notifications.Notifications.Where(n => + n.Reason is (NotificationReason.Like or NotificationReason.Repost) && + n.ReasonSubject is not null) + .Select(s => s.ReasonSubject) + .Distinct(); + + var posts = (await service.GetPostsAsync(hydratePostIds.ToList()) + .ConfigureAwait(false)) + .HandleResult(); + + await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + var groups = notifications.Notifications + .GroupBy(g => (g.Reason is (NotificationReason.Like or NotificationReason.Repost)) ? string.Join('-', g.Reason, g.ReasonSubject) : null); + foreach (var group in groups) + { + NotificationViewModel viewModel; + if (group.Key != null && (viewModel = this.FirstOrDefault(v => v.Subject != null && v.Key == group.Key)) != null) + { + viewModel.Add(group); + continue; + } + + if (group.Key == null) + { + foreach (var notification in group) + { + PostView post = null; + if (notification.Reason is (NotificationReason.Like or NotificationReason.Repost)) + post = posts.Posts.FirstOrDefault(p => p.Uri.ToString() == notification.ReasonSubject.ToString()); + + Add(new NotificationViewModel(notification, post)); + } + } + else + { + var notification = group.FirstOrDefault(); + + PostView post = null; + if (notification.Reason is (NotificationReason.Like or NotificationReason.Repost)) + post = posts.Posts.FirstOrDefault(p => p.Uri.ToString() == notification.ReasonSubject.ToString()); + + Add(new NotificationViewModel(group, post)); + } + } + + ArrayList.Adapter(this).Sort(); // ????? + }); + + if (notifications.Notifications.Count == 0 || string.IsNullOrWhiteSpace(this.cursor)) + HasMoreItems = false; + + return new LoadMoreItemsResult() { Count = (uint)notifications.Notifications.Count }; + } + catch (Exception ex) + { + HasMoreItems = false; + return new LoadMoreItemsResult() { Count = 0 }; + } + } +} diff --git a/UniSky/ViewModels/Notifications/NotificationsPageViewModel.cs b/UniSky/ViewModels/Notifications/NotificationsPageViewModel.cs new file mode 100644 index 0000000..e111ab2 --- /dev/null +++ b/UniSky/ViewModels/Notifications/NotificationsPageViewModel.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FishyFlip.Lexicon.App.Bsky.Actor; +using FishyFlip.Tools; +using Microsoft.Extensions.Logging; +using UniSky.Services; +using Windows.UI.Xaml.Data; + +namespace UniSky.ViewModels.Notifications; + +public partial class NotificationsPageViewModel : ViewModelBase +{ + private IProtocolService protocolService; + + + public NotificationsCollection Notifications { get; } + + public NotificationsPageViewModel(IProtocolService protocolService) + { + this.protocolService = protocolService; + this.Notifications = new NotificationsCollection(this, protocolService); + } +} diff --git a/UniSky/ViewModels/Post/PostEmbedImageViewModel.cs b/UniSky/ViewModels/Posts/PostEmbedImageViewModel.cs similarity index 66% rename from UniSky/ViewModels/Post/PostEmbedImageViewModel.cs rename to UniSky/ViewModels/Posts/PostEmbedImageViewModel.cs index 53f7fae..ec15fde 100644 --- a/UniSky/ViewModels/Post/PostEmbedImageViewModel.cs +++ b/UniSky/ViewModels/Posts/PostEmbedImageViewModel.cs @@ -9,6 +9,11 @@ public partial class PostEmbedImageViewModel : ViewModelBase [ObservableProperty] private string thumbnailUrl; + public PostEmbedImageViewModel(ATIdentifier id, Image image) + { + ThumbnailUrl = $"https://cdn.bsky.app/img/feed_thumbnail/plain/{id}/{image.ImageValue.Ref.Link}@jpeg"; + } + public PostEmbedImageViewModel(ViewImage image) { ThumbnailUrl = image.Thumb; diff --git a/UniSky/ViewModels/Post/PostEmbedImagesViewModel.cs b/UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs similarity index 69% rename from UniSky/ViewModels/Post/PostEmbedImagesViewModel.cs rename to UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs index 868c793..892da4f 100644 --- a/UniSky/ViewModels/Post/PostEmbedImagesViewModel.cs +++ b/UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs @@ -35,6 +35,34 @@ public PostEmbedImageViewModel Image4 public bool IsThree => Count == 3; public bool IsFour => Count == 4; + public PostEmbedImagesViewModel(ATIdentifier id, EmbedImages embed) : base(embed) + { + Count = embed.Images.Count; + Images = embed.Images.Select(i => new PostEmbedImageViewModel(id, i)).ToArray(); + + // this would be problematic + Debug.Assert(Images.Length > 0 && Images.Length <= 4); + Debug.Assert(embed.Images.Count == Images.Length); + Debug.Assert(Images.Length == Count); + + var firstRatio = embed.Images[0].AspectRatio; + if (Images.Length == 1 && firstRatio == null) + { + AspectRatio = new(); + } + else + { + AspectRatio = new AspectRatioConstraint(Images.Length switch + { + 1 => Math.Max((double)firstRatio.Width.Value / firstRatio.Height.Value, 0.75), + 2 => 2.0, + 3 => 2.0, + 4 => 3.0 / 2.0, + _ => throw new NotImplementedException() + }); + } + } + public PostEmbedImagesViewModel(ViewImages embed) : base(embed) { Count = embed.Images.Count; diff --git a/UniSky/ViewModels/Post/PostEmbedVideoViewModel.cs b/UniSky/ViewModels/Posts/PostEmbedVideoViewModel.cs similarity index 100% rename from UniSky/ViewModels/Post/PostEmbedVideoViewModel.cs rename to UniSky/ViewModels/Posts/PostEmbedVideoViewModel.cs diff --git a/UniSky/ViewModels/Post/PostEmbedViewModel.cs b/UniSky/ViewModels/Posts/PostEmbedViewModel.cs similarity index 100% rename from UniSky/ViewModels/Post/PostEmbedViewModel.cs rename to UniSky/ViewModels/Posts/PostEmbedViewModel.cs diff --git a/UniSky/ViewModels/Post/PostViewModel.cs b/UniSky/ViewModels/Posts/PostViewModel.cs similarity index 98% rename from UniSky/ViewModels/Post/PostViewModel.cs rename to UniSky/ViewModels/Posts/PostViewModel.cs index f36a84d..275311a 100644 --- a/UniSky/ViewModels/Post/PostViewModel.cs +++ b/UniSky/ViewModels/Posts/PostViewModel.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -17,14 +16,11 @@ using Microsoft.Extensions.DependencyInjection; using UniSky.Controls.Compose; using UniSky.Helpers; -using UniSky.Pages; using UniSky.Services; using UniSky.ViewModels.Profile; using UniSky.ViewModels.Text; -using Windows.ApplicationModel; using Windows.ApplicationModel.DataTransfer; using Windows.UI.Xaml; -using Windows.UI.Xaml.Media.Animation; namespace UniSky.ViewModels.Posts; From 4fa6b988a848dbc20666eb2e74a567eefec49385 Mon Sep 17 00:00:00 2001 From: Thomas May Date: Sat, 7 Dec 2024 02:27:11 +0000 Subject: [PATCH 2/5] small cleanup --- .../Posts/PostEmbedImagesViewModel.cs | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs b/UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs index 892da4f..25f20d9 100644 --- a/UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs +++ b/UniSky/ViewModels/Posts/PostEmbedImagesViewModel.cs @@ -46,21 +46,7 @@ public PostEmbedImagesViewModel(ATIdentifier id, EmbedImages embed) : base(embed Debug.Assert(Images.Length == Count); var firstRatio = embed.Images[0].AspectRatio; - if (Images.Length == 1 && firstRatio == null) - { - AspectRatio = new(); - } - else - { - AspectRatio = new AspectRatioConstraint(Images.Length switch - { - 1 => Math.Max((double)firstRatio.Width.Value / firstRatio.Height.Value, 0.75), - 2 => 2.0, - 3 => 2.0, - 4 => 3.0 / 2.0, - _ => throw new NotImplementedException() - }); - } + SetAspectRatio(firstRatio); } public PostEmbedImagesViewModel(ViewImages embed) : base(embed) @@ -74,6 +60,11 @@ public PostEmbedImagesViewModel(ViewImages embed) : base(embed) Debug.Assert(Images.Length == Count); var firstRatio = embed.Images[0].AspectRatio; + SetAspectRatio(firstRatio); + } + + private void SetAspectRatio(AspectRatio firstRatio) + { if (Images.Length == 1 && firstRatio == null) { AspectRatio = new(); From b0b8560fdf3791962df3d3467d414114abdb68c0 Mon Sep 17 00:00:00 2001 From: Thomas May Date: Sat, 7 Dec 2024 02:32:07 +0000 Subject: [PATCH 3/5] slight improvements --- .../Notifications/NotificationsCollection.cs | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/UniSky/ViewModels/Notifications/NotificationsCollection.cs b/UniSky/ViewModels/Notifications/NotificationsCollection.cs index b42181a..7edf976 100644 --- a/UniSky/ViewModels/Notifications/NotificationsCollection.cs +++ b/UniSky/ViewModels/Notifications/NotificationsCollection.cs @@ -1,26 +1,17 @@ using System; -using System.Collections.Generic; +using System.Collections; using System.Collections.ObjectModel; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using FishyFlip.Lexicon.App.Bsky.Feed; -using FishyFlip.Models; -using System.Web; +using FishyFlip.Lexicon.App.Bsky.Notification; +using FishyFlip.Tools; using UniSky.Services; -using UniSky.ViewModels.Feeds; -using UniSky.ViewModels.Posts; -using UniSky.ViewModels.Profile; using Windows.Foundation; using Windows.UI.Core; -using Windows.UI.Xaml.Data; using Windows.UI.Xaml; -using FishyFlip.Lexicon.App.Bsky.Notification; -using FishyFlip.Tools; -using System.Collections; -using Windows.UI.Notifications; -using FishyFlip.Lexicon.App.Bsky.Actor; +using Windows.UI.Xaml.Data; namespace UniSky.ViewModels.Notifications; @@ -84,12 +75,15 @@ n.Reason is (NotificationReason.Like or NotificationReason.Repost) && var posts = (await service.GetPostsAsync(hydratePostIds.ToList()) .ConfigureAwait(false)) - .HandleResult(); + .HandleResult() + .Posts + .ToDictionary(k => k.Uri.ToString()); await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var groups = notifications.Notifications .GroupBy(g => (g.Reason is (NotificationReason.Like or NotificationReason.Repost)) ? string.Join('-', g.Reason, g.ReasonSubject) : null); + foreach (var group in groups) { NotificationViewModel viewModel; @@ -99,27 +93,28 @@ await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => continue; } + Notification notification = null; + PostView post = null; if (group.Key == null) { - foreach (var notification in group) + foreach (var ungroupedNotification in group) { - PostView post = null; if (notification.Reason is (NotificationReason.Like or NotificationReason.Repost)) - post = posts.Posts.FirstOrDefault(p => p.Uri.ToString() == notification.ReasonSubject.ToString()); + _ = posts.TryGetValue(notification.ReasonSubject.ToString(), out post); Add(new NotificationViewModel(notification, post)); } + + continue; } - else - { - var notification = group.FirstOrDefault(); - PostView post = null; - if (notification.Reason is (NotificationReason.Like or NotificationReason.Repost)) - post = posts.Posts.FirstOrDefault(p => p.Uri.ToString() == notification.ReasonSubject.ToString()); + notification = group.FirstOrDefault(); + post = null; - Add(new NotificationViewModel(group, post)); - } + if (notification.Reason is (NotificationReason.Like or NotificationReason.Repost)) + _ = posts.TryGetValue(notification.ReasonSubject.ToString(), out post); + + Add(new NotificationViewModel(group, post)); } ArrayList.Adapter(this).Sort(); // ????? From 5ac968c16380dfdc4326ed33afe138b5bfa53293 Mon Sep 17 00:00:00 2001 From: Thomas May Date: Sat, 7 Dec 2024 02:34:02 +0000 Subject: [PATCH 4/5] improve count logic --- UniSky/ViewModels/Notifications/NotificationsCollection.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UniSky/ViewModels/Notifications/NotificationsCollection.cs b/UniSky/ViewModels/Notifications/NotificationsCollection.cs index 7edf976..9ca6746 100644 --- a/UniSky/ViewModels/Notifications/NotificationsCollection.cs +++ b/UniSky/ViewModels/Notifications/NotificationsCollection.cs @@ -79,6 +79,8 @@ n.Reason is (NotificationReason.Like or NotificationReason.Repost) && .Posts .ToDictionary(k => k.Uri.ToString()); + var initialCount = Count; + await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var groups = notifications.Notifications @@ -123,7 +125,7 @@ await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => if (notifications.Notifications.Count == 0 || string.IsNullOrWhiteSpace(this.cursor)) HasMoreItems = false; - return new LoadMoreItemsResult() { Count = (uint)notifications.Notifications.Count }; + return new LoadMoreItemsResult() { Count = (uint)(Count - initialCount) }; } catch (Exception ex) { From ab8ff8d5777d96fd45b2f769e09733e8e86cd299 Mon Sep 17 00:00:00 2001 From: Thomas May Date: Sat, 7 Dec 2024 02:35:21 +0000 Subject: [PATCH 5/5] pain --- UniSky/ViewModels/Notifications/NotificationsCollection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/UniSky/ViewModels/Notifications/NotificationsCollection.cs b/UniSky/ViewModels/Notifications/NotificationsCollection.cs index 9ca6746..7842fce 100644 --- a/UniSky/ViewModels/Notifications/NotificationsCollection.cs +++ b/UniSky/ViewModels/Notifications/NotificationsCollection.cs @@ -101,6 +101,7 @@ await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { foreach (var ungroupedNotification in group) { + notification = ungroupedNotification; if (notification.Reason is (NotificationReason.Like or NotificationReason.Repost)) _ = posts.TryGetValue(notification.ReasonSubject.ToString(), out post);