diff --git a/DI/Dependencies.cs b/DI/Dependencies.cs index 54ae09a..88a34b5 100644 --- a/DI/Dependencies.cs +++ b/DI/Dependencies.cs @@ -5,9 +5,10 @@ namespace DI { public static class Dependencies { - public static void RegisterModules(this ContainerBuilder builder) + public static ContainerBuilder RegisterModules(this ContainerBuilder builder) { builder.RegisterInfrastructureModule(); + return builder; } } } \ No newline at end of file diff --git a/SteamAccountManager.Application/Common/Observable/BaseObservable.cs b/SteamAccountManager.Application/Common/Observable/BaseObservable.cs deleted file mode 100644 index 1be63ad..0000000 --- a/SteamAccountManager.Application/Common/Observable/BaseObservable.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace SteamAccountManager.Application.Common.Observable -{ - public abstract class BaseObservable : IObserveable - { - private List> _observers { get; set; } = new(); - - public void Notify(T? value) - { - _observers.ForEach(o => o(value)); - } - - public IDisposable Subscribe(Action observer) - { - _observers.Add(observer); - return new Unsubscriber(_observers, observer); - } - } -} diff --git a/SteamAccountManager.Application/Common/Observable/IObserveable.cs b/SteamAccountManager.Application/Common/Observable/IObserveable.cs deleted file mode 100644 index e795372..0000000 --- a/SteamAccountManager.Application/Common/Observable/IObserveable.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace SteamAccountManager.Application.Common.Observable -{ - public interface IObserveable - { - public IDisposable Subscribe(Action observeable); - public void Notify(T? value); - } -} diff --git a/SteamAccountManager.Application/Common/Observable/Unsubscriber.cs b/SteamAccountManager.Application/Common/Observable/Unsubscriber.cs deleted file mode 100644 index ffb2fed..0000000 --- a/SteamAccountManager.Application/Common/Observable/Unsubscriber.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace SteamAccountManager.Application.Common.Observable -{ - public class Unsubscriber : IDisposable - { - private readonly List> _observers; - private readonly Action _observer; - - public Unsubscriber(List> observers, Action observer) - { - _observers = observers; - _observer = observer; - } - - public void Dispose() - { - _observers.Remove(_observer); - } - } -} diff --git a/SteamAccountManager.Application/Steam/Observables/IAccountStorageObservable.cs b/SteamAccountManager.Application/Steam/Observables/IAccountStorageObservable.cs deleted file mode 100644 index 4acdfbc..0000000 --- a/SteamAccountManager.Application/Steam/Observables/IAccountStorageObservable.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SteamAccountManager.Application.Common.Observable; -using SteamAccountManager.Domain.Steam.Model; - -namespace SteamAccountManager.Application.Steam.Observables -{ - public interface IAccountStorageObservable : IObserveable?> - { - } -} diff --git a/SteamAccountManager.Application/SteamAccountManager.Application.csproj b/SteamAccountManager.Application/SteamAccountManager.Application.csproj deleted file mode 100644 index e4045ee..0000000 --- a/SteamAccountManager.Application/SteamAccountManager.Application.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net6.0 - enable - enable - - - - - - - - - - - - - - - - - diff --git a/SteamAccountManager.AvaloniaUI/DemoMock/GetAccountWithDetailsUseCaseMock.cs b/SteamAccountManager.AvaloniaUI/DemoMock/GetAccountWithDetailsUseCaseMock.cs index a04f234..d796edb 100644 --- a/SteamAccountManager.AvaloniaUI/DemoMock/GetAccountWithDetailsUseCaseMock.cs +++ b/SteamAccountManager.AvaloniaUI/DemoMock/GetAccountWithDetailsUseCaseMock.cs @@ -1,8 +1,8 @@ -using SteamAccountManager.Application.Steam.UseCase; -using SteamAccountManager.Domain.Steam.Model; +using SteamAccountManager.Domain.Steam.Model; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; +using SteamAccountManager.Domain.Steam.UseCase; namespace SteamAccountManager.AvaloniaUI.DemoMock { diff --git a/SteamAccountManager.AvaloniaUI/Dependencies.cs b/SteamAccountManager.AvaloniaUI/Dependencies.cs index 887f239..05b1504 100644 --- a/SteamAccountManager.AvaloniaUI/Dependencies.cs +++ b/SteamAccountManager.AvaloniaUI/Dependencies.cs @@ -1,12 +1,12 @@ using Autofac; -using Autofac.Core; using DI; using ReactiveUI; -using SteamAccountManager.Application.Steam.Service; using SteamAccountManager.AvaloniaUI.Mappers; using SteamAccountManager.AvaloniaUI.Notifications; using SteamAccountManager.AvaloniaUI.Services; using SteamAccountManager.AvaloniaUI.ViewModels; +using SteamAccountManager.Domain.Steam.Observables; +using SteamAccountManager.Domain.Steam.Service; namespace SteamAccountManager.AvaloniaUI { @@ -16,15 +16,21 @@ internal static class Dependencies public static void RegisterDependencies() { - ContainerBuilder builder = new(); - builder.RegisterModules(); - builder.RegisterAvaloniaModule(); - builder.RegisterViewModels(); + Container = new ContainerBuilder() + .RegisterModules() + .RegisterAvaloniaModule() + .RegisterViewModels() + .Build() + .StartWatchers(); + } - Container = builder.Build(); + public static IContainer StartWatchers(this IContainer container) + { + container.Resolve().Start(); + return container; } - public static void RegisterAvaloniaModule(this ContainerBuilder builder) + public static ContainerBuilder RegisterAvaloniaModule(this ContainerBuilder builder) { builder.RegisterType().SingleInstance(); builder.RegisterType().SingleInstance(); @@ -33,19 +39,25 @@ public static void RegisterAvaloniaModule(this ContainerBuilder builder) #else builder.RegisterType().As().SingleInstance(); #endif + + return builder; } - public static void RegisterViewModels(this ContainerBuilder builder) + public static ContainerBuilder RegisterViewModels(this ContainerBuilder builder) { - builder.RegisterViewModel(); builder.RegisterViewModel(); + + return builder; } - private static void RegisterViewModel(this ContainerBuilder builder) where ViewModel : RoutableViewModel + private static ContainerBuilder RegisterViewModel(this ContainerBuilder builder) + where ViewModel : RoutableViewModel { builder.RegisterType() .WithParameter(new TypedParameter(typeof(IScreen), "screen")); + + return builder; } } -} +} \ No newline at end of file diff --git a/SteamAccountManager.AvaloniaUI/Models/Account.cs b/SteamAccountManager.AvaloniaUI/Models/Account.cs index 32c8dd3..58d1995 100644 --- a/SteamAccountManager.AvaloniaUI/Models/Account.cs +++ b/SteamAccountManager.AvaloniaUI/Models/Account.cs @@ -1,11 +1,9 @@ -using Avalonia.Media.Imaging; -using System; -using System.ComponentModel; -using System.Runtime.CompilerServices; +using System; +using Avalonia.Media.Imaging; namespace SteamAccountManager.AvaloniaUI.Models { - public class Account : INotifyPropertyChanged + public class Account { public IBitmap? ProfilePicture { get; set; } public Uri? ProfilePictureUrl { get; set; } @@ -16,29 +14,15 @@ public class Account : INotifyPropertyChanged public bool IsVacBanned { get; set; } public bool IsCommunityBanned { get; set; } public string LastLogin { get; set; } = string.Empty; - public Rank Rank { get; set; } = new Rank() + + public Rank Rank { get; set; } = new() { Level = -1 }; + public bool ShowLevel { get { return Rank.Level >= 0; } } - - -#pragma warning disable CS8612 // Die NULL-Zulässigkeit von Verweistypen im Typ entspricht nicht dem implizit implementierten Member. - public event PropertyChangedEventHandler PropertyChanged; -#pragma warning restore CS8612 // Die NULL-Zulässigkeit von Verweistypen im Typ entspricht nicht dem implizit implementierten Member. - - // This method is called by the Set accessor of each property. - // The CallerMemberName attribute that is applied to the optional propertyName - // parameter causes the property name of the caller to be substituted as an argument. - private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } } -} +} \ No newline at end of file diff --git a/SteamAccountManager.AvaloniaUI/Notifications/LegacyWindowsLocalNotificationService.cs b/SteamAccountManager.AvaloniaUI/Notifications/LegacyWindowsLocalNotificationService.cs index de330e7..dd8202b 100644 --- a/SteamAccountManager.AvaloniaUI/Notifications/LegacyWindowsLocalNotificationService.cs +++ b/SteamAccountManager.AvaloniaUI/Notifications/LegacyWindowsLocalNotificationService.cs @@ -1,4 +1,4 @@ -using SteamAccountManager.Application.Steam.Service; +using SteamAccountManager.Domain.Steam.Service; namespace SteamAccountManager.AvaloniaUI.Notifications { diff --git a/SteamAccountManager.AvaloniaUI/Notifications/WindowsLocalNotificationService.cs b/SteamAccountManager.AvaloniaUI/Notifications/WindowsLocalNotificationService.cs index d6040d1..298df34 100644 --- a/SteamAccountManager.AvaloniaUI/Notifications/WindowsLocalNotificationService.cs +++ b/SteamAccountManager.AvaloniaUI/Notifications/WindowsLocalNotificationService.cs @@ -1,6 +1,6 @@ #if WINDOWS10_0_17763_0_OR_GREATER using Microsoft.Toolkit.Uwp.Notifications; -using SteamAccountManager.Application.Steam.Service; +using SteamAccountManager.Domain.Steam.Service; namespace SteamAccountManager.AvaloniaUI.Notifications { diff --git a/SteamAccountManager.AvaloniaUI/Services/AvatarService.cs b/SteamAccountManager.AvaloniaUI/Services/AvatarService.cs index 1a18e49..6c56563 100644 --- a/SteamAccountManager.AvaloniaUI/Services/AvatarService.cs +++ b/SteamAccountManager.AvaloniaUI/Services/AvatarService.cs @@ -1,10 +1,10 @@ using Avalonia; using Avalonia.Media.Imaging; using Avalonia.Platform; -using SteamAccountManager.Application.Steam.Service; using System; using System.IO; using System.Threading.Tasks; +using SteamAccountManager.Domain.Steam.Service; namespace SteamAccountManager.AvaloniaUI.Services { diff --git a/SteamAccountManager.AvaloniaUI/SteamAccountManager.AvaloniaUI.csproj b/SteamAccountManager.AvaloniaUI/SteamAccountManager.AvaloniaUI.csproj index dc00c90..8d84755 100644 --- a/SteamAccountManager.AvaloniaUI/SteamAccountManager.AvaloniaUI.csproj +++ b/SteamAccountManager.AvaloniaUI/SteamAccountManager.AvaloniaUI.csproj @@ -45,7 +45,6 @@ - diff --git a/SteamAccountManager.AvaloniaUI/SteamAccountSwitcherStyles.xaml b/SteamAccountManager.AvaloniaUI/SteamAccountSwitcherStyles.xaml index de89a3b..e64520e 100644 --- a/SteamAccountManager.AvaloniaUI/SteamAccountSwitcherStyles.xaml +++ b/SteamAccountManager.AvaloniaUI/SteamAccountSwitcherStyles.xaml @@ -1,35 +1,41 @@  - + - - + + - - - + + + + + \ No newline at end of file diff --git a/SteamAccountManager.AvaloniaUI/ViewModels/AccountSwitcherViewModel.cs b/SteamAccountManager.AvaloniaUI/ViewModels/AccountSwitcherViewModel.cs index cf13fff..0d5b0e3 100644 --- a/SteamAccountManager.AvaloniaUI/ViewModels/AccountSwitcherViewModel.cs +++ b/SteamAccountManager.AvaloniaUI/ViewModels/AccountSwitcherViewModel.cs @@ -1,16 +1,19 @@ -using SteamAccountManager.Application.Steam.Service; -using SteamAccountManager.Application.Steam.UseCase; -using SteamAccountManager.AvaloniaUI.Common; -using SteamAccountManager.AvaloniaUI.Mappers; -using SteamAccountManager.AvaloniaUI.Models; -using SteamAccountManager.AvaloniaUI.ViewModels.Commands; -using System; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; -using SteamAccountManager.Application.Steam.Observables; using ReactiveUI; +using SteamAccountManager.AvaloniaUI.Common; +using SteamAccountManager.AvaloniaUI.Mappers; +using SteamAccountManager.AvaloniaUI.Models; +using SteamAccountManager.AvaloniaUI.ViewModels.Commands; +using SteamAccountManager.Domain.Common.EventSystem; +using SteamAccountManager.Domain.Steam.Configuration.Model; +using SteamAccountManager.Domain.Steam.Service; +using SteamAccountManager.Domain.Steam.Storage; +using SteamAccountManager.Domain.Steam.UseCase; namespace SteamAccountManager.AvaloniaUI.ViewModels { @@ -22,6 +25,8 @@ public class AccountSwitcherViewModel : RoutableViewModel private readonly ISwitchAccountUseCase _switchAccountUseCase; private readonly AccountMapper _accountMapper; private readonly ILocalNotificationService _notificationService; + private readonly IPrivacyConfigStorage _privacyConfigStorage; + private readonly EventBus _eventBus; public AdvancedObservableCollection Accounts { get; private set; } public ICommand ProfileClickedCommand { get; } @@ -29,6 +34,7 @@ public class AccountSwitcherViewModel : RoutableViewModel public ICommand ShowInfoCommand { get; } public ICommand AddAccountCommand { get; } public Account? SelectedAccount { get; set; } + public VisibilityConfig Config { get; private set; } = new(); public AccountSwitcherViewModel ( @@ -36,28 +42,63 @@ public AccountSwitcherViewModel IGetAccountsWithDetailsUseCase getAccountsUseCase, ISwitchAccountUseCase switchAccountUseCase, AccountMapper accountMapper, - IAccountStorageObservable accountStorageObserver, - ILocalNotificationService notificationService + ILocalNotificationService notificationService, + IPrivacyConfigStorage privacyConfigStorage, + EventBus eventBus ) : base(screen) { _getAccountsUseCase = getAccountsUseCase; _switchAccountUseCase = switchAccountUseCase; _accountMapper = accountMapper; _notificationService = notificationService; + _privacyConfigStorage = privacyConfigStorage; + _eventBus = eventBus; Accounts = new AdvancedObservableCollection(); ProfileClickedCommand = new ProfileClickedCommand(); RefreshAccountsCommand = new QuickCommand(LoadAccounts); ShowInfoCommand = new QuickCommand(ShowInfo); AddAccountCommand = new QuickCommand(AddAccount); - accountStorageObserver.Subscribe(Accounts_Changed); + RegisterSubscriptions(); + LoadVisibilityConfig(); LoadAccounts(); } - private void Accounts_Changed(List? accounts) + private void RegisterSubscriptions() { - LoadAccounts(); + _eventBus.Subscribe(subscriberKey: GetType().Name, Events.ACCOUNTS_UPDATED, + _ => LoadAccounts() + ); + _eventBus.Subscribe(subscriberKey: GetType().Name, Events.PRIVACY_CONFIG_UPDATED, + _ => LoadVisibilityConfig() + ); + } + + private void LoadVisibilityConfig() + { + var config = _privacyConfigStorage.Get()?.DetailSettings; + if (config is null) + return; + + foreach (var setting in config) + { + switch (setting.DetailType) + { + case AccountDetailType.LoginName: + Config.ShowLoginName = setting.IsEnabled; + break; + case AccountDetailType.Level: + Config.ShowLevel = setting.IsEnabled; + break; + case AccountDetailType.Avatar: + Config.ShowAvatar = setting.IsEnabled; + break; + case AccountDetailType.BanStatus: + Config.ShowBanStatus = setting.IsEnabled; + break; + } + } } private async void AddAccount() @@ -66,8 +107,8 @@ private async void AddAccount() } private IEnumerable SortAccounts(Account[] accounts) => accounts.OrderByDescending(x => x.Rank.Level) - .ThenBy(x => x.Name) - .ThenBy(x => x.IsVacBanned); + .ThenBy(x => x.Name) + .ThenBy(x => x.IsVacBanned); private async Task> GetAccounts() { @@ -78,6 +119,7 @@ private async Task> GetAccounts() public async void LoadAccounts() { + LoadVisibilityConfig(); Accounts.SetItems((await GetAccounts()).ToList()); } @@ -98,14 +140,23 @@ public async void OnAccountSelected(Account selectedAccount) public void ShowInfo() { - if(System.OperatingSystem.IsWindows()) + if (OperatingSystem.IsWindows()) { - System.Diagnostics.Process.Start("explorer", "https://github.com/sahin-a/SteamAccountManager/"); + Process.Start("explorer", "https://github.com/sahin-a/SteamAccountManager/"); } - else + else { - System.Diagnostics.Process.Start("xdg-open", "https://github.com/sahin-a/SteamAccountManager/"); + Process.Start("xdg-open", "https://github.com/sahin-a/SteamAccountManager/"); } } } -} + + public class VisibilityConfig + { + public bool ShowUsername { get; set; } = true; + public bool ShowLoginName { get; set; } = true; + public bool ShowAvatar { get; set; } = true; + public bool ShowLevel { get; set; } = true; + public bool ShowBanStatus { get; set; } = true; + } +} \ No newline at end of file diff --git a/SteamAccountManager.AvaloniaUI/ViewModels/SettingsViewModel.cs b/SteamAccountManager.AvaloniaUI/ViewModels/SettingsViewModel.cs index c50de03..b7b2fd8 100644 --- a/SteamAccountManager.AvaloniaUI/ViewModels/SettingsViewModel.cs +++ b/SteamAccountManager.AvaloniaUI/ViewModels/SettingsViewModel.cs @@ -1,27 +1,94 @@ -using System.Windows.Input; +using System; +using System.Linq; +using System.Windows.Input; +using DynamicData; using ReactiveUI; -using SteamAccountManager.Infrastructure.Steam.Local.Storage; +using SteamAccountManager.AvaloniaUI.Common; +using SteamAccountManager.Domain.Common.EventSystem; +using SteamAccountManager.Domain.Steam.Configuration.Model; +using SteamAccountManager.Domain.Steam.Storage; namespace SteamAccountManager.AvaloniaUI.ViewModels { public class SettingsViewModel : RoutableViewModel { - private readonly SteamApiKeyStorage _steamApiKeyStorage; + private readonly ISteamApiKeyStorage _steamApiKeyStorage; + private readonly IPrivacyConfigStorage _privacyConfigStorage; + private readonly EventBus _eventBus; + + + public AdvancedObservableCollection AccountDetailsToggles { get; } = new(); public ICommand SaveApiKeyCommand { get; } public string WebApiKey { get; set; } - public SettingsViewModel(IScreen screen, SteamApiKeyStorage apiKeyStorage) : base(screen) + public SettingsViewModel + ( + IScreen screen, + ISteamApiKeyStorage apiKeyStorage, + IPrivacyConfigStorage privacyConfigStorage, + EventBus eventBus + ) : base(screen) { _steamApiKeyStorage = apiKeyStorage; + _privacyConfigStorage = privacyConfigStorage; + _eventBus = eventBus; + SaveApiKeyCommand = ReactiveCommand.Create((string key) => SaveApiKey(key)); + InitializeControls(); PrefillFields(); } + private void InitializeControls() + { + CreateAccountDetailToggles(); + } + private void PrefillFields() { WebApiKey = _steamApiKeyStorage.Get(); + + var privacyConfig = _privacyConfigStorage.Get()?.DetailSettings; + if (privacyConfig is not null) + { + foreach (var toggle in AccountDetailsToggles) + { + toggle.IsToggled = privacyConfig + .FirstOrDefault(x => x.DetailType == toggle.DetailType)?.IsEnabled ?? false; + } + } + } + + private void CreateAccountDetailToggles() + { + var detailToggledCommand = + ReactiveCommand.Create((AccountDetailToggle detailToggle) => DetailToggled(detailToggle)); + + var toggles = Enum.GetValues().Select(x => + new AccountDetailToggle(x, title: x.ToTitle(), detailToggledCommand, isToggled: true)); + + AccountDetailsToggles.SetItems(toggles.ToList()); + } + + private void DetailToggled(AccountDetailToggle detailToggle) + { + var privacyConfig = _privacyConfigStorage.Get(); + if (privacyConfig is not null) + { + var setting = privacyConfig.DetailSettings.FirstOrDefault(x => x.DetailType == detailToggle.DetailType); + privacyConfig.DetailSettings.ReplaceOrAdd(original: setting, + replaceWith: new(detailToggle.DetailType, detailToggle.IsToggled)); + + _privacyConfigStorage.Set(privacyConfig); + } + else + { + var settings = AccountDetailsToggles.Select(x => new DetailSetting(x.DetailType, x.IsToggled)); + _privacyConfigStorage.Set(new PrivacyConfig(settings.ToList())); + } + + _eventBus.Notify(Events.PRIVACY_CONFIG_UPDATED, null); } private void SaveApiKey(string key) @@ -29,4 +96,42 @@ private void SaveApiKey(string key) _steamApiKeyStorage.Set(key); } } + + static class AccountDetailTypeExtensions + { + // TODO: refactor this when localization story is being done + public static string ToTitle(this AccountDetailType type) + { + switch (type) + { + case AccountDetailType.LoginName: + return "Login Name"; + case AccountDetailType.Level: + return "Level"; + case AccountDetailType.Avatar: + return "Avatar"; + case AccountDetailType.BanStatus: + return "Ban Status"; + } + + return ""; + } + } + + public class AccountDetailToggle + { + public string Title { get; set; } + public ICommand ToggledCommand { get; set; } + public bool IsToggled { get; set; } + + public AccountDetailType DetailType { get; set; } + + public AccountDetailToggle(AccountDetailType detailType, string title, ICommand toggledCommand, bool isToggled) + { + Title = title; + ToggledCommand = toggledCommand; + IsToggled = isToggled; + DetailType = detailType; + } + } } \ No newline at end of file diff --git a/SteamAccountManager.AvaloniaUI/Views/AccountSwitcherView.axaml b/SteamAccountManager.AvaloniaUI/Views/AccountSwitcherView.axaml index 33e7628..82758f4 100644 --- a/SteamAccountManager.AvaloniaUI/Views/AccountSwitcherView.axaml +++ b/SteamAccountManager.AvaloniaUI/Views/AccountSwitcherView.axaml @@ -2,94 +2,111 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:local="using:SteamAccountManager.AvaloniaUI" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SteamAccountManager.AvaloniaUI.Views.AccountSwitcherView"> - - - - - + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - + + + - - - + + + + + - - - - - - + + + + + + - - + + - - - - - - - - - + + + + + + + + + - + - + \ No newline at end of file diff --git a/SteamAccountManager.AvaloniaUI/Views/SettingsView.axaml b/SteamAccountManager.AvaloniaUI/Views/SettingsView.axaml index fb5fcdd..17f170c 100644 --- a/SteamAccountManager.AvaloniaUI/Views/SettingsView.axaml +++ b/SteamAccountManager.AvaloniaUI/Views/SettingsView.axaml @@ -8,16 +8,30 @@ + - + + + + + + + + + + + +