using Avalonia; using Avalonia.Controls; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using EventBus; using Mono.CompilerServices.SymbolWriter; using Shaker.Models; using SukiUI.Dialogs; using SukiUI.Toasts; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Windows.Input; namespace ShakerApp.ViewModels; public abstract class ViewModelBase : ObservableObject where TModel : IModel { private string Caption => (string)(App.Current?.FindResource("PromptTitle") ?? ""); private string Yes => (string)(App.Current?.FindResource("PromptYes") ?? ""); private string No => (string)(App.Current?.FindResource("PromptNo") ?? ""); public virtual double Width => double.NaN; public virtual double Height => double.NaN; public virtual bool CanResize => true; private List AllFields = new List(); private List<(string,IReadOnlyList)> AllProperties = new List<(string, IReadOnlyList)>(); [AllowNull] public Action CloseWindowAction { get; set; } public ISukiToastManager ToastManager { get; } = new SukiToastManager(); public ISukiDialogManager DialogManager { get; } = new SukiDialogManager(); [AllowNull] public virtual Type Content { get => content; set => SetProperty(ref content , value); } private string title = string.Empty; private bool saveIsEnabled= false; public bool SaveIsEnabled { get { return saveIsEnabled; } set {SetProperty(ref saveIsEnabled , value); } } [AllowNull] public virtual bool CanCancel { get; } = typeof(TModel).IsAnsiClass && !typeof(TModel).IsAbstract; public ViewModelBase() { if (typeof(TModel).IsAnsiClass && !typeof(TModel).IsAbstract) { Model = Activator.CreateInstance(); AllFields = typeof(TModel).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList(); this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(x => x.GetCustomAttribute() != null) .ToList() .ForEach(x => { var att = x.GetCustomAttribute(); if (att == null || att.Names.Count ==0) return; AllProperties.Add((x.Name, att.Names)); }); } } public bool ShowError(string msg) { return Tools.DispatherInovke.Inovke(()=> DialogManager.CreateDialog() .OfType(Avalonia.Controls.Notifications.NotificationType.Error) .WithTitle(Caption) .WithContent(msg) .WithActionButton (Yes, _ => { }, true).TryShow()); } public bool ShowAsk(string msg, Action? yesaction = null, Action? noaction = null) { return Tools.DispatherInovke.Inovke(()=> DialogManager.CreateDialog() .OfType(Avalonia.Controls.Notifications.NotificationType.Information) .WithTitle(Caption) .WithContent(msg) .WithActionButton(Yes, _ => yesaction?.Invoke(), true) .WithActionButton(No, _ => noaction?.Invoke(), true) .TryShow()); } public bool ShowInfo(string msg) { return Tools.DispatherInovke.Inovke(()=> DialogManager.CreateDialog() .OfType(Avalonia.Controls.Notifications.NotificationType.Information) .WithTitle(Caption) .WithContent(msg) .WithActionButton (Yes, _ => { }, true).TryShow()); } public bool ShowSuccess(string msg) { return Tools.DispatherInovke.Inovke(()=> DialogManager.CreateDialog() .OfType(Avalonia.Controls.Notifications.NotificationType.Success) .WithTitle(Caption) .WithContent(msg) .WithActionButton (Yes, _ => { }, true).TryShow()); } public bool ShowWarning(string msg) { return Tools.DispatherInovke.Inovke(()=> DialogManager.CreateDialog() .OfType(Avalonia.Controls.Notifications.NotificationType.Warning) .WithTitle(Caption) .WithContent(msg) .WithActionButton (Yes, _ => { }, true).TryShow()); } public void ShowToast(string msg,Avalonia.Controls.Notifications.NotificationType type = Avalonia.Controls.Notifications.NotificationType.Information) { if (ToastManager == null) return; Tools.DispatherInovke.Inovke(()=> ToastManager.CreateToast() .WithTitle(Caption) .WithContent(msg) .OfType(type) .Dismiss().After(TimeSpan.FromSeconds(3)) .Dismiss().ByClicking() .Queue()); } public ViewModelBase(TModel model):this() { UpDateModel(model); } public virtual void ReceiveServiceModel(TModel model) { if (typeof(TModel).IsAbstract || typeof(TModel).IsInterface) return; if(lastModel!=null) { lastModel = (TModel)model.Clone(); } UpDateModel(model); } public virtual void UpDateModel(TModel model) { if (typeof(TModel).IsAbstract || typeof(TModel).IsInterface) return; List changedNames = new List(); if (model == null || AllFields.Count==0) return; if (Model == null) { changedNames = AllFields.Select(x => x.Name).ToList(); } else { AllFields.ForEach(x => { var lastvalue = x.GetValue(Model); var fieldvalue = x.GetValue(model); if (!Object.Equals(lastvalue, fieldvalue)) { changedNames.Add(x.Name); } }); } Model = model; if (changedNames.Count == 0) return; List nochanged = new List(); changedNames.ForEach(x => { bool state = false; AllProperties.ForEach(y => { if(y.Item2.Contains(x)) { OnPropertyChanged(y.Item1); state = true; } }); if (!state) nochanged.Add(x); }); if (nochanged.Count == 0) return; RefreshUI(nochanged); } public virtual void Init() { } protected virtual void RefreshUI(List changedNames) { } private bool cansave = false; public virtual string OKContent => "Save"; public virtual string CancelContent =>"Cancel"; [AllowNull] private TModel model = default; public virtual TModel Model { get => model; set => SetProperty(ref model, value); } [return: NotNull] protected EventBus.EventBroker.EventData GetEvent() => (EventBroker.EventData)EventBroker.Instance.GetEvent(); [return: NotNull] protected EventBus.EventBroker.EventData GetEvent() => (EventBroker.EventData)EventBroker.Instance.GetEvent(); [return: NotNull] public EventBus.EventBroker.AnonymousEventData GetEvent([NotNull] string eventName) => (EventBroker.AnonymousEventData)EventBroker.Instance.GetEvent(eventName); [return: NotNull] public EventBus.EventBroker.AnonymousEventData GetEvent([NotNull] string eventName) => (EventBroker.AnonymousEventData)EventBroker.Instance.GetEvent(eventName); public ICommand SaveCommand => new RelayCommand(()=> { if (!cansave) return; Save(); cansave = false; }); public ICommand CancelCommand => new RelayCommand(Cancel); public virtual string Title { get => title; set =>SetProperty(ref title , value); } public bool ButtonVisibily { get => buttonVisibily; set =>SetProperty(ref buttonVisibily , value); } protected virtual void Save() { lastModel = default; } [AllowNull] protected TModel lastModel; [AllowNull] private Type content; public virtual void InitData() { cansave = true; if (CanCancel) { lastModel = (TModel)Model.Clone(); SaveIsEnabled = false; } else { //lastModel = default; } } protected virtual bool SkipProperty(string? propertyName) { return false; } protected override void OnPropertyChanged(PropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.PropertyName == nameof(Content) || e.PropertyName == nameof(Model) || e.PropertyName == nameof(ButtonVisibily) || e.PropertyName == nameof(SaveCommand) || e.PropertyName == nameof(Title) || e.PropertyName == nameof(SaveIsEnabled) || e.PropertyName == nameof(CancelCommand)) return; if (SkipProperty(e.PropertyName)) return; SaveIsEnabled = true; } private bool buttonVisibily = true; protected virtual void Cancel() { if (CanCancel && lastModel !=null) { UpDateModel(lastModel); lastModel = default; } } }