diff --git a/Common.Library/Common.Library.csproj b/Common.Library/Common.Library.csproj index d555782..77cc174 100644 --- a/Common.Library/Common.Library.csproj +++ b/Common.Library/Common.Library.csproj @@ -7,6 +7,7 @@ + diff --git a/Common.Library/Core/BaseViewModel.cs b/Common.Library/Core/BaseViewModel.cs new file mode 100644 index 0000000..5bef5b8 --- /dev/null +++ b/Common.Library/Core/BaseViewModel.cs @@ -0,0 +1,39 @@ +using CommunityToolkit.Maui.Alerts; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace GreadyPoang.Core; +public partial class BaseViewModel : ObservableObject +{ + [ObservableProperty] + private bool isBusy; + + protected async Task RunAsyncCommand(Func action, string loadingMessage = null, string errorMessage = "Ett fel inträffade") + { + if (IsBusy) return; + + try + { + IsBusy = true; + + if (!string.IsNullOrWhiteSpace(loadingMessage)) + await Snackbar.Make( + message: loadingMessage, + duration: TimeSpan.FromSeconds(2), + action: null).Show(); + + await action.Invoke(); + } + catch (Exception ex) + { + await Snackbar.Make( + message: $"{errorMessage}: {ex.Message}", + duration: TimeSpan.FromSeconds(3), + action: () => Console.WriteLine("Åtgärd vald")).Show(); + } + finally + { + IsBusy = false; + } + } +} + diff --git a/GreadyPoang.Services/Services/Implements/PopupEventHub.cs b/GreadyPoang.Services/Services/Implements/PopupEventHub.cs new file mode 100644 index 0000000..7a5683c --- /dev/null +++ b/GreadyPoang.Services/Services/Implements/PopupEventHub.cs @@ -0,0 +1,11 @@ +namespace GreadyPoang.Services; + +public class PopupEventHub : IPopupEventHub +{ + public event EventHandler? InfoPopupCloseRequested; + + public void RaiseInfoPopupClose() + { + InfoPopupCloseRequested?.Invoke(this, EventArgs.Empty); + } +} diff --git a/GreadyPoang.Services/Services/Interfaces/IPopupEventHub.cs b/GreadyPoang.Services/Services/Interfaces/IPopupEventHub.cs new file mode 100644 index 0000000..e9ab6a6 --- /dev/null +++ b/GreadyPoang.Services/Services/Interfaces/IPopupEventHub.cs @@ -0,0 +1,8 @@ +namespace GreadyPoang.Services; + +public interface IPopupEventHub +{ + event EventHandler? InfoPopupCloseRequested; + + void RaiseInfoPopupClose(); +} \ No newline at end of file diff --git a/GreadyPoang.ViewModelLayer/ViewModelClasses/InfoPopupViewModel.cs b/GreadyPoang.ViewModelLayer/ViewModelClasses/InfoPopupViewModel.cs new file mode 100644 index 0000000..d45e3d8 --- /dev/null +++ b/GreadyPoang.ViewModelLayer/ViewModelClasses/InfoPopupViewModel.cs @@ -0,0 +1,50 @@ +using CommunityToolkit.Maui; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using GreadyPoang.Services; + +namespace GreadyPoang.ViewModelLayer; + +public partial class InfoPopupViewModel : ObservableObject, IQueryAttributable +{ + private readonly IPopupService _popupService; + private readonly IPopupEventHub _popupEvent; + + public event EventHandler ClosePopupRequested; + + [ObservableProperty] + private string title; + + [ObservableProperty] + private string message; + + [ObservableProperty] + private string name; + public InfoPopupViewModel(IPopupService popupService, IPopupEventHub popupEvent) + { + _popupService = popupService; + _popupEvent = popupEvent; + } + + [RelayCommand] + private async Task Cancel() + { + //await _popupService.ClosePopupAsync(Shell.Current); + _popupEvent.RaiseInfoPopupClose(); + } + + [RelayCommand(CanExecute = nameof(CanSave))] + void OnSave() + { + } + + bool CanSave() => string.IsNullOrWhiteSpace(Name) is false; + + public void ApplyQueryAttributes(IDictionary query) + { + Title = (string)query[nameof(InfoPopupViewModel.Title)]; + Message = (string)query[nameof(InfoPopupViewModel.Message)]; + Name = (string)query[nameof(InfoPopupViewModel.Name)]; + } + +} diff --git a/GreadyPoang.ViewModelLayer/ViewModelClasses/ParticipantViewModel.cs b/GreadyPoang.ViewModelLayer/ViewModelClasses/ParticipantViewModel.cs index b3a5184..d49ab72 100644 --- a/GreadyPoang.ViewModelLayer/ViewModelClasses/ParticipantViewModel.cs +++ b/GreadyPoang.ViewModelLayer/ViewModelClasses/ParticipantViewModel.cs @@ -1,13 +1,16 @@ using Common.Library; +using CommunityToolkit.Maui; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using GreadyPoang.Core; using GreadyPoang.EntityLayer; +using GreadyPoang.Services; using System.Collections.ObjectModel; namespace GreadyPoang.ViewModelLayer; -public partial class ParticipantViewModel : ObservableObject +public partial class ParticipantViewModel : BaseViewModel { #region Constructors public ParticipantViewModel() : base() @@ -15,16 +18,29 @@ public partial class ParticipantViewModel : ObservableObject } - public ParticipantViewModel(IRepository repo, IMethodSharingService sharingService) : base() + public ParticipantViewModel( + IRepository repo, + IMethodSharingService sharingService, + IPopupService popupService, + IPopupEventHub popupEvent + //, + //InfoPopupViewModel infoPopupViewModel + ) : base() { _Repository = repo; _sharingService = sharingService; + _popupService = popupService; + _popupEvent = popupEvent; + //_infoPopupViewModel = infoPopupViewModel; ParticipantObject = new Participant(); ParticipantList = new ObservableCollection(); IsSaveCommandEnabled = true; + _popupEvent.InfoPopupCloseRequested += infoPopupViewModel_ClosePopupRequested; + PopupVisad = false; } - #endregion + + #endregion #region Private Variables [ObservableProperty] @@ -33,17 +49,40 @@ public partial class ParticipantViewModel : ObservableObject private ObservableCollection participantList; private readonly IRepository? _Repository; private readonly IMethodSharingService _sharingService; + private readonly IPopupService _popupService; + private readonly IPopupEventHub _popupEvent; + private readonly InfoPopupViewModel _infoPopupViewModel; + #endregion [ObservableProperty] private bool isSaveCommandEnabled; + public bool PopupVisad { get; set; } + #region Get Method public ObservableCollection Get() { ParticipantList = _sharingService.Get(); + + if (!PopupVisad) + { + var queryAttributes = new Dictionary + { + [nameof(InfoPopupViewModel.Title)] = "Deltagar bildens infopopup", + [nameof(InfoPopupViewModel.Message)] = "Deltagare laddade", + [nameof(InfoPopupViewModel.Name)] = "Urban", + + }; + + _popupService.ShowPopup( + Shell.Current, + options: PopupOptions.Empty, + shellParameters: queryAttributes); + } + return ParticipantList; } @@ -68,25 +107,47 @@ public partial class ParticipantViewModel : ObservableObject #endregion - [RelayCommand(CanExecute = nameof(IsSaveCommandEnabled))] - private async Task Save() + private async Task Save() { - if (_Repository == null || ParticipantObject == null) + await RunAsyncCommand(async () => { - return false; - } - var tmpTask = _Repository.Save(ParticipantObject); - int tmp = tmpTask.GetAwaiter().GetResult(); - if (tmp != -1) - { - ParticipantObject = new Participant(); - this.Get(); - await Shell.Current.GoToAsync(".."); - } - return tmp != -1; + if (_Repository == null || ParticipantObject == null) + { + return; + } + await Task.Delay(3600); // Simulerar en fördröjning för att visa laddningsindikatorn + var tmpTask = _Repository.Save(ParticipantObject); + int tmp = await tmpTask; + if (tmp != -1) + { + ParticipantObject = new Participant(); + this.Get(); + await Shell.Current.GoToAsync(".."); + } + }, loadingMessage: "Sparar deltagare...", errorMessage: "Fel vid sparande av deltagare"); } + + + //[RelayCommand(CanExecute = nameof(IsSaveCommandEnabled))] + //private async Task Save() + //{ + // if (_Repository == null || ParticipantObject == null) + // { + // return false; + // } + // var tmpTask = _Repository.Save(ParticipantObject); + // int tmp = tmpTask.GetAwaiter().GetResult(); + // if (tmp != -1) + // { + // ParticipantObject = new Participant(); + // this.Get(); + // await Shell.Current.GoToAsync(".."); + // } + // return tmp != -1; + //} + [RelayCommand] private void DeleteAsync(Participant pp) { @@ -99,4 +160,26 @@ public partial class ParticipantViewModel : ObservableObject this.Get(); Shell.Current.GoToAsync(".."); } -} \ No newline at end of file + + [RelayCommand] + private async Task LoadDataAsync() + { + await RunAsyncCommand(async () => + { + await Task.Delay(1500); // Simulerar laddning + Console.WriteLine("Data laddad!"); + }, loadingMessage: "Laddar data..."); + } + + //private void ClosePopup() + //{ + // _popupService.ClosePopupAsync(Shell.Current).GetAwaiter().GetResult(); + //} + + private async void infoPopupViewModel_ClosePopupRequested(object? sender, EventArgs e) + { + PopupVisad = true; + await _popupService.ClosePopupAsync(Shell.Current); + } + +} diff --git a/GreadyPoang/GreadyPoang.csproj b/GreadyPoang/GreadyPoang.csproj index 6fc9ac5..1360b86 100644 --- a/GreadyPoang/GreadyPoang.csproj +++ b/GreadyPoang/GreadyPoang.csproj @@ -60,6 +60,7 @@ + @@ -76,6 +77,9 @@ + + InfoPopup.xaml + ParticipantListView.xaml @@ -88,6 +92,9 @@ MSBuild:Compile + + MSBuild:Compile + MSBuild:Compile diff --git a/GreadyPoang/MauiProgram.cs b/GreadyPoang/MauiProgram.cs index f3df99b..ace904d 100644 --- a/GreadyPoang/MauiProgram.cs +++ b/GreadyPoang/MauiProgram.cs @@ -1,7 +1,9 @@ using Common.Library; +using CommunityToolkit.Maui; using GreadyPoang.DataLayer; using GreadyPoang.DataLayer.Database; using GreadyPoang.EntityLayer; +using GreadyPoang.Popups; using GreadyPoang.Services; using GreadyPoang.ViewModelLayer; using GreadyPoang.Views; @@ -18,6 +20,8 @@ public static class MauiProgram builder .UseMauiApp() + .UseMauiCommunityToolkit(options => + options.SetShouldEnableSnackbarOnWindows(true)) .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); @@ -52,6 +56,8 @@ public static class MauiProgram builder.Services.AddScoped, MethodSharingService>(); builder.Services.AddScoped(); builder.Services.AddSingleton(); + builder.Services.AddTransientPopup(); + builder.Services.AddSingleton(); #if DEBUG builder.Logging.AddDebug(); diff --git a/GreadyPoang/Popups/InfoPopup.xaml b/GreadyPoang/Popups/InfoPopup.xaml new file mode 100644 index 0000000..16fcddc --- /dev/null +++ b/GreadyPoang/Popups/InfoPopup.xaml @@ -0,0 +1,21 @@ + + + +