diff --git a/WinWARP.Core/Data/AppDbContext.cs b/WinWARP.Core/Data/AppDbContext.cs new file mode 100644 index 0000000..1c4b2b4 --- /dev/null +++ b/WinWARP.Core/Data/AppDbContext.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.EntityFrameworkCore; +using WinWARP.Core.Models.Entities; + +namespace WinWARP.Core.Data; + +public class AppDbContext : DbContext +{ + public DbSet Subscriptions => Set(); + + public AppDbContext(DbContextOptions options) : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity() + .HasKey(s => s.Id); + } +} \ No newline at end of file diff --git a/WinWARP.Core/Models/Entities/Server.cs b/WinWARP.Core/Models/Entities/Server.cs new file mode 100644 index 0000000..5f94541 --- /dev/null +++ b/WinWARP.Core/Models/Entities/Server.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace WinWARP.Core.Models.Entities; + +public class Server +{ + [Key] + public int Id + { + get; set; + } + + + public int SubscriptionId + { + get; set; + } + +} diff --git a/WinWARP.Core/Models/Entities/Subscription.cs b/WinWARP.Core/Models/Entities/Subscription.cs new file mode 100644 index 0000000..4afb37f --- /dev/null +++ b/WinWARP.Core/Models/Entities/Subscription.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace WinWARP.Core.Models.Entities; + +public class Subscription +{ + [Key] + public int Id + { + get; set; + } + + [Required] + [StringLength(100)] + public string Link + { + get; set; + } + + [StringLength(100)] + public string WebPage + { + get; set; + } = string.Empty; + + [StringLength(100)] + public string DefaultTitle + { + get; set; + } = string.Empty; + + public int DefaultUpdateInterval + { + get; set; + } = 1; + + [StringLength(100)] + public string Title + { + get; set; + } = string.Empty; + + public int UpdateInterval + { + get; set; + } = 1; + + [StringLength(100)] + public string SupportURL + { + get; set; + } = string.Empty; +} diff --git a/WinWARP.Core/Services/Implementations/SubscriptionDbService.cs b/WinWARP.Core/Services/Implementations/SubscriptionDbService.cs new file mode 100644 index 0000000..17ce93a --- /dev/null +++ b/WinWARP.Core/Services/Implementations/SubscriptionDbService.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.EntityFrameworkCore; +using WinWARP.Core.Data; +using WinWARP.Core.Models.Entities; +using WinWARP.Core.Services.Interfaces; + +namespace WinWARP.Core.Services.Implementations; + +public class SubscriptionDbService : ISubscriptionDbService +{ + private IDbContextFactory _dbContextFactory; + + public SubscriptionDbService(IDbContextFactory dbContextFactory) + { + _dbContextFactory = dbContextFactory; + } + + public async Task> GetSubscriptionsAsync() + { + using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + return await dbContext.Subscriptions.ToListAsync(); + } + + public async Task AddSubscriptionAsync(Subscription subscription) + { + using var dbContext = await _dbContextFactory.CreateDbContextAsync(); + dbContext.Subscriptions.Add(subscription); + await dbContext.SaveChangesAsync(); + } +} diff --git a/WinWARP.Core/Services/ILocalizationService.cs b/WinWARP.Core/Services/Interfaces/ILocalizationService.cs similarity index 86% rename from WinWARP.Core/Services/ILocalizationService.cs rename to WinWARP.Core/Services/Interfaces/ILocalizationService.cs index ae41c65..ee7395b 100644 --- a/WinWARP.Core/Services/ILocalizationService.cs +++ b/WinWARP.Core/Services/Interfaces/ILocalizationService.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace WinWARP.Core.Services; +namespace WinWARP.Core.Services.Interfaces; public interface ILocalizationService { diff --git a/WinWARP.Core/Services/INavigationService.cs b/WinWARP.Core/Services/Interfaces/INavigationService.cs similarity index 89% rename from WinWARP.Core/Services/INavigationService.cs rename to WinWARP.Core/Services/Interfaces/INavigationService.cs index 02b3678..0ac2bc2 100644 --- a/WinWARP.Core/Services/INavigationService.cs +++ b/WinWARP.Core/Services/Interfaces/INavigationService.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Text; -namespace WinWARP.Core.Services; +namespace WinWARP.Core.Services.Interfaces; public interface INavigationService { diff --git a/WinWARP.Core/Services/Interfaces/ISubscriptionDbService.cs b/WinWARP.Core/Services/Interfaces/ISubscriptionDbService.cs new file mode 100644 index 0000000..b6e01d0 --- /dev/null +++ b/WinWARP.Core/Services/Interfaces/ISubscriptionDbService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WinWARP.Core.Models.Entities; + +namespace WinWARP.Core.Services.Interfaces; + +public interface ISubscriptionDbService +{ + public Task> GetSubscriptionsAsync(); + public Task AddSubscriptionAsync(Subscription subscription); +} diff --git a/WinWARP.Core/ViewModels/HomeViewModel.cs b/WinWARP.Core/ViewModels/HomeViewModel.cs index d7a0a78..9f98075 100644 --- a/WinWARP.Core/ViewModels/HomeViewModel.cs +++ b/WinWARP.Core/ViewModels/HomeViewModel.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using WinWARP.Core.Services; +using WinWARP.Core.Services.Interfaces; namespace WinWARP.Core.ViewModels; diff --git a/WinWARP.Core/ViewModels/MainViewModel.cs b/WinWARP.Core/ViewModels/MainViewModel.cs index d92da88..b40786f 100644 --- a/WinWARP.Core/ViewModels/MainViewModel.cs +++ b/WinWARP.Core/ViewModels/MainViewModel.cs @@ -4,7 +4,7 @@ using System.ComponentModel; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using WinWARP.Core.Services; +using WinWARP.Core.Services.Interfaces; namespace WinWARP.Core.ViewModels; diff --git a/WinWARP.Core/ViewModels/SettingsViewModel.cs b/WinWARP.Core/ViewModels/SettingsViewModel.cs index 840da00..e5780fa 100644 --- a/WinWARP.Core/ViewModels/SettingsViewModel.cs +++ b/WinWARP.Core/ViewModels/SettingsViewModel.cs @@ -4,7 +4,7 @@ using System.Collections.ObjectModel; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using WinWARP.Core.Services; +using WinWARP.Core.Services.Interfaces; namespace WinWARP.Core.ViewModels; diff --git a/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs b/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs new file mode 100644 index 0000000..9e7ae2f --- /dev/null +++ b/WinWARP.Core/ViewModels/SubsSettingsViewModel.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using WinWARP.Core.Models.Entities; +using WinWARP.Core.Services.Interfaces; + +namespace WinWARP.Core.ViewModels; + +public partial class SubsSettingsViewModel(ISubscriptionDbService dbService) : ObservableObject +{ + private readonly ISubscriptionDbService _dbService = dbService; + + public ObservableCollection Subscriptions { get; } = []; + + public async Task LoadSubscriptionsAsync() + { + Subscriptions.Clear(); + var data = await _dbService.GetSubscriptionsAsync(); + foreach (var subscription in data) + { + Subscriptions.Add(subscription); + } + } + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(AddSubscriptionCommand))] + public partial string NewSubscriptionLink { get; set; } = string.Empty; + + [RelayCommand(CanExecute = nameof(CanAddSubscription))] + public async Task AddSubscriptionAsync() + { + if (!string.IsNullOrWhiteSpace(NewSubscriptionLink)) + { + var subscription = new Subscription + { + Link = NewSubscriptionLink, + Title = "New Subscription", + UpdateInterval = 60 // Default update interval + }; + await _dbService.AddSubscriptionAsync(subscription); + Subscriptions.Add(subscription); + NewSubscriptionLink = string.Empty; + } + } + + private bool CanAddSubscription() + { + return !string.IsNullOrWhiteSpace(NewSubscriptionLink); + } +} diff --git a/WinWARP.Core/ViewModels/SubsSettingsPage.cs b/WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs similarity index 52% rename from WinWARP.Core/ViewModels/SubsSettingsPage.cs rename to WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs index fd873eb..133e326 100644 --- a/WinWARP.Core/ViewModels/SubsSettingsPage.cs +++ b/WinWARP.Core/ViewModels/Wrappers/SubscriptionViewModel.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; -namespace WinWARP.Core.ViewModels; +namespace WinWARP.Core.ViewModels.Wrappers; -public class SubsSettingsViewModel : ObservableObject +public partial class SubscriptionViewModel : ObservableObject { + } diff --git a/WinWARP.Core/WinWARP.Core.csproj b/WinWARP.Core/WinWARP.Core.csproj index f954a7b..1aa6290 100644 --- a/WinWARP.Core/WinWARP.Core.csproj +++ b/WinWARP.Core/WinWARP.Core.csproj @@ -8,6 +8,11 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/WinWARP.Ui/App.xaml.cs b/WinWARP.Ui/App.xaml.cs index 5f5a288..87f01f3 100644 --- a/WinWARP.Ui/App.xaml.cs +++ b/WinWARP.Ui/App.xaml.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -12,20 +13,22 @@ using Microsoft.UI.Xaml.Data; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Navigation; -using Microsoft.UI.Xaml.Shapes; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.ApplicationSettings; using WinUI3Localizer; -using WinWARP.Core.Services; using WinWARP.Core.ViewModels; using WinWARP.Core.ViewModels.ConfigSettings; using WinWARP.Core.ViewModels.Settings; +using WinWARP.Core.Data; using WinWARP.Ui.Services; using WinWARP.Ui.Views; using WinWARP.Ui.Views.Settings; +using WinWARP.Core.Services.Implementations; +using WinWARP.Core.Services.Interfaces; +using System.Diagnostics; // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. @@ -52,34 +55,34 @@ public partial class App : Application { InitializeComponent(); Services = ConfigureServices(); + + using var context = Services.GetRequiredService>().CreateDbContext(); + context.Database.EnsureCreated(); } /// /// Configures the services for dependency injection. /// /// - private static IServiceProvider ConfigureServices() + private static ServiceProvider ConfigureServices() { var services = new ServiceCollection(); - var navigationService = new NavigationService(); - navigationService.Configure(typeof(HomeViewModel), typeof(HomePage)); - navigationService.Configure(typeof(SettingsViewModel), typeof(SettingsPage)); - navigationService.Configure(typeof(SubsSettingsViewModel), typeof(SubsSettingsPage)); - navigationService.Configure(typeof(ConfigSettingsViewModel), typeof(ConfigSettingsPage)); + // DB + Debug.WriteLine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WinWARP", "app.db")); + services.AddDbContextFactory(options => + { + var folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WinWARP"); - navigationService.Configure(typeof(GeneralSettingsViewModel), typeof(GeneralSettingsPage)); - navigationService.Configure(typeof(UpdateSettingsViewModel), typeof(UpdateSettingsPage)); + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } - navigationService.Configure(typeof(InboundSettingsViewModel), typeof(InboundSettingsPage)); - navigationService.Configure(typeof(RoutingSettingsViewModel), typeof(RoutingSettingsPage)); - navigationService.Configure(typeof(DnsSettingsViewModel), typeof(DnsSettingsPage)); - navigationService.Configure(typeof(TlsSettingsViewModel), typeof(TlsSettingsPage)); - navigationService.Configure(typeof(WarpSettingsViewModel), typeof(WarpSettingsPage)); - - services.AddSingleton(); - - services.AddSingleton(navigationService); + var dbPath = Path.Combine(folder, "app.db"); + options.UseSqlite($"Data Source={dbPath}"); + }); + services.AddTransient(); // ViewModels services.AddTransient(); @@ -97,6 +100,26 @@ public partial class App : Application // Views services.AddTransient(); + + // UI services + var navigationService = new NavigationService(); + navigationService.Configure(typeof(HomeViewModel), typeof(HomePage)); + navigationService.Configure(typeof(SettingsViewModel), typeof(SettingsPage)); + navigationService.Configure(typeof(SubsSettingsViewModel), typeof(SubsSettingsPage)); + navigationService.Configure(typeof(ConfigSettingsViewModel), typeof(ConfigSettingsPage)); + + navigationService.Configure(typeof(GeneralSettingsViewModel), typeof(GeneralSettingsPage)); + navigationService.Configure(typeof(UpdateSettingsViewModel), typeof(UpdateSettingsPage)); + + navigationService.Configure(typeof(InboundSettingsViewModel), typeof(InboundSettingsPage)); + navigationService.Configure(typeof(RoutingSettingsViewModel), typeof(RoutingSettingsPage)); + navigationService.Configure(typeof(DnsSettingsViewModel), typeof(DnsSettingsPage)); + navigationService.Configure(typeof(TlsSettingsViewModel), typeof(TlsSettingsPage)); + navigationService.Configure(typeof(WarpSettingsViewModel), typeof(WarpSettingsPage)); + + services.AddSingleton(navigationService); + + services.AddSingleton(); return services.BuildServiceProvider(); } @@ -109,7 +132,7 @@ public partial class App : Application { var stringsFolderPath = System.IO.Path.Combine(AppContext.BaseDirectory, "Strings"); - ILocalizer localizer = await new LocalizerBuilder() + var localizer = await new LocalizerBuilder() .AddStringResourcesFolderForLanguageDictionaries(stringsFolderPath) .SetOptions(options => { diff --git a/WinWARP.Ui/MainWindow.xaml.cs b/WinWARP.Ui/MainWindow.xaml.cs index 13fe523..2edd83a 100644 --- a/WinWARP.Ui/MainWindow.xaml.cs +++ b/WinWARP.Ui/MainWindow.xaml.cs @@ -14,7 +14,7 @@ using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Navigation; using Windows.Foundation; using Windows.Foundation.Collections; -using WinWARP.Core.Services; +using WinWARP.Core.Services.Interfaces; using WinWARP.Core.ViewModels; using WinWARP.Ui.Services; diff --git a/WinWARP.Ui/Services/LocalizationService.cs b/WinWARP.Ui/Services/LocalizationService.cs index 66145aa..2d8976f 100644 --- a/WinWARP.Ui/Services/LocalizationService.cs +++ b/WinWARP.Ui/Services/LocalizationService.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using WinUI3Localizer; -using WinWARP.Core.Services; +using WinWARP.Core.Services.Interfaces; namespace WinWARP.Ui.Services; diff --git a/WinWARP.Ui/Services/NavigationService.cs b/WinWARP.Ui/Services/NavigationService.cs index 7e774c3..7e33f31 100644 --- a/WinWARP.Ui/Services/NavigationService.cs +++ b/WinWARP.Ui/Services/NavigationService.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; using System.Text; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; -using WinWARP.Core.Services; +using WinWARP.Core.Services.Interfaces; namespace WinWARP.Ui.Services; diff --git a/WinWARP.Ui/Views/SubsSettingsPage.xaml b/WinWARP.Ui/Views/SubsSettingsPage.xaml index d236436..245c62b 100644 --- a/WinWARP.Ui/Views/SubsSettingsPage.xaml +++ b/WinWARP.Ui/Views/SubsSettingsPage.xaml @@ -6,9 +6,23 @@ 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:m="using:WinWARP.Core.Models.Entities" mc:Ignorable="d"> - + + + + + +