From 5cb8eee38c9d0c8dd775fbbd8fc9678fdc59e348 Mon Sep 17 00:00:00 2001 From: retr0volkov Date: Tue, 22 Sep 2026 15:23:39 +0300 Subject: [PATCH] New UI (not wired up) --- WinWARP.Core/Models/Entities/Server.cs | 5 + .../Implementations/SubscriptionFetcher.cs | 10 +- .../Interfaces/ISubscriptionFetcher.cs | 1 - WinWARP.Core/ViewModels/HomeViewModel.cs | 2 +- .../ViewModels/ServerItemViewModel.cs | 18 +- .../ViewModels/SubsSettingsViewModel.cs | 15 +- .../Wrappers/SubscriptionViewModel.cs | 73 ++++++++ .../Converters/BoolToVisibilityConverter.cs | 8 +- WinWARP.Ui/Strings/en-US/Resources.resw | 66 +++++++- WinWARP.Ui/Strings/ru-RU/Resources.resw | 66 +++++++- .../Views/Components/ServerListElement.xaml | 31 +++- .../Components/ServerListElement.xaml.cs | 28 +++- WinWARP.Ui/Views/SubsSettingsPage.xaml | 156 +++++++++++++++--- WinWARP.Ui/WinWARP.Ui.csproj | 1 + 14 files changed, 426 insertions(+), 54 deletions(-) diff --git a/WinWARP.Core/Models/Entities/Server.cs b/WinWARP.Core/Models/Entities/Server.cs index df094bb..af54af0 100644 --- a/WinWARP.Core/Models/Entities/Server.cs +++ b/WinWARP.Core/Models/Entities/Server.cs @@ -44,4 +44,9 @@ public abstract class Server { get; set; } = false; + + public List Tags + { + get; set; + } = []; } diff --git a/WinWARP.Core/Services/Implementations/SubscriptionFetcher.cs b/WinWARP.Core/Services/Implementations/SubscriptionFetcher.cs index aeae0f7..d036743 100644 --- a/WinWARP.Core/Services/Implementations/SubscriptionFetcher.cs +++ b/WinWARP.Core/Services/Implementations/SubscriptionFetcher.cs @@ -14,7 +14,7 @@ namespace WinWARP.Core.Services.Implementations; public partial class SubscriptionFetcher(IDialogService dialogService) : ISubscriptionFetcher { - private static readonly HttpClient _httpClient = new HttpClient(); + private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(10) }; private readonly IDialogService _dialogService = dialogService; public bool IsUrlValid(string subscriptionUrl) @@ -31,7 +31,6 @@ public partial class SubscriptionFetcher(IDialogService dialogService) : ISubscr public async Task FetchAsync(string subscriptionUrl) { - _httpClient.Timeout = TimeSpan.FromSeconds(10); var subscription = new Subscription { Link = subscriptionUrl @@ -239,7 +238,8 @@ public partial class SubscriptionFetcher(IDialogService dialogService) : ISubscr { DefaultTitle = GetServerTitle(title, out var region), Region = FlagEmojiParser.ExtractCountryCodes(title).FirstOrDefault() ?? string.Empty, - ConnectionString = serverData + ConnectionString = serverData, + Tags = GetTags(serverData) }; } else @@ -250,7 +250,7 @@ public partial class SubscriptionFetcher(IDialogService dialogService) : ISubscr #endregion #region Tags - public List GetTags(string connection) + private static List GetTags(string connection) { if (string.IsNullOrWhiteSpace(connection)) return null; @@ -351,7 +351,7 @@ public partial class SubscriptionFetcher(IDialogService dialogService) : ISubscr yield return transport.ToUpperInvariant(); } - private IEnumerable GetJsonTags(string json) + private static IEnumerable GetJsonTags(string json) { throw new NotImplementedException(); } diff --git a/WinWARP.Core/Services/Interfaces/ISubscriptionFetcher.cs b/WinWARP.Core/Services/Interfaces/ISubscriptionFetcher.cs index 9b84696..f26e2d4 100644 --- a/WinWARP.Core/Services/Interfaces/ISubscriptionFetcher.cs +++ b/WinWARP.Core/Services/Interfaces/ISubscriptionFetcher.cs @@ -9,5 +9,4 @@ public interface ISubscriptionFetcher { public bool IsUrlValid(string url); public Task FetchAsync(string url); - public List GetTags(string connectionString); } diff --git a/WinWARP.Core/ViewModels/HomeViewModel.cs b/WinWARP.Core/ViewModels/HomeViewModel.cs index f61d1a0..85fc041 100644 --- a/WinWARP.Core/ViewModels/HomeViewModel.cs +++ b/WinWARP.Core/ViewModels/HomeViewModel.cs @@ -14,6 +14,6 @@ public partial class HomeViewModel(INavigationService navigationService) : Obser [RelayCommand] private void TestTransition() { - _navigationService.NavigateTo(); + _navigationService.NavigateTo(); } } diff --git a/WinWARP.Core/ViewModels/ServerItemViewModel.cs b/WinWARP.Core/ViewModels/ServerItemViewModel.cs index 2f53357..07a7187 100644 --- a/WinWARP.Core/ViewModels/ServerItemViewModel.cs +++ b/WinWARP.Core/ViewModels/ServerItemViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -15,8 +16,11 @@ public abstract partial class ServerItemViewModel : ObservableObject Id = server.Id; DefaultTitle = server.DefaultTitle; Title = server.Title; - ConnectionString = server.ConnectionString; Region = server.Region; + ConnectionString = server.ConnectionString; + IsDeleted = server.IsDeleted; + IsDisabled = server.IsDisabled; + Tags = new ObservableCollection(server.Tags); } public int Id @@ -68,4 +72,16 @@ public abstract partial class ServerItemViewModel : ObservableObject } public ObservableCollection Tags { get; } = []; + + [ObservableProperty] + public partial bool IsDeleted + { + get; set; + } + + [ObservableProperty] + public partial bool IsDisabled + { + get; set; + } } diff --git a/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs b/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs index 0540511..fa34cd6 100644 --- a/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs +++ b/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs @@ -26,7 +26,7 @@ public partial class SubsSettingsViewModel(ISubscriptionDbService dbService, ISu } public ObservableCollection Subscriptions { get; } = []; - public ObservableCollection Servers { get; } = []; + public ObservableCollection Servers { get; } = []; public async Task LoadSubscriptionsAsync() { @@ -37,8 +37,6 @@ public partial class SubsSettingsViewModel(ISubscriptionDbService dbService, ISu Subscriptions.Add(new SubscriptionViewModel(subscription)); } - Servers.Add(new StandaloneServerViewModel(new StandaloneServer() { Region = "NO", Title = "Not default title", DefaultTitle = "Default title" }) { Tags = { "VLESS", "GRPC", "REALITY" } }); - ShowLoadingIndicator = false; } @@ -66,13 +64,10 @@ public partial class SubsSettingsViewModel(ISubscriptionDbService dbService, ISu subscription.Title = customName; subscription.UpdateInterval = updateInterval; - Subscriptions.Add(new SubscriptionViewModel(subscription)); - foreach (var server in subscription.Servers) - { - var serverVM = new SubscriptionServerViewModel(server); - foreach (var tag in _fetcher.GetTags(server.ConnectionString)) serverVM.Tags.Add(tag); - Servers.Add(serverVM); - } + var sub = new SubscriptionViewModel(subscription); + + Subscriptions.Add(sub); + ShowLoadingIndicator = false; } diff --git a/WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs b/WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs index 5d7328d..c242d8b 100644 --- a/WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs +++ b/WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -21,6 +22,8 @@ public partial class SubscriptionViewModel : ObservableValidator Title = subscription.Title; UpdateInterval = subscription.UpdateInterval; SupportURL = subscription.SupportURL; + + Servers = new ObservableCollection(subscription.Servers.Select(s => new SubscriptionServerViewModel(s))); } [ObservableProperty] @@ -30,12 +33,16 @@ public partial class SubscriptionViewModel : ObservableValidator public partial string WebPage { get; set; } [ObservableProperty] + [NotifyPropertyChangedFor(nameof(GetTitle))] + [NotifyPropertyChangedFor(nameof(IsNotDefaultTitle))] public partial string DefaultTitle { get; set; } [ObservableProperty] public partial int DefaultUpdateInterval { get; set; } [ObservableProperty] + [NotifyPropertyChangedFor(nameof(GetTitle))] + [NotifyPropertyChangedFor(nameof(IsNotDefaultTitle))] public partial string Title { get; set; } [ObservableProperty] @@ -63,4 +70,70 @@ public partial class SubscriptionViewModel : ObservableValidator { return IsDirty && !HasErrors; } + + public ObservableCollection Servers + { + get; set; + } + + [RelayCommand] + public async Task DeleteAsync() + { + + } + + public async Task EditNameAsync() + { + + } + + [ObservableProperty] + public partial bool IsNameEditing + { + get; set; + } = false; + + [RelayCommand] + public void EditName() + { + if (IsNameEditing) + EditNameAsync(); + IsNameEditing = !IsNameEditing; + } + + [ObservableProperty] + public partial bool IsDeleted + { + get; set; + } + + [ObservableProperty] + public partial bool IsDisabled + { + get; set; + } + + public string GetUidForNameEditing(bool isNameEditing) + { + if (isNameEditing) return "ServerListElementMenuFlyoutSave"; + else return "ServerListElementMenuFlyoutEdit"; + } + + public string GetGlyphForNameEditing(bool isNameEditing) + { + if (isNameEditing) return "\uE792"; + else return "\uE70F"; + } + + public string GetTitle + { + get => string.IsNullOrEmpty(Title) ? (string.IsNullOrEmpty(DefaultTitle) ? string.Empty : DefaultTitle) : Title; + set => throw new InvalidOperationException(); + } + + public bool IsNotDefaultTitle + { + get => (!string.IsNullOrEmpty(Title) && Title != DefaultTitle); + set => throw new InvalidOperationException(); + } } diff --git a/WinWARP.Ui/Converters/BoolToVisibilityConverter.cs b/WinWARP.Ui/Converters/BoolToVisibilityConverter.cs index 3b86285..65dae79 100644 --- a/WinWARP.Ui/Converters/BoolToVisibilityConverter.cs +++ b/WinWARP.Ui/Converters/BoolToVisibilityConverter.cs @@ -21,7 +21,13 @@ public partial class BoolToVisibilityConverter : MarkupExtension, IValueConverte flag = boolValue; } - if (IsInverted) + var parameterInverted = false; + if (parameter is string paramStr && bool.TryParse(paramStr, out var result)) + { + parameterInverted = result; + } + + if (IsInverted || parameterInverted) { flag = !flag; } diff --git a/WinWARP.Ui/Strings/en-US/Resources.resw b/WinWARP.Ui/Strings/en-US/Resources.resw index b588222..661a9e4 100644 --- a/WinWARP.Ui/Strings/en-US/Resources.resw +++ b/WinWARP.Ui/Strings/en-US/Resources.resw @@ -213,9 +213,6 @@ DNS Settings - - Subscriptions and servers - Configs settings @@ -273,4 +270,67 @@ Error occurred: + + Edit name + + + Disable server + + + Delete server + + + New title... + + + Save name + + + Add subscription + + + Select subscriptions + + + Select servers + + + Select all + + + Enable selected + + + Disable selected + + + Delete selected + + + Subscriptions and servers + + + Add server + + + Subscriptons + + + Server + + + Nothing here... + + + Import config + + + New title... + + + Delete subscription + + + Disable subscription + \ No newline at end of file diff --git a/WinWARP.Ui/Strings/ru-RU/Resources.resw b/WinWARP.Ui/Strings/ru-RU/Resources.resw index 75eadb9..2e5c905 100644 --- a/WinWARP.Ui/Strings/ru-RU/Resources.resw +++ b/WinWARP.Ui/Strings/ru-RU/Resources.resw @@ -213,9 +213,6 @@ Настройки DNS - - Подписки и сервера - Конфигурации @@ -273,4 +270,67 @@ Произошла ошибка: + + Изменить имя + + + Выключить сервер + + + Удалить сервер + + + Новое название + + + Сохранить имя + + + Добавить подписку + + + Выбрать подписки + + + Выбрать сервера + + + Выбрать всё + + + Включить выбранные + + + Отключить выбранные + + + Удалить выбранные + + + Подписки и сервера + + + Добавить сервер + + + Подписки + + + Сервера + + + Здесь пусто... + + + Импортировать файл + + + Новое имя... + + + Удалить подписку + + + Выключить подписку + \ No newline at end of file diff --git a/WinWARP.Ui/Views/Components/ServerListElement.xaml b/WinWARP.Ui/Views/Components/ServerListElement.xaml index cb3492a..9fecde9 100644 --- a/WinWARP.Ui/Views/Components/ServerListElement.xaml +++ b/WinWARP.Ui/Views/Components/ServerListElement.xaml @@ -10,6 +10,7 @@ xmlns:w="using:WinWARP.Core.ViewModels.Wrappers" xmlns:conv="using:WinWARP.Ui.Converters" xmlns:h="using:WinWARP.Ui.Helpers" + xmlns:u="using:WinUI3Localizer" Height="64" Width="300" mc:Ignorable="d"> @@ -23,17 +24,30 @@ + - - - + + + + + + + + + + + + + + + + + - + @@ -57,10 +71,11 @@ --> - + + - diff --git a/WinWARP.Ui/Views/Components/ServerListElement.xaml.cs b/WinWARP.Ui/Views/Components/ServerListElement.xaml.cs index 8eff4ba..b40d9d6 100644 --- a/WinWARP.Ui/Views/Components/ServerListElement.xaml.cs +++ b/WinWARP.Ui/Views/Components/ServerListElement.xaml.cs @@ -27,7 +27,7 @@ public sealed partial class ServerListElement : UserControl public static readonly DependencyProperty ServerDataProperty = DependencyProperty.Register(nameof(ServerData), typeof(ServerItemViewModel), - typeof(ServerListElement), new PropertyMetadata(null)); + typeof(ServerListElement), new PropertyMetadata(null, OnServerDataChanged)); public ServerItemViewModel ServerData { @@ -35,7 +35,7 @@ public sealed partial class ServerListElement : UserControl set => SetValue(ServerDataProperty, value); } - public string Title(ServerItemViewModel serverData) => string.IsNullOrEmpty(serverData?.Title) ? (string.IsNullOrEmpty(serverData?.DefaultTitle) ? string.Empty : serverData.DefaultTitle) : serverData.Title; + public string GetTitle(ServerItemViewModel serverData) => string.IsNullOrEmpty(serverData?.Title) ? (string.IsNullOrEmpty(serverData?.DefaultTitle) ? string.Empty : serverData.DefaultTitle) : serverData.Title; public Visibility IsNotDefaultTitle(ServerItemViewModel serverData) => (!string.IsNullOrEmpty(serverData?.Title) && serverData?.Title != serverData?.DefaultTitle) ? Visibility.Visible : Visibility.Collapsed; @@ -80,4 +80,28 @@ public sealed partial class ServerListElement : UserControl ServerListFlyout.ShowAt(button, options); } } + + private static void OnServerDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (ServerListElement)d; + if (e.OldValue is ServerItemViewModel oldVM) oldVM.PropertyChanged -= control.OnServerItemPropertyChanged; + if (e.NewValue is ServerItemViewModel newVM) newVM.PropertyChanged += control.OnServerItemPropertyChanged; + } + + private void OnServerItemPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ServerItemViewModel.Title)) Bindings.Update(); + } + + private string GetUidForNameEditing(bool isNameEditing) + { + if (isNameEditing) return "ServerListElementMenuFlyoutSave"; + else return "ServerListElementMenuFlyoutEdit"; + } + + private string GetGlyphForNameEditing(bool isNameEditing) + { + if (isNameEditing) return "\uE792"; + else return "\uE70F"; + } } diff --git a/WinWARP.Ui/Views/SubsSettingsPage.xaml b/WinWARP.Ui/Views/SubsSettingsPage.xaml index 0be0686..b0e6585 100644 --- a/WinWARP.Ui/Views/SubsSettingsPage.xaml +++ b/WinWARP.Ui/Views/SubsSettingsPage.xaml @@ -6,29 +6,147 @@ xmlns:local="using:WinWARP.Ui.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:com="using:CommunityToolkit.WinUI.Controls" + xmlns:conv="using:WinWARP.Ui.Converters" xmlns:c="using:WinWARP.Ui.Views.Components" xmlns:vm="using:WinWARP.Core.ViewModels" + xmlns:w="using:WinWARP.Core.ViewModels.Wrappers" + xmlns:u="using:WinUI3Localizer" mc:Ignorable="d"> - - -