From abb466d73e7eaee77ab9163a4ff3273218bfa92d Mon Sep 17 00:00:00 2001 From: pgrho Date: Thu, 14 Sep 2017 12:46:01 +0900 Subject: [PATCH] Changed message view to be WebView --- .../KokoroIO.XamarinForms.Android.csproj | 1 - .../MessageContentRenderer.cs | 118 ------------- .../KokoroIO.XamarinForms.UWP.csproj | 2 - .../MessageContentRenderer.cs | 160 ------------------ .../MessageListViewRenderer.cs | 99 ----------- .../KokoroIO.XamarinForms.projitems | 9 +- .../ViewModels/ListMessageBlock.cs | 27 --- .../ViewModels/MessageBlock.cs | 23 --- .../ViewModels/MessageBlockBase.cs | 14 -- .../ViewModels/MessageInfo.cs | 70 +------- .../ViewModels/MessageListItem.cs | 12 -- .../ViewModels/MessageSpan.cs | 52 ------ .../ViewModels/MessageSpanType.cs | 8 - .../Views/MessageContent.cs | 17 -- .../Views/MessageListView.cs | 19 --- .../Views/MessageWebView.cs | 137 +++++++++++++++ .../Views/MessagesPage.xaml | 75 +------- 17 files changed, 142 insertions(+), 701 deletions(-) delete mode 100644 src/KokoroIO.XamarinForms.Android/MessageContentRenderer.cs delete mode 100644 src/KokoroIO.XamarinForms.UWP/MessageContentRenderer.cs delete mode 100644 src/KokoroIO.XamarinForms.UWP/MessageListViewRenderer.cs delete mode 100644 src/KokoroIO.XamarinForms/ViewModels/ListMessageBlock.cs delete mode 100644 src/KokoroIO.XamarinForms/ViewModels/MessageBlock.cs delete mode 100644 src/KokoroIO.XamarinForms/ViewModels/MessageBlockBase.cs delete mode 100644 src/KokoroIO.XamarinForms/ViewModels/MessageListItem.cs delete mode 100644 src/KokoroIO.XamarinForms/ViewModels/MessageSpan.cs delete mode 100644 src/KokoroIO.XamarinForms/ViewModels/MessageSpanType.cs delete mode 100644 src/KokoroIO.XamarinForms/Views/MessageContent.cs delete mode 100644 src/KokoroIO.XamarinForms/Views/MessageListView.cs create mode 100644 src/KokoroIO.XamarinForms/Views/MessageWebView.cs diff --git a/src/KokoroIO.XamarinForms.Android/KokoroIO.XamarinForms.Android.csproj b/src/KokoroIO.XamarinForms.Android/KokoroIO.XamarinForms.Android.csproj index f679cd1..459f87e 100644 --- a/src/KokoroIO.XamarinForms.Android/KokoroIO.XamarinForms.Android.csproj +++ b/src/KokoroIO.XamarinForms.Android/KokoroIO.XamarinForms.Android.csproj @@ -98,7 +98,6 @@ - diff --git a/src/KokoroIO.XamarinForms.Android/MessageContentRenderer.cs b/src/KokoroIO.XamarinForms.Android/MessageContentRenderer.cs deleted file mode 100644 index 5478c80..0000000 --- a/src/KokoroIO.XamarinForms.Android/MessageContentRenderer.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.ComponentModel; -using Android.Text; -using Android.Widget; -using KokoroIO.XamarinForms.Droid; -using KokoroIO.XamarinForms.ViewModels; -using KokoroIO.XamarinForms.Views; -using Xamarin.Forms; -using Xamarin.Forms.Platform.Android; - -[assembly: ExportRenderer(typeof(MessageContent), typeof(MessageContentRenderer))] - -namespace KokoroIO.XamarinForms.Droid -{ - public sealed class MessageContentRenderer : ViewRenderer - { - protected override void OnElementChanged(ElementChangedEventArgs e) - { - base.OnElementChanged(e); - - if (e.NewElement != null) - { - if (Control == null) - { - SetNativeControl(new TextView(Context)); - } - UpdateBlocks(Control); - } - } - - protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == MessageContent.BlocksProperty.PropertyName) - { - UpdateBlocks(Control); - } - base.OnElementPropertyChanged(sender, e); - } - - private WeakReference _Blocks; - - private void UpdateBlocks(TextView textView) - { - if (_Blocks != null && _Blocks.TryGetTarget(out var v)) - { - v.CollectionChanged -= Blocks_CollectionChanged; - } - - var bs = Element.Blocks; - - if (bs is INotifyCollectionChanged cc) - { - cc.CollectionChanged += Blocks_CollectionChanged; - _Blocks = new WeakReference(cc); - } - else - { - _Blocks = null; - } - - if (bs == null) - { - textView.Text = ""; - return; - } - - var builder = new SpannableStringBuilder(); - - foreach (var b in bs) - { - if (builder.Length() > 0) - { - builder.Append(System.Environment.NewLine); - builder.Append(System.Environment.NewLine); - } - - if (b is MessageBlock mb) - { - foreach (var s in mb.Spans) - { - AppendSpan(s, builder); - } - } - else if (b is ListMessageBlock lmb) - { - foreach (var li in lmb.Items) - { - if (builder.Length() > 0) - { - builder.Append(System.Environment.NewLine); - } - - builder.Append(" * "); - foreach (var s in li.Spans) - { - AppendSpan(s, builder); - } - } - } - else - { - builder.Append(b.ToString()); - } - } - - textView.TextFormatted = builder; - } - - private static void AppendSpan(MessageSpan s, SpannableStringBuilder builder) - { - builder.Append(s.Text); - } - - private void Blocks_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - => UpdateBlocks(Control); - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms.UWP/KokoroIO.XamarinForms.UWP.csproj b/src/KokoroIO.XamarinForms.UWP/KokoroIO.XamarinForms.UWP.csproj index 8425a2e..d335c84 100644 --- a/src/KokoroIO.XamarinForms.UWP/KokoroIO.XamarinForms.UWP.csproj +++ b/src/KokoroIO.XamarinForms.UWP/KokoroIO.XamarinForms.UWP.csproj @@ -106,8 +106,6 @@ MainPage.xaml - - diff --git a/src/KokoroIO.XamarinForms.UWP/MessageContentRenderer.cs b/src/KokoroIO.XamarinForms.UWP/MessageContentRenderer.cs deleted file mode 100644 index 248e1fb..0000000 --- a/src/KokoroIO.XamarinForms.UWP/MessageContentRenderer.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.ComponentModel; -using KokoroIO.XamarinForms.UWP; -using KokoroIO.XamarinForms.ViewModels; -using KokoroIO.XamarinForms.Views; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Documents; -using Xamarin.Forms.Platform.UWP; - -[assembly: ExportRenderer(typeof(MessageContent), typeof(MessageContentRenderer))] - -namespace KokoroIO.XamarinForms.UWP -{ - public sealed class MessageContentRenderer : ViewRenderer - { - public MessageContentRenderer() - { - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - base.OnElementChanged(e); - - if (e.NewElement != null) - { - if (Control == null) - { - var rtb = new RichTextBlock(); - rtb.IsTextSelectionEnabled = false; - rtb.TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap; - ScrollViewer.SetHorizontalScrollBarVisibility(rtb, ScrollBarVisibility.Hidden); - ScrollViewer.SetHorizontalScrollMode(rtb, ScrollMode.Disabled); - ScrollViewer.SetVerticalScrollBarVisibility(rtb, ScrollBarVisibility.Hidden); - ScrollViewer.SetVerticalScrollMode(rtb, ScrollMode.Disabled); - - SetNativeControl(rtb); - } - UpdateBlocks(Control); - } - } - - protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize) - { - Control.MaxWidth = availableSize.Width; - return base.MeasureOverride(availableSize); - } - - protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == MessageContent.BlocksProperty.PropertyName) - { - UpdateBlocks(Control); - } - base.OnElementPropertyChanged(sender, e); - } - - protected override void Dispose(bool disposing) - { - if (_Blocks != null && _Blocks.TryGetTarget(out var v)) - { - v.CollectionChanged -= Blocks_CollectionChanged; - } - base.Dispose(disposing); - } - - private WeakReference _Blocks; - - private void UpdateBlocks(RichTextBlock rtb) - { - if (_Blocks != null && _Blocks.TryGetTarget(out var v)) - { - v.CollectionChanged -= Blocks_CollectionChanged; - } - - var bs = Element.Blocks; - - if (bs is INotifyCollectionChanged cc) - { - cc.CollectionChanged += Blocks_CollectionChanged; - _Blocks = new WeakReference(cc); - } - else - { - _Blocks = null; - } - - rtb.Blocks.Clear(); - - if (bs != null) - { - foreach (var b in bs) - { - if (b is MessageBlock mb) - { - var para = new Paragraph(); - - foreach (var s in mb.Spans) - { - para.Inlines.Add(Createinline(s)); - } - - rtb.Blocks.Add(para); - } - else if (b is ListMessageBlock lmb) - { - foreach (var li in lmb.Items) - { - var para = new Paragraph(); - - para.TextIndent = 20; - - para.Inlines.Add(new Run() { Text = "* " }); - - foreach (var s in li.Spans) - { - para.Inlines.Add(Createinline(s)); - } - - rtb.Blocks.Add(para); - } - } - else - { - var para = new Paragraph(); - - para.Inlines.Add(new Run() - { - Text = b.ToString() - }); - - rtb.Blocks.Add(para); - } - } - } - } - - private static Inline Createinline(MessageSpan s) - { - if (s.Text == Environment.NewLine) - { - return new LineBreak(); - } - else if (s.Type == MessageSpanType.Hyperlink) - { - var hl = new Hyperlink(); - hl.NavigateUri = s.Href != null ? new Uri(s.Href) : null; - hl.Inlines.Add(new Run() { Text = s.Text }); - return hl; - } - else - { - return new Run() { Text = s.Text }; - } - } - - private void Blocks_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - => UpdateBlocks(Control); - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms.UWP/MessageListViewRenderer.cs b/src/KokoroIO.XamarinForms.UWP/MessageListViewRenderer.cs deleted file mode 100644 index 50a0218..0000000 --- a/src/KokoroIO.XamarinForms.UWP/MessageListViewRenderer.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using KokoroIO.XamarinForms.UWP; -using KokoroIO.XamarinForms.Views; -using Windows.UI.Xaml.Automation.Peers; -using Windows.UI.Xaml.Controls; -using Xamarin.Forms.Platform.UWP; - -[assembly: ExportRenderer(typeof(MessageListView), typeof(MessageListViewRenderer))] - -namespace KokoroIO.XamarinForms.UWP -{ - public sealed class MessageListViewRenderer : ListViewRenderer - { - protected override void OnElementChanged(ElementChangedEventArgs e) - { - base.OnElementChanged(e); - - DisposeScrollViewer(); - - BindScollViewer(true); - } - - private void BindScollViewer(bool attachLoaded) - { - var sv = List == null ? null - : (FrameworkElementAutomationPeer.CreatePeerForElement(List) - ?.GetPattern(PatternInterface.Scroll) as ScrollViewerAutomationPeer)?.Owner - as ScrollViewer; - - if (sv != null) - { - sv.ViewChanged += ScrollViewer_ViewChanged; - _ScrollViewer = new WeakReference(sv); - } - else - { - _ScrollViewer = null; - - if (List != null) - { - List.Loaded += List_Loaded; - } - } - } - - private void List_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) - { - BindScollViewer(false); - ((ListView)sender).Loaded -= List_Loaded; - } - - protected override void Dispose(bool disposing) - { - DisposeScrollViewer(); - - base.Dispose(disposing); - } - - private void DisposeScrollViewer() - { - if (_ScrollViewer != null && _ScrollViewer.TryGetTarget(out var s)) - { - s.ViewChanged -= ScrollViewer_ViewChanged; - } - } - - private WeakReference _ScrollViewer; - private WeakReference _LastTop; - - private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) - { - if (e.IsIntermediate) - { - return; - } - - if (!Element.IsRefreshing && List.Items.Count > 0) - { - var sv = (ScrollViewer)sender; - if (_LastTop != null && _LastTop.TryGetTarget(out var lt)) - { - lt.StartBringIntoView(new Windows.UI.Xaml.BringIntoViewOptions() { AnimationDesired = false }); - _LastTop = null; - return; - } - - var item = List.ContainerFromIndex(0) as ListViewItem; - - var gt = item.TransformToVisual(sv); - var fp = gt.TransformPoint(new Windows.Foundation.Point(0, item.ActualHeight)); - if (fp.Y > 0) - { - _LastTop = new WeakReference(item); - ((MessageListView)Element)?.RefreshTopCommand?.Execute(null); - } - } - } - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/KokoroIO.XamarinForms.projitems b/src/KokoroIO.XamarinForms/KokoroIO.XamarinForms.projitems index 9ab6dd3..b1d6d65 100644 --- a/src/KokoroIO.XamarinForms/KokoroIO.XamarinForms.projitems +++ b/src/KokoroIO.XamarinForms/KokoroIO.XamarinForms.projitems @@ -29,22 +29,15 @@ - - - - - - AboutPage.xaml - - + MessagesPage.xaml Code diff --git a/src/KokoroIO.XamarinForms/ViewModels/ListMessageBlock.cs b/src/KokoroIO.XamarinForms/ViewModels/ListMessageBlock.cs deleted file mode 100644 index 14065d6..0000000 --- a/src/KokoroIO.XamarinForms/ViewModels/ListMessageBlock.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Xml.Linq; - -namespace KokoroIO.XamarinForms.ViewModels -{ - public sealed class ListMessageBlock : MessageBlockBase - { - internal ListMessageBlock(MessageInfo message, XElement element) - : base(message) - { - _Items = new List(); - - foreach (var li in element.Elements("li")) - { - var ivm = new MessageListItem(); - - ivm.Spans.AddRange(MessageSpan.EnumerateSpans(Message, li)); - - _Items.Add(ivm); - } - } - - private readonly List _Items; - - public List Items => _Items; - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/ViewModels/MessageBlock.cs b/src/KokoroIO.XamarinForms/ViewModels/MessageBlock.cs deleted file mode 100644 index 3256dc4..0000000 --- a/src/KokoroIO.XamarinForms/ViewModels/MessageBlock.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Xml.Linq; - -namespace KokoroIO.XamarinForms.ViewModels -{ - public sealed class MessageBlock : MessageBlockBase - { - internal MessageBlock(MessageInfo message) - : base(message) - { - } - - internal MessageBlock(MessageInfo message, XElement element) - : base(message) - { - _Spans.AddRange(MessageSpan.EnumerateSpans(Message, element)); - } - - private readonly List _Spans = new List(); - - public List Spans => _Spans; - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/ViewModels/MessageBlockBase.cs b/src/KokoroIO.XamarinForms/ViewModels/MessageBlockBase.cs deleted file mode 100644 index b009c73..0000000 --- a/src/KokoroIO.XamarinForms/ViewModels/MessageBlockBase.cs +++ /dev/null @@ -1,14 +0,0 @@ -using KokoroIO.XamarinForms.Helpers; - -namespace KokoroIO.XamarinForms.ViewModels -{ - public abstract class MessageBlockBase : ObservableObject - { - internal MessageBlockBase(MessageInfo message) - { - Message = message; - } - - internal MessageInfo Message { get; } - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/ViewModels/MessageInfo.cs b/src/KokoroIO.XamarinForms/ViewModels/MessageInfo.cs index c2dda90..9bcdc61 100644 --- a/src/KokoroIO.XamarinForms/ViewModels/MessageInfo.cs +++ b/src/KokoroIO.XamarinForms/ViewModels/MessageInfo.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.ObjectModel; -using System.IO; -using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.Linq; using KokoroIO.XamarinForms.Helpers; using Shipwreck.KokoroIO; @@ -18,8 +13,7 @@ internal MessageInfo(MessagesViewModel page, Message message) Profile = page.Application.GetProfile(message.Profile); PublishedAt = message.PublishedAt; - Blocks = new ObservableCollection(); - LoadBlocks(message); + Content = message.Content; } private MessagesViewModel Page { get; } @@ -48,66 +42,6 @@ internal void SetIsMerged(MessageInfo prev) #endregion IsMerged - public ObservableCollection Blocks { get; } - - private void LoadBlocks(Message model) - { - try - { - var html = model.Content.Replace("
", "
").Replace("\u0008", ""); - - using (var sr = new StringReader(html)) - using (var xr = XmlReader.Create(sr, new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment })) - { - while (xr.Read()) - { - if (xr.NodeType == XmlNodeType.Element && xr.Depth == 0) - { - using (var sxr = xr.ReadSubtree()) - { - var e = XElement.Load(sxr); - - if (Regex.IsMatch(e.Name.LocalName, "^[uo]l$", RegexOptions.IgnoreCase)) - { - Blocks.Add(new ListMessageBlock(this, e)); - } - else - { - Blocks.Add(new MessageBlock(this, e)); - } - } - } - } - } - } - catch - { - Blocks.Clear(); - - var ps = Regex.Split(model.RawContent, "(\\r|\\r?\\n){2,}"); - foreach (var p in ps) - { - if (!string.IsNullOrEmpty(p)) - { - var pvm = new MessageBlock(this); - using (var sr = new StringReader(p)) - { - for (var l = sr.ReadLine(); l != null; l = sr.ReadLine()) - { - if (pvm.Spans.Count > 0) - { - pvm.Spans.Add(new MessageSpan(this) { Text = Environment.NewLine }); - } - pvm.Spans.Add(new MessageSpan(this) - { - Text = l - }); - } - } - Blocks.Add(pvm); - } - } - } - } + public string Content { get; set; } } } \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/ViewModels/MessageListItem.cs b/src/KokoroIO.XamarinForms/ViewModels/MessageListItem.cs deleted file mode 100644 index 08d854e..0000000 --- a/src/KokoroIO.XamarinForms/ViewModels/MessageListItem.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using KokoroIO.XamarinForms.Helpers; - -namespace KokoroIO.XamarinForms.ViewModels -{ - public sealed class MessageListItem : ObservableObject - { - private readonly List _Spans = new List(); - - public List Spans => _Spans; - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/ViewModels/MessageSpan.cs b/src/KokoroIO.XamarinForms/ViewModels/MessageSpan.cs deleted file mode 100644 index 72c05c8..0000000 --- a/src/KokoroIO.XamarinForms/ViewModels/MessageSpan.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml; -using System.Xml.Linq; - -namespace KokoroIO.XamarinForms.ViewModels -{ - public sealed class MessageSpan - { - public MessageSpan(MessageInfo message) - { - Message = message; - } - - internal MessageInfo Message { get; } - - public MessageSpanType Type { get; set; } - - public string Text { get; set; } - public string Href { get; private set; } - - public static IEnumerable EnumerateSpans(MessageInfo message, XElement root) - { - foreach (var d in root.DescendantNodes()) - { - if (d.NodeType == XmlNodeType.Text) - { - var t = ((XText)d).Value; - - var xe = d.Parent as XElement; - - yield return new MessageSpan(message) - { - Text = t, - Href = xe.Attribute("href")?.Value, - Type = "a".Equals(xe?.Name?.LocalName) ? MessageSpanType.Hyperlink : MessageSpanType.Default - }; - } - else if (d.NodeType == XmlNodeType.Element) - { - if ("br".Equals((d as XElement)?.Name.LocalName)) - { - yield return new MessageSpan(message) - { - Text = Environment.NewLine, - }; - } - } - } - } - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/ViewModels/MessageSpanType.cs b/src/KokoroIO.XamarinForms/ViewModels/MessageSpanType.cs deleted file mode 100644 index 46851ee..0000000 --- a/src/KokoroIO.XamarinForms/ViewModels/MessageSpanType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace KokoroIO.XamarinForms.ViewModels -{ - public enum MessageSpanType - { - Default, - Hyperlink - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/Views/MessageContent.cs b/src/KokoroIO.XamarinForms/Views/MessageContent.cs deleted file mode 100644 index 834ef30..0000000 --- a/src/KokoroIO.XamarinForms/Views/MessageContent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using KokoroIO.XamarinForms.ViewModels; -using Xamarin.Forms; - -namespace KokoroIO.XamarinForms.Views -{ - public sealed class MessageContent : View - { - public static readonly BindableProperty BlocksProperty = BindableProperty.Create(nameof(Blocks), typeof(IEnumerable), typeof(MessageContent)); - - public IEnumerable Blocks - { - get => GetValue(BlocksProperty) as IEnumerable; - set => SetValue(BlocksProperty, value); - } - } -} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/Views/MessageListView.cs b/src/KokoroIO.XamarinForms/Views/MessageListView.cs deleted file mode 100644 index b313193..0000000 --- a/src/KokoroIO.XamarinForms/Views/MessageListView.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Input; -using Xamarin.Forms; - -namespace KokoroIO.XamarinForms.Views -{ - public class MessageListView : ListView - { - public static readonly BindableProperty RefreshTopCommandProperty = BindableProperty.Create(nameof(RefreshTopCommand), typeof(ICommand), typeof(MessageListView)); - - public ICommand RefreshTopCommand - { - get => (ICommand)GetValue(RefreshTopCommandProperty); - set => SetValue(RefreshTopCommandProperty, value); - } - } -} diff --git a/src/KokoroIO.XamarinForms/Views/MessageWebView.cs b/src/KokoroIO.XamarinForms/Views/MessageWebView.cs new file mode 100644 index 0000000..4dd471e --- /dev/null +++ b/src/KokoroIO.XamarinForms/Views/MessageWebView.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Xml; +using KokoroIO.XamarinForms.ViewModels; +using Xamarin.Forms; + +namespace KokoroIO.XamarinForms.Views +{ + public class MessageWebView : WebView + { + public static readonly BindableProperty MessagesProperty + = BindableProperty.Create(nameof(Messages), typeof(IEnumerable), typeof(MessageWebView), propertyChanged: MessagesChanged); + + public IEnumerable Messages + { + get { return (IEnumerable)GetValue(MessagesProperty); } + set { SetValue(MessagesProperty, value); } + } + + private static void MessagesChanged(BindableObject bindable, object oldValue, object newValue) + { + var mwv = (MessageWebView)bindable; + + { + if (oldValue is INotifyCollectionChanged cc) + { + cc.CollectionChanged -= mwv.Cc_CollectionChanged; + } + } + { + if (newValue is INotifyCollectionChanged cc) + { + cc.CollectionChanged += mwv.Cc_CollectionChanged; + } + } + mwv.RefreshMessages(); + } + + private void Cc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + RefreshMessages(); + } + + private void RefreshMessages() + { + string xml; + var replacements = new Dictionary(); + using (var sw = new StringWriter()) + using (var xw = XmlWriter.Create(sw)) + { + xw.WriteDocType("html", null, null, null); + + xw.WriteStartElement("html"); + xw.WriteStartElement("head"); + xw.WriteString(""); + xw.WriteEndElement(); + xw.WriteStartElement("body"); + + var ms = Messages; + + if (ms != null) + { + foreach (var m in ms) + { + xw.WriteStartElement("div"); + xw.WriteAttributeString("class", m.IsMerged ? "talk not-continued" : "talk continued"); + xw.WriteAttributeString("data-message-id", m.Id.ToString("D")); + { + xw.WriteStartElement("div"); + xw.WriteAttributeString("class", "avatar"); + { + xw.WriteStartElement("a"); + xw.WriteAttributeString("class", "img-rounded"); + + xw.WriteStartElement("img"); + xw.WriteAttributeString("src", m.Profile.Avatar); + + xw.WriteEndElement(); + xw.WriteEndElement(); + } + xw.WriteEndElement(); + + xw.WriteStartElement("div"); + xw.WriteAttributeString("class", "message"); + { + xw.WriteStartElement("div"); + xw.WriteAttributeString("class", "speaker"); + { + xw.WriteStartElement("a"); + xw.WriteString(m.Profile.DisplayName); + xw.WriteEndElement(); + + xw.WriteStartElement("small"); + xw.WriteAttributeString("class", "timeleft text-muted"); + xw.WriteString(m.PublishedAt.ToString("MM/dd HH:mm")); + xw.WriteEndElement(); + } + xw.WriteEndElement(); + + xw.WriteStartElement("div"); + xw.WriteAttributeString("class", "filtered_text"); + { + var cm = $""; + xw.WriteRaw(cm); + + replacements[cm] = m.Content; + } + xw.WriteEndElement(); + } + xw.WriteEndElement(); + } + xw.WriteEndElement(); + } + } + + xw.WriteEndElement(); + xw.WriteEndElement(); + + xw.Flush(); + + xml = sw.ToString(); + } + + foreach (var kv in replacements) + { + xml = xml.Replace(kv.Key, kv.Value); + } + + Source = new HtmlWebViewSource() + { + BaseUrl = "https://kokoro.io/", + Html = xml + }; + } + } +} \ No newline at end of file diff --git a/src/KokoroIO.XamarinForms/Views/MessagesPage.xaml b/src/KokoroIO.XamarinForms/Views/MessagesPage.xaml index df19250..a40f84f 100644 --- a/src/KokoroIO.XamarinForms/Views/MessagesPage.xaml +++ b/src/KokoroIO.XamarinForms/Views/MessagesPage.xaml @@ -6,78 +6,7 @@ x:Class="KokoroIO.XamarinForms.Views.MessagesPage" Title="{Binding Title}"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file