using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Avalonia.Svg.Skia; using Avalonia.Threading; using Comal.Classes; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using DialogHostAvalonia; using InABox.Avalonia; using InABox.Avalonia.Components; using InABox.Configuration; using InABox.Core; using PRS.Avalonia.Components; using PRS.Avalonia.Dialogs; namespace PRS.Avalonia; public abstract partial class ViewModelBase : ObservableValidator, IViewModelBase { private static DataAccessLayer? _dataAccessLayer; private static RepositoryLayer? _repositories; private static Dictionary? _databaseSettings; private static MobileDatabaseSettings? _currentDatabase; [ObservableProperty] private bool _backButtonVisible = true; private CancellationTokenSource _cts = new(); [ObservableProperty] private AvaloniaMenuItemCollection _primaryMenu = new(); [ObservableProperty] private bool _reverseTransition; [ObservableProperty] private AvaloniaMenuItemCollection _secondaryMenu = new(); [ObservableProperty] private bool _progressVisible = false; public static DataAccessLayer DataAccess { get { if (_dataAccessLayer == null) { _dataAccessLayer = new DataAccessLayer(); _dataAccessLayer.Connected += (s, e) => Connected(); _dataAccessLayer.Disconnected += (s, e) => Disconnected(); _dataAccessLayer.Validated += (s, e) => Validated(); } _dataAccessLayer ??= new DataAccessLayer(); return _dataAccessLayer; } } public static RepositoryLayer Repositories { get { _repositories ??= new RepositoryLayer(DataAccess); return _repositories; } } public static Dictionary DatabaseSettings { get { if (_databaseSettings == null) LoadDatabaseSettings(); return _databaseSettings; } } public static MobileDatabaseSettings CurrentDatabase { get { if (_currentDatabase == null) LoadDatabaseSettings(); return DatabaseSettings.Any(x => x.Value.IsDefault) ? DatabaseSettings.FirstOrDefault(x => x.Value.IsDefault).Value : DatabaseSettings.First().Value; } } public static string CurrentDatabaseName => DatabaseSettings.Any(x => x.Value.IsDefault) ? DatabaseSettings.FirstOrDefault(x => x.Value.IsDefault).Key : DatabaseSettings.First().Key; public static bool IsSharedDevice => string.IsNullOrWhiteSpace(CurrentDatabase.UserID) || string.IsNullOrWhiteSpace(CurrentDatabase.Password); private static void Connected() { } private static void Validated() { Repositories.MeModel.Refresh(true); } private static void Disconnected() { } public string DefaultCacheFileName(Guid? id = null, string? tag = null) where T : IShell { return string.IsNullOrWhiteSpace(tag) ? id == null ? $"{GetType().Name}.{typeof(T).Name}" : $"{GetType().Name}.{typeof(T).Name}.{id}" : id == null ? $"{GetType().Name}.{typeof(T).Name}-{tag}" : $"{GetType().Name}.{typeof(T).Name}-{tag}.{id}"; } [RelayCommand] private void BackButtonPressed() { if (OnBackButtonPressed()) Navigation.Back(); } public virtual bool OnBackButtonPressed() { return true; } public async Task Activate() { await OnActivated(); var token = _cts.Token; _ = Task.Run( async () => { var result = await Refresh(); while (result != TimeSpan.Zero) { if (token.IsCancellationRequested) break; await Task.Delay(result); if (!token.IsCancellationRequested) result = await Refresh(); } }, token ).ContinueWith(task => { if(task.Exception is not null) { App.HandleException(task.Exception); } }); } protected virtual Task OnActivated() { return Task.CompletedTask; } private async Task Refresh() { return await OnRefresh(); } /// /// Refresh the data on the screen. If this method returns a value other than , then that value is used to /// schedule the next refresh. /// /// Time until next refresh is triggered, or if periodic refreshing is unwanted. protected virtual Task OnRefresh() { return Task.FromResult(TimeSpan.FromSeconds(30)); } public async Task Deactivate() { await _cts.CancelAsync(); _cts.Dispose(); _cts = new CancellationTokenSource(); await OnDeactivated(); await Task.CompletedTask; } protected virtual Task OnDeactivated() { return Task.CompletedTask; } public static void SaveDatabaseSettings() { var config = new LocalConfiguration(); var old = config.LoadAll(); foreach (var key in old.Keys) if (!DatabaseSettings.ContainsKey(key)) new LocalConfiguration(key).Delete(); config.SaveAll(DatabaseSettings); } [MemberNotNull(nameof(_databaseSettings))] public static void LoadDatabaseSettings() { _databaseSettings = new LocalConfiguration().LoadAll(); // Contruct Defaults if required if (!_databaseSettings.Any()) { _currentDatabase = new MobileDatabaseSettings(); _currentDatabase.URLs = new[] { "demo.prsdigital.com.au:8033" }; _currentDatabase.UserID = "GUEST"; _currentDatabase.Password = "guest"; _currentDatabase.IsDefault = true; _currentDatabase.CacheID = Guid.NewGuid(); _databaseSettings["Demo Database"] = _currentDatabase; new LocalConfiguration().SaveAll(_databaseSettings); } // Retrieve the Default (or the first, if there is no default) _currentDatabase = _databaseSettings.Any(x => x.Value.IsDefault) ? _databaseSettings.FirstOrDefault(x => x.Value.IsDefault).Value : _databaseSettings.First().Value; if (_currentDatabase.CacheID == Guid.Empty) { _currentDatabase.CacheID = Guid.NewGuid(); new LocalConfiguration().SaveAll(_databaseSettings); } } } public abstract class PopupViewModel : ViewModelBase, IPopupViewModel { public bool IsClosed { get; private set; } public void Close() { IsClosed = true; DialogHost.GetDialogSession(null)?.Close(); } } public abstract class PopupViewModel : PopupViewModel, IPopupViewModel { private TResult? _result; public TResult? GetResult() { return _result ?? default; } public void Close(TResult result) { _result = result; Close(); } }