Skip to content

Instantly share code, notes, and snippets.

@INTERNALINTERFERENCE
Created December 14, 2022 16:59
Show Gist options
  • Save INTERNALINTERFERENCE/9a385e5b65321e8973971d8ea1c61a2d to your computer and use it in GitHub Desktop.
Save INTERNALINTERFERENCE/9a385e5b65321e8973971d8ea1c61a2d to your computer and use it in GitHub Desktop.
public class Trie : ViewModelBase
{
public Trie(
string part,
int level,
Trie? root = null,
Trie? parent = null )
{
Part = part;
Level = level;
Parent = parent;
Root = root ?? this;
MessagesCount = 1;
TopicsCount = 0;
History
.Connect()
.ObserveOn( RxApp.TaskpoolScheduler ) // to run on background thread
.Sort( SortExpressionComparer<ReceivedHistoryMessage>
.Descending( e => e.Id ) )
.ObserveOn( RxApp.MainThreadScheduler ) //this needed because UI updates need to run on the main
.Bind( out _uiHistoryMessages )
.DisposeMany()
.Subscribe();
Observable
.Interval( TimeSpan.FromSeconds( 1 ) )
.Subscribe( _ =>
{
Root.EnqueueUpdate();
} );
}
#region IO
public SourceList<ReceivedHistoryMessage> History { get; } = new();
private readonly ReadOnlyObservableCollection<ReceivedHistoryMessage> _uiHistoryMessages;
private readonly Dictionary<string, Trie> _trieChildren = new();
private AvaloniaList<Trie> _visibleChildren = new();
public IAvaloniaReadOnlyList<Trie> VisibleChildren
=> _visibleChildren;
public ReadOnlyObservableCollection<ReceivedHistoryMessage> UiHistoryMessages
=> _uiHistoryMessages;
[Reactive] private int TopicsCount { get; set; }
[Reactive] private int MessagesCount { get; set; }
[Reactive] public bool IsShowMessagesChecked { get; set; }
[Reactive] public string? Header { get; set; }
[Reactive] public string? Payload { get; set; }
[Reactive] public string? Topic { get; set; }
[Reactive] public MqttDelivery Delivery { get; set; } = new();
public string Part { get; }
public int Level { get; }
public Trie? Parent { get; }
private Trie Root { get; }
private bool _updateEnqueued;
private int _historyId;
private bool _isExpanded;
public bool IsExpanded
{
get => _isExpanded;
set
{
this.RaiseAndSetIfChanged( ref _isExpanded, value );
Root.EnqueueUpdate();
}
}
#endregion IO
public bool Add(
string[] topic,
int level,
MqttDelivery delivery )
{
var changedTopicCount = false;
if ( topic.IsNullOrEmpty() )
{
Delivery = delivery;
Topic = delivery.Topic;
Header = delivery.Header?.ToJsonString( true );
Payload = delivery.Payload?.ToJsonString( true );
TopicsCount = 1;
AddToHistory( delivery );
return false;
}
MessagesCount++;
if ( !_trieChildren.ContainsKey( topic[ 0 ] ) )
{
var node = new Trie( topic[ 0 ], level, Root, this );
_trieChildren.TryAdd( topic[ 0 ], node );
changedTopicCount = true;
}
if ( !_trieChildren[ topic[ 0 ] ]
.Add( topic.Skip( 1 ).ToArray(), level + 1, delivery )
&& !changedTopicCount )
return changedTopicCount;
changedTopicCount = true;
TopicsCount++;
return changedTopicCount;
}
public void EnqueueUpdate()
{
if ( _updateEnqueued ) return;
_updateEnqueued = true;
Dispatcher.UIThread.Post(
Update,
DispatcherPriority.Background );
}
private void AppendItems()
{
_updateEnqueued = false;
var flatTrieList = new AvaloniaList<Trie>();
AppendItems(
flatTrieList,
this );
_visibleChildren = flatTrieList;
}
private void AppendItems(
AvaloniaList<Trie> flatTrieList,
Trie node )
{
flatTrieList.Add( node );
if ( !node.IsExpanded
|| IsShowMessagesChecked ) return;
foreach ( var ch in node._trieChildren )
AppendItems( flatTrieList, ch.Value );
}
private void Update()
{
AppendItems();
Root.RaisePropertyChanged( nameof( Root.VisibleChildren ) );
}
public void ForceResync()
{
Root.Update();
}
private void AddToHistory( MqttMessage mqttMessage )
{
while ( History.Count >= 43 )
History.RemoveAt( History.Count - 1 );
History.Insert( 0, new ReceivedHistoryMessage
{
Id = _historyId++,
Time = DateTime.Now,
Message = mqttMessage
} );
}
}
@INTERNALINTERFERENCE
Copy link
Author

спасибо вам, получилось красиво

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment