using System.Collections.ObjectModel; using System.Linq; using System.Windows.Threading; using ytLive.Helpers; namespace ytLive.ViewModels; public partial class MainViewModel { private const int VisibleLogEntryLimit = 500; private readonly ObservableCollection _currentLaunchLogEntries = new(); private readonly ObservableCollection _pinnedLogEntries = new(); private DispatcherTimer? _currentLaunchLogTimer; private long _lastCurrentLaunchLogSequence; private bool _isLogsTabSelected; public ObservableCollection CurrentLaunchLogEntries => _currentLaunchLogEntries; public ObservableCollection PinnedLogEntries => _pinnedLogEntries; public bool HasPinnedLogEntries => _pinnedLogEntries.Count > 0; public RelayCommand AcknowledgeLogEntryCommand => new(AcknowledgeLogEntry); public bool IsLiveChatTabSelected { get => !_isLogsTabSelected; set { if (value) SelectLogsTab(false); else if (!_isLogsTabSelected) OnPropertyChanged(nameof(IsLiveChatTabSelected)); } } public bool IsLogsTabSelected { get => _isLogsTabSelected; set { if (value) SelectLogsTab(true); else if (_isLogsTabSelected) OnPropertyChanged(nameof(IsLogsTabSelected)); } } private void InitializeCurrentLaunchLogs() { var entries = AppLog.SnapshotCurrentLaunch() .OrderByDescending(entry => entry.Sequence) .Take(VisibleLogEntryLimit) .ToArray(); foreach (var entry in entries) { if (entry.ErrorClass.HasValue) InsertPinnedLogEntry(entry); else _currentLaunchLogEntries.Add(entry); } _lastCurrentLaunchLogSequence = entries.FirstOrDefault()?.Sequence ?? 0; _currentLaunchLogTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) }; _currentLaunchLogTimer.Tick += (_, _) => RefreshCurrentLaunchLogs(); } private void SelectLogsTab(bool selected) { if (_isLogsTabSelected == selected) { OnPropertyChanged(nameof(IsLiveChatTabSelected)); OnPropertyChanged(nameof(IsLogsTabSelected)); return; } _isLogsTabSelected = selected; OnPropertyChanged(nameof(IsLiveChatTabSelected)); OnPropertyChanged(nameof(IsLogsTabSelected)); if (selected) { RefreshCurrentLaunchLogs(); _currentLaunchLogTimer?.Start(); } else { _currentLaunchLogTimer?.Stop(); } } internal void RefreshCurrentLaunchLogs() { var newEntries = AppLog.SnapshotCurrentLaunch() .Where(entry => entry.Sequence > _lastCurrentLaunchLogSequence) .OrderBy(entry => entry.Sequence) .ToArray(); foreach (var entry in newEntries) { if (entry.ErrorClass.HasValue) InsertPinnedLogEntry(entry); else InsertChronologicalLogEntry(entry); _lastCurrentLaunchLogSequence = entry.Sequence; } } private void InsertPinnedLogEntry(AppLogEntry entry) { var index = 0; while (index < _pinnedLogEntries.Count) { var current = _pinnedLogEntries[index]; var currentClass = (int)current.ErrorClass!.Value; var entryClass = (int)entry.ErrorClass!.Value; if (currentClass < entryClass || (currentClass == entryClass && current.Sequence > entry.Sequence)) index++; else break; } _pinnedLogEntries.Insert(index, entry); OnPropertyChanged(nameof(HasPinnedLogEntries)); } private void AcknowledgeLogEntry(AppLogEntry? entry) { if (entry?.ErrorClass == null || !_pinnedLogEntries.Remove(entry)) return; InsertChronologicalLogEntry(entry); OnPropertyChanged(nameof(HasPinnedLogEntries)); } private void InsertChronologicalLogEntry(AppLogEntry entry) { var index = 0; while (index < _currentLaunchLogEntries.Count && _currentLaunchLogEntries[index].Sequence > entry.Sequence) index++; _currentLaunchLogEntries.Insert(index, entry); if (_currentLaunchLogEntries.Count > VisibleLogEntryLimit) _currentLaunchLogEntries.RemoveAt(_currentLaunchLogEntries.Count - 1); } private void StopCurrentLaunchLogFeed() => _currentLaunchLogTimer?.Stop(); }