diff --git a/Valour/Client/Components/Menus/Modals/Users/Edit/EditDevicePreferencesComponent.razor b/Valour/Client/Components/Menus/Modals/Users/Edit/EditDevicePreferencesComponent.razor index 783918769..05b00c5ce 100644 --- a/Valour/Client/Components/Menus/Modals/Users/Edit/EditDevicePreferencesComponent.razor +++ b/Valour/Client/Components/Menus/Modals/Users/Edit/EditDevicePreferencesComponent.razor @@ -23,6 +23,17 @@

When enabled, faces like :) will be automatically turned into emojis in chat.

+
+
+ Big Emojis + +
+

When enabled, messages containing only a few emojis (5 or less) are shown larger.

+
+
Error Reporting @@ -419,6 +430,11 @@ MarkdownManager.RegenPipeline(); } + private async Task SwitchBigEmojiMessages() + { + await DevicePreferences.SetBigEmojiMessages(!DevicePreferences.BigEmojiMessages, LocalStorage); + } + private string GetMicPermissionDescription() { if (string.Equals(_micPermissionState, "granted", StringComparison.OrdinalIgnoreCase)) diff --git a/Valour/Client/Components/Messages/MessageComponent.razor b/Valour/Client/Components/Messages/MessageComponent.razor index 6cf65c718..b867984b8 100644 --- a/Valour/Client/Components/Messages/MessageComponent.razor +++ b/Valour/Client/Components/Messages/MessageComponent.razor @@ -201,8 +201,10 @@ else if (string.IsNullOrWhiteSpace(_message.Content)) return; + var isBigEmoji = DevicePreferences.BigEmojiMessages && MarkdownManager.IsEmojiOnlyMessage(_message.Content); + builder.OpenElement(0, "div"); - builder.AddAttribute(1, "class", "fragments"); + builder.AddAttribute(1, "class", isBigEmoji ? "fragments big-emoji" : "fragments"); try { Markdown.RenderToFragment( diff --git a/Valour/Client/Device/DevicePreferences.cs b/Valour/Client/Device/DevicePreferences.cs index bf114cf8c..50e918b1d 100644 --- a/Valour/Client/Device/DevicePreferences.cs +++ b/Valour/Client/Device/DevicePreferences.cs @@ -19,6 +19,12 @@ public static class DevicePreferences /// public static bool AutoEmoji { get; set; } = false; // Default it to off + /// + /// True if messages containing only a few emojis (and no other text) should + /// be rendered larger, the same size as a heading. + /// + public static bool BigEmojiMessages { get; set; } = true; + public static string? MicrophoneDeviceId { get; set; } public static string? CameraDeviceId { get; set; } public static bool ErrorReportingEnabled { get; private set; } @@ -49,6 +55,12 @@ public static async Task SetErrorReportingEnabled(bool isEnabled, IAppStorage lo await localStorage.SetAsync(ErrorReportingEnabledStorageKey, isEnabled); } + public static async Task SetBigEmojiMessages(bool isEnabled, IAppStorage localStorage) + { + BigEmojiMessages = isEnabled; + await localStorage.SetAsync("BigEmojiMessages", isEnabled); + } + public static async Task SetForceGpuAccelerationEnabled(bool isEnabled, IAppStorage localStorage) { ForceGpuAcceleration = isEnabled; @@ -67,6 +79,11 @@ public static async Task LoadPreferences(IAppStorage localStorage) AutoEmoji = await localStorage.GetAsync("AutoEmoji"); } + if (await localStorage.ContainsKeyAsync("BigEmojiMessages")) + { + BigEmojiMessages = await localStorage.GetAsync("BigEmojiMessages"); + } + if (await localStorage.ContainsKeyAsync("MicrophoneDeviceId")) { MicrophoneDeviceId = await localStorage.GetAsync("MicrophoneDeviceId"); diff --git a/Valour/Client/Messages/Rendering/MarkdownManager.cs b/Valour/Client/Messages/Rendering/MarkdownManager.cs index 0cd61733a..3703a3544 100644 --- a/Valour/Client/Messages/Rendering/MarkdownManager.cs +++ b/Valour/Client/Messages/Rendering/MarkdownManager.cs @@ -1,6 +1,8 @@ using Markdig; using Markdig.Blazor; using Markdig.Extensions.AutoLinks; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; using Valour.Client.Device; using Valour.Client.Markdig; using Markdown = Markdig.Markdown; @@ -51,6 +53,57 @@ public static void RegenPipeline() Renderer.ObjectRenderers.Insert(0, new ValourLinkRenderer()); } + /// + /// Maximum number of emojis a message can contain and still be rendered + /// large by the "big emoji" preference. + /// + public const int MaxBigEmojiCount = 5; + + /// + /// Returns true if the given message content is made up of nothing but + /// 1-5 emojis (no other text), and is therefore eligible to be rendered + /// at heading size when the big-emoji preference is enabled. + /// + public static bool IsEmojiOnlyMessage(string content) + { + if (string.IsNullOrWhiteSpace(content)) + return false; + + MarkdownDocument document; + + try + { + document = Markdown.Parse(content, Pipeline); + } + catch + { + return false; + } + + if (document.Count != 1 || document[0] is not ParagraphBlock { Inline: { } inline }) + return false; + + var emojiCount = 0; + + foreach (var item in inline) + { + switch (item) + { + case ValourEmojiInline: + emojiCount++; + break; + case LineBreakInline: + break; + case LiteralInline literal when literal.Content.IsEmptyOrWhitespace(): + break; + default: + return false; + } + } + + return emojiCount is > 0 and <= MaxBigEmojiCount; + } + public static string GetHtml(string content) { if (content is null) diff --git a/Valour/Client/wwwroot/css/globals.css b/Valour/Client/wwwroot/css/globals.css index ab012024a..5bcbc4036 100644 --- a/Valour/Client/wwwroot/css/globals.css +++ b/Valour/Client/wwwroot/css/globals.css @@ -1210,6 +1210,10 @@ img.emoji { max-height: 900px !important; } +.message .fragments.big-emoji { + font-size: var(--font-size-5xl); +} + .message .fragments a:not(.nohide) { font-size: 0; }