diff --git a/.DS_Store b/.DS_Store index 9535946..3acaae0 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Presence.Desktop/App.axaml b/Presence.Desktop/App.axaml new file mode 100644 index 0000000..92a16bc --- /dev/null +++ b/Presence.Desktop/App.axaml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/Presence.Desktop/App.axaml.cs b/Presence.Desktop/App.axaml.cs new file mode 100644 index 0000000..0f4bce1 --- /dev/null +++ b/Presence.Desktop/App.axaml.cs @@ -0,0 +1,37 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Microsoft.Extensions.DependencyInjection; +using Presence.Desktop.DI; +using Presence.Desktop.ViewModels; +using Presence.Desktop.Views; + +namespace Presence.Desktop +{ + public partial class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddCommonService(); + var services = serviceCollection.BuildServiceProvider(); + var mainViewModel = services.GetRequiredService(); + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow() + { + DataContext = new MainWindowViewModel(services), + }; + } + + base.OnFrameworkInitializationCompleted(); + } + + } +} \ No newline at end of file diff --git a/Presence.Desktop/Assets/avalonia-logo.ico b/Presence.Desktop/Assets/avalonia-logo.ico new file mode 100644 index 0000000..da8d49f Binary files /dev/null and b/Presence.Desktop/Assets/avalonia-logo.ico differ diff --git a/Presence.Desktop/DI/ServiceColletionExtensions.cs b/Presence.Desktop/DI/ServiceColletionExtensions.cs new file mode 100644 index 0000000..195bfff --- /dev/null +++ b/Presence.Desktop/DI/ServiceColletionExtensions.cs @@ -0,0 +1,29 @@ +using Demo.Data.RemoteData.RemoteDataBase; +using Demo.Data.Repository; +using Demo.Domain.UseCase; +using Microsoft.Extensions.DependencyInjection; +using Presence.Desktop.ViewModels; +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Concurrency; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + + namespace Presence.Desktop.DI +{ + public static class ServiceColletionExtensions + { + public static void AddCommonService(this IServiceCollection collection) { + collection + .AddDbContext() + .AddSingleton() + .AddSingleton() + .AddTransient() + .AddTransient() + .AddTransient(); + } + } +} \ No newline at end of file diff --git a/Presence.Desktop/Models/GroupPresenter.cs b/Presence.Desktop/Models/GroupPresenter.cs new file mode 100644 index 0000000..af7f88e --- /dev/null +++ b/Presence.Desktop/Models/GroupPresenter.cs @@ -0,0 +1,17 @@ + using Avalonia.Controls; +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + namespace Presence.Desktop.Models +{ + public class GroupPresenter + { + public int Id { get; set; } + public string Name { get; set; } + public IEnumerable? users { get; set; } = null; + } +} \ No newline at end of file diff --git a/Presence.Desktop/Models/PresencePresenter.cs b/Presence.Desktop/Models/PresencePresenter.cs new file mode 100644 index 0000000..77dcf55 --- /dev/null +++ b/Presence.Desktop/Models/PresencePresenter.cs @@ -0,0 +1,19 @@ +using Avalonia.Controls; +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + namespace Presence.Desktop.Models +{ + public class PresencePresenter + { + public int UserGuid { get; set; } + public bool IsAttedance {get; set; } + public DateOnly Date {get; set; } + public int LessonNumber {get; set; } + public UserPresenter user { get; set; } + } +} \ No newline at end of file diff --git a/Presence.Desktop/Models/UserPresenter.cs b/Presence.Desktop/Models/UserPresenter.cs new file mode 100644 index 0000000..d99854c --- /dev/null +++ b/Presence.Desktop/Models/UserPresenter.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + namespace Presence.Desktop.Models +{ + public class UserPresenter + { + public Guid Guid { get; set; } + public string Name { get; set; } + public GroupPresenter Group { get; set; } + } +} \ No newline at end of file diff --git a/Presence.Desktop/Presence.Desktop.csproj b/Presence.Desktop/Presence.Desktop.csproj new file mode 100644 index 0000000..ef51aab --- /dev/null +++ b/Presence.Desktop/Presence.Desktop.csproj @@ -0,0 +1,29 @@ + + + WinExe + net8.0 + enable + true + app.manifest + true + + + + + + + + + + + None + All + + + + + + + + + diff --git a/Presence.Desktop/Program.cs b/Presence.Desktop/Program.cs new file mode 100644 index 0000000..3851175 --- /dev/null +++ b/Presence.Desktop/Program.cs @@ -0,0 +1,24 @@ +using Avalonia; +using Avalonia.ReactiveUI; +using System; + +namespace Presence.Desktop +{ + internal sealed class Program + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace() + .UseReactiveUI(); + } +} \ No newline at end of file diff --git a/Presence.Desktop/ViewLocator.cs b/Presence.Desktop/ViewLocator.cs new file mode 100644 index 0000000..6e218c4 --- /dev/null +++ b/Presence.Desktop/ViewLocator.cs @@ -0,0 +1,19 @@ +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Presence.Desktop.ViewModels; +using System; +using Presence.Desktop.Views; +using ReactiveUI; + +namespace Presence.Desktop +{ + public class ViewLocator : IViewLocator + { + public IViewFor? ResolveView(T? viewModel, string? contract = null) => viewModel switch + { + GroupViewModel groupViewModel => new GroupView{DataContext = groupViewModel}, + PresenceViewModel presenceViewModel => new PresenceView{DataContext = presenceViewModel}, + _ => throw new ArgumentOutOfRangeException(nameof(viewModel)) + }; + } +} diff --git a/Presence.Desktop/ViewModels/GroupViewModel.cs b/Presence.Desktop/ViewModels/GroupViewModel.cs new file mode 100644 index 0000000..f5dbf04 --- /dev/null +++ b/Presence.Desktop/ViewModels/GroupViewModel.cs @@ -0,0 +1,92 @@ +using Demo.Domain.UseCase; +using DynamicData; +using DynamicData.Binding; +using Presence.Desktop.Models; +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; +using Tmds.DBus.Protocol; + +namespace Presence.Desktop.ViewModels +{ + public class GroupViewModel : ViewModelBase, IRoutableViewModel + { + private readonly List _groupPresentersDataSource = new List(); + private ObservableCollection _groups; + public ObservableCollection Groups => _groups; + private GroupPresenter? _selectedGroupItem; + + public ReactiveCommand ButtonRemoveUsersByGroup {get; } + // public ReactiveCommand ButtonAddUser { get; } + + public GroupPresenter? SelectedGroupItem + { + get => _selectedGroupItem; + set => this.RaiseAndSetIfChanged(ref _selectedGroupItem, value); + } + + + public ObservableCollection Users { get => _users;} + public ObservableCollection _users; + public GroupViewModel(IGroupUseCase groupUseCase, IUserUseCase userUseCase) + { + foreach (var item in groupUseCase.GetAllGroupsWithUsers()) + { + GroupPresenter groupPresenter = new GroupPresenter + { + Id = item.ID, + Name = item.Name, + users = item.Users?.Select(user => new UserPresenter + { + Name = user.FIO, + Guid = user.Guid, + Group = new GroupPresenter { Id = item.ID, Name = item.Name } + } + ).ToList() + }; + _groupPresentersDataSource.Add(groupPresenter); + } + + _groups = new ObservableCollection(_groupPresentersDataSource); + + _users = new ObservableCollection(); + + this.WhenAnyValue(vm => vm.SelectedGroupItem) + .Subscribe(_ => SetUsers()); + + ButtonRemoveUsersByGroup = ReactiveCommand.Create(() => RemoveUsersByGroup(groupUseCase)); + } + + private void SetUsers() + { + if(SelectedGroupItem == null) return; + if (SelectedGroupItem.users == null) return; + Users.Clear(); + foreach (var item in SelectedGroupItem.users) + { + Users.Add(item); + } + } + + private void RemoveUsersByGroup(IGroupUseCase groupUseCase) + { + if (_selectedGroupItem != null){ + groupUseCase.RemoveUsersByGroup(_selectedGroupItem.Id); + } + + var usersToRemove = Users.Where(user => user.Group.Id == _selectedGroupItem.Id).ToList(); + foreach (var user in usersToRemove) + { + Users.Remove(user); + } + } + + public string? UrlPathSegment { get; } + public IScreen HostScreen { get; } + } +} + diff --git a/Presence.Desktop/ViewModels/MainWindowViewModels.cs b/Presence.Desktop/ViewModels/MainWindowViewModels.cs new file mode 100644 index 0000000..a4640b4 --- /dev/null +++ b/Presence.Desktop/ViewModels/MainWindowViewModels.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using ReactiveUI; + +namespace Presence.Desktop.ViewModels; + +public class MainWindowViewModel: ViewModelBase, IScreen +{ + public RoutingState Router { get; } = new RoutingState(); + + public MainWindowViewModel(IServiceProvider serviceProvider) + { + var groupViewModel = serviceProvider.GetRequiredService(); + Router.Navigate.Execute(groupViewModel); + } +} \ No newline at end of file diff --git a/Presence.Desktop/ViewModels/PresenceViewModel.cs b/Presence.Desktop/ViewModels/PresenceViewModel.cs new file mode 100644 index 0000000..d492c79 --- /dev/null +++ b/Presence.Desktop/ViewModels/PresenceViewModel.cs @@ -0,0 +1,11 @@ +using ReactiveUI; + +namespace Presence.Desktop.ViewModels; + +public class PresenceViewModel: ViewModelBase, IRoutableViewModel +{ + public string? UrlPathSegment { get; } + public IScreen HostScreen { get; } +} + + \ No newline at end of file diff --git a/Presence.Desktop/ViewModels/ViewModelBase.cs b/Presence.Desktop/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..e708d0d --- /dev/null +++ b/Presence.Desktop/ViewModels/ViewModelBase.cs @@ -0,0 +1,8 @@ +using ReactiveUI; + +namespace Presence.Desktop.ViewModels +{ + public class ViewModelBase : ReactiveObject + { + } +} \ No newline at end of file diff --git a/Presence.Desktop/Views/GroupView.axaml b/Presence.Desktop/Views/GroupView.axaml new file mode 100644 index 0000000..44c2d7d --- /dev/null +++ b/Presence.Desktop/Views/GroupView.axaml @@ -0,0 +1,56 @@ + + + + + + + + + + +