From 9bea81ecda9f829fcbdd5f2bf81c1c7e8245cc95 Mon Sep 17 00:00:00 2001 From: Julien Richard Date: Sun, 23 Oct 2022 19:06:48 +0200 Subject: [PATCH] Add xml serialization --- src/Greenshot.Editor/Controls/EmojiData.cs | 148 +++++++++--------- .../Controls/EmojiPicker.xaml | 2 +- .../Controls/EmojiPicker.xaml.cs | 6 +- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/src/Greenshot.Editor/Controls/EmojiData.cs b/src/Greenshot.Editor/Controls/EmojiData.cs index 0821e59da..0e1eb0039 100644 --- a/src/Greenshot.Editor/Controls/EmojiData.cs +++ b/src/Greenshot.Editor/Controls/EmojiData.cs @@ -16,59 +16,34 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; +using System.Xml; +using System.Xml.Serialization; using SixLabors.Fonts.Unicode; namespace Greenshot.Editor.Controls { public static class EmojiData { - private static Task _init; - public static IList AllGroups { get; private set; } + private const string FilePath = "emojis.xml"; + + public static Emojis Data { get; private set; } = new Emojis(); public static void Load() { - _init ??= Task.Run(ParseEmojiList); - } + var x = new XmlSerializer(typeof(Emojis)); - public class Emoji - { - public string Name { get; set; } - public string Text { get; set; } - public bool HasVariations => VariationList.Count > 0; - - public Group Group => SubGroup.Group; - public SubGroup SubGroup; - - public IList VariationList { get; } = new List(); - } - - public class SubGroup - { - public string Name { get; set; } - public Group Group; - - public IList EmojiList { get; } = new List(); - } - - public class Group - { - public string Name { get; set; } - public string Icon => SubGroups.FirstOrDefault()?.EmojiList.FirstOrDefault()?.Text; - - public IList SubGroups { get; } = new List(); - - public int EmojiCount - => SubGroups.Select(s => s.EmojiList.Count).Sum(); - - public IEnumerable> EmojiChunkList - => new ChunkHelper(EmojiList, 8); - - public IEnumerable EmojiList - => from s in SubGroups - from e in s.EmojiList - select e; + if (File.Exists(FilePath)) + { + Data = (Emojis)x.Deserialize(new XmlTextReader(FilePath)); + } + else + { + // To be removed + ParseEmojiList(); + x.Serialize(new XmlTextWriter(FilePath, Encoding.UTF8), Data); + } } private static List SkinToneComponents = new List @@ -93,7 +68,7 @@ namespace Greenshot.Editor.Controls private static void ParseEmojiList() { - var lookup_by_name = new Dictionary(); + var lookup_by_name = new Dictionary(); var match_group = new Regex(@"^# group: (.*)"); var match_subgroup = new Regex(@"^# subgroup: (.*)"); var match_sequence = new Regex(@"^([0-9a-fA-F ]+[0-9a-fA-F]).*; *([-a-z]*) *# [^ ]* (E[0-9.]* )?(.*)"); @@ -105,26 +80,25 @@ namespace Greenshot.Editor.Controls var match_family = new Regex($"{adult}(\u200d{adult})*(\u200d{child})+"); var qualified_lut = new Dictionary(); - var list = new List(); var alltext = new List(); - Group current_group = null; - SubGroup current_subgroup = null; + Emojis.Group current_group = null; + Emojis.Group current_subgroup = null; foreach (var line in EmojiDescriptionLines()) { var m = match_group.Match(line); if (m.Success) { - current_group = new Group { Name = m.Groups[1].ToString() }; - list.Add(current_group); + current_group = new Emojis.Group { Name = m.Groups[1].ToString() }; + Data.Groups.Add(current_group); continue; } m = match_subgroup.Match(line); if (m.Success) { - current_subgroup = new SubGroup { Name = m.Groups[1].ToString(), Group = current_group }; + current_subgroup = new Emojis.Group { Name = m.Groups[1].ToString() }; current_group.SubGroups.Add(current_subgroup); continue; } @@ -181,13 +155,8 @@ namespace Greenshot.Editor.Controls qualified_lut[unqualified] = text; - var emoji = new Emoji - { - Name = name, - Text = text, - SubGroup = current_subgroup, - }; - + var emoji = new Emojis.Emoji { Name = name, Text = text, }; + lookup_by_name[ToColonSyntax(name)] = emoji; // Get the left part of the name and check whether we’re a variation of an existing @@ -195,18 +164,15 @@ namespace Greenshot.Editor.Controls // FIXME: does not work properly because variations can appear before the generic emoji if (name.Contains(":") && lookup_by_name.TryGetValue(ToColonSyntax(name.Split(':')[0]), out var parent_emoji)) { - if (parent_emoji.VariationList.Count == 0) - parent_emoji.VariationList.Add(parent_emoji); - parent_emoji.VariationList.Add(emoji); + parent_emoji.Variations.Add(emoji); } else - current_subgroup.EmojiList.Add(emoji); + current_subgroup.Emojis.Add(emoji); } } // Remove the Component group. Not sure we want to have the skin tones in the picker. - list.RemoveAll(g => g.Name == "Component"); - AllGroups = list; + Data.Groups.RemoveAll(g => g.Name == "Component"); } private static IEnumerable EmojiDescriptionLines() @@ -217,6 +183,49 @@ namespace Greenshot.Editor.Controls } } + public class Emojis + { + [XmlElement(ElementName = "Group")] + public List Groups { get; set; } = new(); + + public class Group + { + [XmlAttribute] + public string Name { get; set; } + + [XmlElement(ElementName = "Group")] + public List SubGroups { get; set; } = new(); + + [XmlElement(ElementName = "Emoji")] + public List Emojis { get; set; } = new(); + + public IEnumerable> EmojiChunkList => new ChunkHelper(EmojiList, 8); + + public string Icon => SubGroups.FirstOrDefault()?.Emojis.FirstOrDefault()?.Text; + + public IEnumerable EmojiList + => from s in SubGroups + from e in s.Emojis + select e; + } + + public class Emoji + { + [XmlAttribute] + public string Name { get; set; } + + [XmlAttribute] + public string Text { get; set; } + + [XmlArray] + public List Variations { get; set; } + + public bool HasVariations => Variations.Count > 0; + + public IEnumerable AllVariations => HasVariations ? new[] { this }.Union(Variations) : Array.Empty(); + } + } + sealed class ChunkHelper : IEnumerable> { public ChunkHelper(IEnumerable elements, int size) @@ -227,12 +236,10 @@ namespace Greenshot.Editor.Controls public IEnumerator> GetEnumerator() { - using (var enumerator = m_elements.GetEnumerator()) - { - m_has_more = enumerator.MoveNext(); - while (m_has_more) - yield return GetNextBatch(enumerator).ToList(); - } + using var enumerator = m_elements.GetEnumerator(); + m_has_more = enumerator.MoveNext(); + while (m_has_more) + yield return GetNextBatch(enumerator).ToList(); } private IEnumerable GetNextBatch(IEnumerator enumerator) @@ -246,11 +253,10 @@ namespace Greenshot.Editor.Controls } } - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private readonly IEnumerable m_elements; private readonly int m_size; private bool m_has_more; } -} +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Controls/EmojiPicker.xaml b/src/Greenshot.Editor/Controls/EmojiPicker.xaml index ba5a4e547..011754560 100644 --- a/src/Greenshot.Editor/Controls/EmojiPicker.xaml +++ b/src/Greenshot.Editor/Controls/EmojiPicker.xaml @@ -13,7 +13,7 @@ - EmojiGroups => EmojiData.AllGroups; + public IList EmojiGroups => EmojiData.Data.Groups; // Backwards compatibility for when the backend was a TextBlock. public double FontSize @@ -77,8 +77,8 @@ namespace Greenshot.Editor.Controls private void OnEmojiPicked(object sender, RoutedEventArgs e) { - if (sender is not Control { DataContext: EmojiData.Emoji emoji }) return; - if (emoji.VariationList.Count != 0 && sender is not Button) return; + if (sender is not Control { DataContext: Emojis.Emoji emoji }) return; + if (emoji.Variations.Count != 0 && sender is not Button) return; Selection = emoji.Text; Button_INTERNAL.IsChecked = false;