commit 16160f642467ec70760ccdf2284ae498cd3220d5 Author: Radek Goláň jr Date: Thu Apr 9 10:36:09 2026 +0200 feat: initial datamodel + ef connection and migrations Initial version of the data model Includes EF initialization and migrations EF migrations are applied on application start diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cae166f --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +## A streamlined .gitignore for modern .NET projects +## including temporary files, build results, and +## files generated by popular .NET tools. If you are +## developing with Visual Studio, the VS .gitignore +## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +## has more thorough IDE-specific entries. +## +## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg + +# dotenv environment variables file +.env + +# Others +~$* +*~ +CodeCoverage/ + +# MSBuild Binary and Structured Log +*.binlog + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets +!*.code-workspace + +# Built Visual Studio Code Extensions +*.vsix diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..da1024c --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,23 @@ + + + + true + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + \ No newline at end of file diff --git a/TournamentOrganizer.Browser/Program.cs b/TournamentOrganizer.Browser/Program.cs new file mode 100644 index 0000000..9bc020d --- /dev/null +++ b/TournamentOrganizer.Browser/Program.cs @@ -0,0 +1,15 @@ +using System.Runtime.Versioning; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Browser; +using TournamentOrganizer; + +internal sealed partial class Program +{ + private static Task Main(string[] args) => BuildAvaloniaApp() + .WithInterFont() + .StartBrowserAppAsync("out"); + + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure(); +} \ No newline at end of file diff --git a/TournamentOrganizer.Browser/Properties/AssemblyInfo.cs b/TournamentOrganizer.Browser/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..99df742 --- /dev/null +++ b/TournamentOrganizer.Browser/Properties/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly:System.Runtime.Versioning.SupportedOSPlatform("browser")] diff --git a/TournamentOrganizer.Browser/Properties/launchSettings.json b/TournamentOrganizer.Browser/Properties/launchSettings.json new file mode 100644 index 0000000..2350710 --- /dev/null +++ b/TournamentOrganizer.Browser/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "TournamentOrganizer.Browser": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:7169;http://localhost:5235", + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}" + } + } +} diff --git a/TournamentOrganizer.Browser/TournamentOrganizer.Browser.csproj b/TournamentOrganizer.Browser/TournamentOrganizer.Browser.csproj new file mode 100644 index 0000000..015a9cf --- /dev/null +++ b/TournamentOrganizer.Browser/TournamentOrganizer.Browser.csproj @@ -0,0 +1,16 @@ + + + net10.0-browser + Exe + true + enable + + + + + + + + + + diff --git a/TournamentOrganizer.Browser/runtimeconfig.template.json b/TournamentOrganizer.Browser/runtimeconfig.template.json new file mode 100644 index 0000000..92a0467 --- /dev/null +++ b/TournamentOrganizer.Browser/runtimeconfig.template.json @@ -0,0 +1,10 @@ +{ + "wasmHostProperties": { + "perHostConfig": [ + { + "name": "browser", + "host": "browser" + } + ] + } +} \ No newline at end of file diff --git a/TournamentOrganizer.Browser/wwwroot/app.css b/TournamentOrganizer.Browser/wwwroot/app.css new file mode 100644 index 0000000..9b1f02b --- /dev/null +++ b/TournamentOrganizer.Browser/wwwroot/app.css @@ -0,0 +1,58 @@ +/* HTML styles for the splash screen */ +.avalonia-splash { + position: absolute; + height: 100%; + width: 100%; + background: white; + font-family: 'Outfit', sans-serif; + justify-content: center; + align-items: center; + display: flex; + pointer-events: none; +} + +/* Light theme styles */ +@media (prefers-color-scheme: light) { + .avalonia-splash { + background: white; + } + + .avalonia-splash h2 { + color: #1b2a4e; + } + + .avalonia-splash a { + color: #0D6EFD; + } +} + +@media (prefers-color-scheme: dark) { + .avalonia-splash { + background: #1b2a4e; + } + + .avalonia-splash h2 { + color: white; + } + + .avalonia-splash a { + color: white; + } +} + +.avalonia-splash h2 { + font-weight: 400; + font-size: 1.5rem; +} + +.avalonia-splash a { + text-decoration: none; + font-size: 2.5rem; + display: block; +} + +.avalonia-splash.splash-close { + transition: opacity 200ms, display 200ms; + display: none; + opacity: 0; +} diff --git a/TournamentOrganizer.Browser/wwwroot/favicon.ico b/TournamentOrganizer.Browser/wwwroot/favicon.ico new file mode 100644 index 0000000..f7da8bb Binary files /dev/null and b/TournamentOrganizer.Browser/wwwroot/favicon.ico differ diff --git a/TournamentOrganizer.Browser/wwwroot/index.html b/TournamentOrganizer.Browser/wwwroot/index.html new file mode 100644 index 0000000..f5c77a7 --- /dev/null +++ b/TournamentOrganizer.Browser/wwwroot/index.html @@ -0,0 +1,36 @@ + + + + + TournamentOrganizer.Browser + + + + + + +
+
+

+ Powered by + + + + + + + + + + + + + + +

+
+
+ + + + diff --git a/TournamentOrganizer.Browser/wwwroot/main.js b/TournamentOrganizer.Browser/wwwroot/main.js new file mode 100644 index 0000000..2402700 --- /dev/null +++ b/TournamentOrganizer.Browser/wwwroot/main.js @@ -0,0 +1,13 @@ +import { dotnet } from './_framework/dotnet.js' + +const is_browser = typeof window != "undefined"; +if (!is_browser) throw new Error(`Expected to be running in a browser`); + +const dotnetRuntime = await dotnet + .withDiagnosticTracing(false) + .withApplicationArgumentsFromQuery() + .create(); + +const config = dotnetRuntime.getConfig(); + +await dotnetRuntime.runMain(config.mainAssemblyName, [globalThis.location.href]); diff --git a/TournamentOrganizer.Desktop/Program.cs b/TournamentOrganizer.Desktop/Program.cs new file mode 100644 index 0000000..4141c24 --- /dev/null +++ b/TournamentOrganizer.Desktop/Program.cs @@ -0,0 +1,21 @@ +using System; +using Avalonia; + +namespace TournamentOrganizer.Desktop; + +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(); +} diff --git a/TournamentOrganizer.Desktop/TournamentOrganizer.Desktop.csproj b/TournamentOrganizer.Desktop/TournamentOrganizer.Desktop.csproj new file mode 100644 index 0000000..e7bb0af --- /dev/null +++ b/TournamentOrganizer.Desktop/TournamentOrganizer.Desktop.csproj @@ -0,0 +1,26 @@ + + + WinExe + + net10.0 + enable + + + + app.manifest + + + + + + + None + All + + + + + + + diff --git a/TournamentOrganizer.Desktop/app.manifest b/TournamentOrganizer.Desktop/app.manifest new file mode 100644 index 0000000..a167c85 --- /dev/null +++ b/TournamentOrganizer.Desktop/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/TournamentOrganizer.sln b/TournamentOrganizer.sln new file mode 100644 index 0000000..7ea1d73 --- /dev/null +++ b/TournamentOrganizer.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32811.315 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TournamentOrganizer", "TournamentOrganizer\TournamentOrganizer.csproj", "{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TournamentOrganizer.Desktop", "TournamentOrganizer.Desktop\TournamentOrganizer.Desktop.csproj", "{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TournamentOrganizer.Browser", "TournamentOrganizer.Browser\TournamentOrganizer.Browser.csproj", "{1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DA99C4E-89E3-4049-9C22-0A7EC60D83D8}" + ProjectSection(SolutionItems) = preProject + Directory.Packages.props = Directory.Packages.props + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.Build.0 = Release|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.Build.0 = Release|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Release|Any CPU.Build.0 = Release|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Release|Any CPU.Build.0 = Release|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E} + EndGlobalSection +EndGlobal diff --git a/TournamentOrganizer/App.axaml b/TournamentOrganizer/App.axaml new file mode 100644 index 0000000..803325b --- /dev/null +++ b/TournamentOrganizer/App.axaml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/TournamentOrganizer/App.axaml.cs b/TournamentOrganizer/App.axaml.cs new file mode 100644 index 0000000..e216cd9 --- /dev/null +++ b/TournamentOrganizer/App.axaml.cs @@ -0,0 +1,66 @@ +using System.Linq; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Data.Core; +using Avalonia.Data.Core.Plugins; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using Microsoft.EntityFrameworkCore; +using TournamentOrganizer.ViewModels; +using TournamentOrganizer.Views; + +namespace TournamentOrganizer; + +public partial class App : Application +{ + + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // Avoid duplicate validations from both Avalonia and the CommunityToolkit. + // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins + DisableAvaloniaDataAnnotationValidation(); + desktop.MainWindow = new MainWindow + { + DataContext = new MainViewModel() + }; + } + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = new MainView + { + DataContext = new MainViewModel() + }; + } + + Dispatcher.UIThread.Post(async () => await ApplyDatabaseMigrations()); + + base.OnFrameworkInitializationCompleted(); + } + + private async Task ApplyDatabaseMigrations() + { + using var context = new TournamentContext(); + await context.Database.MigrateAsync(); + } + + private void DisableAvaloniaDataAnnotationValidation() + { + // Get an array of plugins to remove + var dataValidationPluginsToRemove = + BindingPlugins.DataValidators.OfType().ToArray(); + + // remove each entry found + foreach (var plugin in dataValidationPluginsToRemove) + { + BindingPlugins.DataValidators.Remove(plugin); + } + } +} \ No newline at end of file diff --git a/TournamentOrganizer/Assets/avalonia-logo.ico b/TournamentOrganizer/Assets/avalonia-logo.ico new file mode 100644 index 0000000..f7da8bb Binary files /dev/null and b/TournamentOrganizer/Assets/avalonia-logo.ico differ diff --git a/TournamentOrganizer/Database/TournamentContext.cs b/TournamentOrganizer/Database/TournamentContext.cs new file mode 100644 index 0000000..486f4a3 --- /dev/null +++ b/TournamentOrganizer/Database/TournamentContext.cs @@ -0,0 +1,40 @@ +using System; +using System.IO; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using TournamentOrganizer.Models; + +namespace TournamentOrganizer; + +public class TournamentContext : DbContext +{ + public DbSet Events { get; set; } + public DbSet Games { get; set; } + public DbSet Matches { get; set; } + public DbSet TeamParticipants { get; set; } + public DbSet PlayerParticipants { get; set; } + public DbSet Players { get; set; } + public DbSet Rounds { get; set; } + public DbSet Teams { get; set; } + public DbSet Tournaments { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + string datadir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TournamentOrganizer"); + Directory.CreateDirectory(datadir); + string dbfile = Path.Combine(datadir, "sqlite.db"); + optionsBuilder.UseSqlite(new SqliteConnectionStringBuilder() + { + DataSource = dbfile, + Mode = SqliteOpenMode.ReadWriteCreate, + ForeignKeys = true, + RecursiveTriggers = true + }.ToString()); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + } + +} diff --git a/TournamentOrganizer/Migrations/20260409072947_InitialEvent.Designer.cs b/TournamentOrganizer/Migrations/20260409072947_InitialEvent.Designer.cs new file mode 100644 index 0000000..daa73c8 --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409072947_InitialEvent.Designer.cs @@ -0,0 +1,46 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TournamentOrganizer; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + [DbContext(typeof(TournamentContext))] + [Migration("20260409072947_InitialEvent")] + partial class InitialEvent + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.5"); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EventEnd") + .HasColumnType("TEXT"); + + b.Property("EventStart") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Events"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409072947_InitialEvent.cs b/TournamentOrganizer/Migrations/20260409072947_InitialEvent.cs new file mode 100644 index 0000000..83fe20e --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409072947_InitialEvent.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + /// + public partial class InitialEvent : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Events", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: false), + EventStart = table.Column(type: "TEXT", nullable: false), + EventEnd = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Events", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Events"); + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409082427_InitialDataModel.Designer.cs b/TournamentOrganizer/Migrations/20260409082427_InitialDataModel.Designer.cs new file mode 100644 index 0000000..43c5345 --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409082427_InitialDataModel.Designer.cs @@ -0,0 +1,315 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TournamentOrganizer; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + [DbContext(typeof(TournamentContext))] + [Migration("20260409082427_InitialDataModel")] + partial class InitialDataModel + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.5"); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EventEnd") + .HasColumnType("TEXT"); + + b.Property("EventStart") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TournamentId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TournamentId"); + + b.ToTable("Matches"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.Property("RoundId") + .HasColumnType("INTEGER"); + + b.Property("PlayerId") + .HasColumnType("INTEGER"); + + b.HasKey("RoundId", "PlayerId"); + + b.HasIndex("PlayerId"); + + b.ToTable("PlayerParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("WinnerId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MatchId"); + + b.ToTable("Rounds"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.Property("Seed") + .HasColumnType("INTEGER"); + + b.HasKey("MatchId", "TeamId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("GameId") + .HasColumnType("INTEGER"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.HasIndex("GameId"); + + b.ToTable("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament") + .WithMany() + .HasForeignKey("TournamentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tournament"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Players") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Match") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Match"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Round") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Matches") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Round"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.HasOne("TournamentOrganizer.Models.Event", "Event") + .WithMany("Tournaments") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Game", "Game") + .WithMany("Tournaments") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + + b.Navigation("Game"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Navigation("Matches"); + + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409082427_InitialDataModel.cs b/TournamentOrganizer/Migrations/20260409082427_InitialDataModel.cs new file mode 100644 index 0000000..26879f5 --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409082427_InitialDataModel.cs @@ -0,0 +1,244 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + /// + public partial class InitialDataModel : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Games", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: false), + Description = table.Column(type: "TEXT", nullable: false), + S1RuleSet = table.Column(type: "INTEGER", nullable: false), + S2RuleSet = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Games", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Teams", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Teams", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Tournaments", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + GameId = table.Column(type: "INTEGER", nullable: false), + EventId = table.Column(type: "INTEGER", nullable: false), + S1RuleSet = table.Column(type: "INTEGER", nullable: false), + S2RuleSet = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Tournaments", x => x.Id); + table.ForeignKey( + name: "FK_Tournaments_Events_EventId", + column: x => x.EventId, + principalTable: "Events", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Tournaments_Games_GameId", + column: x => x.GameId, + principalTable: "Games", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Players", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: false), + Contact = table.Column(type: "TEXT", nullable: false), + TeamId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Players", x => x.Id); + table.ForeignKey( + name: "FK_Players_Teams_TeamId", + column: x => x.TeamId, + principalTable: "Teams", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Matches", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + TournamentId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Matches", x => x.Id); + table.ForeignKey( + name: "FK_Matches_Tournaments_TournamentId", + column: x => x.TournamentId, + principalTable: "Tournaments", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Rounds", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + MatchId = table.Column(type: "INTEGER", nullable: false), + WinnerId = table.Column(type: "INTEGER", nullable: true), + State = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Rounds", x => x.Id); + table.ForeignKey( + name: "FK_Rounds_Matches_MatchId", + column: x => x.MatchId, + principalTable: "Matches", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TeamParticipants", + columns: table => new + { + MatchId = table.Column(type: "INTEGER", nullable: false), + TeamId = table.Column(type: "INTEGER", nullable: false), + Seed = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TeamParticipants", x => new { x.MatchId, x.TeamId }); + table.ForeignKey( + name: "FK_TeamParticipants_Matches_MatchId", + column: x => x.MatchId, + principalTable: "Matches", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TeamParticipants_Teams_TeamId", + column: x => x.TeamId, + principalTable: "Teams", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PlayerParticipants", + columns: table => new + { + RoundId = table.Column(type: "INTEGER", nullable: false), + PlayerId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PlayerParticipants", x => new { x.RoundId, x.PlayerId }); + table.ForeignKey( + name: "FK_PlayerParticipants_Players_PlayerId", + column: x => x.PlayerId, + principalTable: "Players", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PlayerParticipants_Rounds_RoundId", + column: x => x.RoundId, + principalTable: "Rounds", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Matches_TournamentId", + table: "Matches", + column: "TournamentId"); + + migrationBuilder.CreateIndex( + name: "IX_PlayerParticipants_PlayerId", + table: "PlayerParticipants", + column: "PlayerId"); + + migrationBuilder.CreateIndex( + name: "IX_Players_TeamId", + table: "Players", + column: "TeamId"); + + migrationBuilder.CreateIndex( + name: "IX_Rounds_MatchId", + table: "Rounds", + column: "MatchId"); + + migrationBuilder.CreateIndex( + name: "IX_TeamParticipants_TeamId", + table: "TeamParticipants", + column: "TeamId"); + + migrationBuilder.CreateIndex( + name: "IX_Tournaments_EventId", + table: "Tournaments", + column: "EventId"); + + migrationBuilder.CreateIndex( + name: "IX_Tournaments_GameId", + table: "Tournaments", + column: "GameId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PlayerParticipants"); + + migrationBuilder.DropTable( + name: "TeamParticipants"); + + migrationBuilder.DropTable( + name: "Players"); + + migrationBuilder.DropTable( + name: "Rounds"); + + migrationBuilder.DropTable( + name: "Teams"); + + migrationBuilder.DropTable( + name: "Matches"); + + migrationBuilder.DropTable( + name: "Tournaments"); + + migrationBuilder.DropTable( + name: "Games"); + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409083011_TournamentStartEnd.Designer.cs b/TournamentOrganizer/Migrations/20260409083011_TournamentStartEnd.Designer.cs new file mode 100644 index 0000000..ca63d02 --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409083011_TournamentStartEnd.Designer.cs @@ -0,0 +1,318 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TournamentOrganizer; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + [DbContext(typeof(TournamentContext))] + [Migration("20260409083011_TournamentStartEnd")] + partial class TournamentStartEnd + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.5"); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TournamentId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TournamentId"); + + b.ToTable("Matches"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.Property("RoundId") + .HasColumnType("INTEGER"); + + b.Property("PlayerId") + .HasColumnType("INTEGER"); + + b.HasKey("RoundId", "PlayerId"); + + b.HasIndex("PlayerId"); + + b.ToTable("PlayerParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MatchId"); + + b.ToTable("Rounds"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.Property("Seed") + .HasColumnType("INTEGER"); + + b.HasKey("MatchId", "TeamId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("GameId") + .HasColumnType("INTEGER"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.HasIndex("GameId"); + + b.ToTable("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament") + .WithMany() + .HasForeignKey("TournamentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tournament"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Players") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Match") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Match"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Round") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Matches") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Round"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.HasOne("TournamentOrganizer.Models.Event", "Event") + .WithMany("Tournaments") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Game", "Game") + .WithMany("Tournaments") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + + b.Navigation("Game"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Navigation("Matches"); + + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409083011_TournamentStartEnd.cs b/TournamentOrganizer/Migrations/20260409083011_TournamentStartEnd.cs new file mode 100644 index 0000000..c8b0d41 --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409083011_TournamentStartEnd.cs @@ -0,0 +1,71 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + /// + public partial class TournamentStartEnd : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "WinnerId", + table: "Rounds"); + + migrationBuilder.RenameColumn( + name: "EventStart", + table: "Events", + newName: "Start"); + + migrationBuilder.RenameColumn( + name: "EventEnd", + table: "Events", + newName: "End"); + + migrationBuilder.AddColumn( + name: "End", + table: "Tournaments", + type: "TEXT", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "Start", + table: "Tournaments", + type: "TEXT", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "End", + table: "Tournaments"); + + migrationBuilder.DropColumn( + name: "Start", + table: "Tournaments"); + + migrationBuilder.RenameColumn( + name: "Start", + table: "Events", + newName: "EventStart"); + + migrationBuilder.RenameColumn( + name: "End", + table: "Events", + newName: "EventEnd"); + + migrationBuilder.AddColumn( + name: "WinnerId", + table: "Rounds", + type: "INTEGER", + nullable: true); + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409083129_TeamParticipantScore.Designer.cs b/TournamentOrganizer/Migrations/20260409083129_TeamParticipantScore.Designer.cs new file mode 100644 index 0000000..4b297cc --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409083129_TeamParticipantScore.Designer.cs @@ -0,0 +1,321 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TournamentOrganizer; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + [DbContext(typeof(TournamentContext))] + [Migration("20260409083129_TeamParticipantScore")] + partial class TeamParticipantScore + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.5"); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TournamentId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TournamentId"); + + b.ToTable("Matches"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.Property("RoundId") + .HasColumnType("INTEGER"); + + b.Property("PlayerId") + .HasColumnType("INTEGER"); + + b.HasKey("RoundId", "PlayerId"); + + b.HasIndex("PlayerId"); + + b.ToTable("PlayerParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MatchId"); + + b.ToTable("Rounds"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.Property("Seed") + .HasColumnType("INTEGER"); + + b.HasKey("MatchId", "TeamId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("GameId") + .HasColumnType("INTEGER"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.HasIndex("GameId"); + + b.ToTable("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament") + .WithMany() + .HasForeignKey("TournamentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tournament"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Players") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Match") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Match"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Round") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Matches") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Round"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.HasOne("TournamentOrganizer.Models.Event", "Event") + .WithMany("Tournaments") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Game", "Game") + .WithMany("Tournaments") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + + b.Navigation("Game"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Navigation("Matches"); + + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TournamentOrganizer/Migrations/20260409083129_TeamParticipantScore.cs b/TournamentOrganizer/Migrations/20260409083129_TeamParticipantScore.cs new file mode 100644 index 0000000..9b1a912 --- /dev/null +++ b/TournamentOrganizer/Migrations/20260409083129_TeamParticipantScore.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + /// + public partial class TeamParticipantScore : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Score", + table: "TeamParticipants", + type: "INTEGER", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Score", + table: "TeamParticipants"); + } + } +} diff --git a/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs b/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs new file mode 100644 index 0000000..ee727db --- /dev/null +++ b/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs @@ -0,0 +1,318 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TournamentOrganizer; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + [DbContext(typeof(TournamentContext))] + partial class TournamentContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.5"); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("TournamentId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TournamentId"); + + b.ToTable("Matches"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.Property("RoundId") + .HasColumnType("INTEGER"); + + b.Property("PlayerId") + .HasColumnType("INTEGER"); + + b.HasKey("RoundId", "PlayerId"); + + b.HasIndex("PlayerId"); + + b.ToTable("PlayerParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MatchId"); + + b.ToTable("Rounds"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.Property("MatchId") + .HasColumnType("INTEGER"); + + b.Property("TeamId") + .HasColumnType("INTEGER"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.Property("Seed") + .HasColumnType("INTEGER"); + + b.HasKey("MatchId", "TeamId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamParticipants"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("EventId") + .HasColumnType("INTEGER"); + + b.Property("GameId") + .HasColumnType("INTEGER"); + + b.Property("S1RuleSet") + .HasColumnType("INTEGER"); + + b.Property("S2RuleSet") + .HasColumnType("INTEGER"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventId"); + + b.HasIndex("GameId"); + + b.ToTable("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Match", b => + { + b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament") + .WithMany() + .HasForeignKey("TournamentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tournament"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Player", b => + { + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Players") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Round", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Match") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Match"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b => + { + b.HasOne("TournamentOrganizer.Models.Match", "Round") + .WithMany() + .HasForeignKey("MatchId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Team", "Team") + .WithMany("Matches") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Round"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b => + { + b.HasOne("TournamentOrganizer.Models.Event", "Event") + .WithMany("Tournaments") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("TournamentOrganizer.Models.Game", "Game") + .WithMany("Tournaments") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + + b.Navigation("Game"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Event", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Game", b => + { + b.Navigation("Tournaments"); + }); + + modelBuilder.Entity("TournamentOrganizer.Models.Team", b => + { + b.Navigation("Matches"); + + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TournamentOrganizer/Models/Event.cs b/TournamentOrganizer/Models/Event.cs new file mode 100644 index 0000000..4104c39 --- /dev/null +++ b/TournamentOrganizer/Models/Event.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TournamentOrganizer.Models; + +public class Event +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public string Name { get; set; } = "Example Tournament"; + public DateTime Start { get; set; } + public DateTime End { get; set; } + + public required List Tournaments { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Game.cs b/TournamentOrganizer/Models/Game.cs new file mode 100644 index 0000000..2e6aed4 --- /dev/null +++ b/TournamentOrganizer/Models/Game.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TournamentOrganizer.Models; + +public enum RuleSet +{ + DoubleElimination, + SingleElimination, + RoundRobin, + Swiss +} + +public class Game +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public string Name { get; set; } = "Example Game"; + public string Description { get; set; } = "Example Game Description"; + + public RuleSet S1RuleSet { get; set; } + public int S1Groups; + public int S1GroupAdvances; + + public RuleSet? S2RuleSet { get; set; } + + public required List Tournaments { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Match.cs b/TournamentOrganizer/Models/Match.cs new file mode 100644 index 0000000..80b9507 --- /dev/null +++ b/TournamentOrganizer/Models/Match.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TournamentOrganizer.Models; + +public class Match +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public int TournamentId { get; set; } + + public required List Teams; + public required List Rounds; + public required Tournament Tournament { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Participant.cs b/TournamentOrganizer/Models/Participant.cs new file mode 100644 index 0000000..1251089 --- /dev/null +++ b/TournamentOrganizer/Models/Participant.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; + +namespace TournamentOrganizer.Models; + +[PrimaryKey(nameof(RoundId), nameof(PlayerId))] +public class PlayerParticipant +{ + public int RoundId { get; set; } + public int PlayerId { get; set; } + + public required Player Player { get; set; } + public required Round Round { get; set; } +} + + +public class TeamParticipant +{ + public int MatchId { get; set; } + public int TeamId { get; set; } + public int Seed { get; set; } + public int Score { get; set; } + + public required Team Team { get; set; } + public required Match Round { get; set; } +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Player.cs b/TournamentOrganizer/Models/Player.cs new file mode 100644 index 0000000..0dfa4e5 --- /dev/null +++ b/TournamentOrganizer/Models/Player.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TournamentOrganizer.Models; + +public class Player +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public string Name { get; set; } = "Example Tournament"; + public string Contact { get; set; } = "discordname"; + public int TeamId { get; set; } + + public required Team Team { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Round.cs b/TournamentOrganizer/Models/Round.cs new file mode 100644 index 0000000..2fabc44 --- /dev/null +++ b/TournamentOrganizer/Models/Round.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TournamentOrganizer.Models; + +public enum RoundState +{ + WAITING, + STARTED, + FINISHED +} + +public class Round +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public int MatchId { get; set; } + public RoundState State { get; set; } = RoundState.WAITING; + + public required List Players; + public required Match Match { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Team.cs b/TournamentOrganizer/Models/Team.cs new file mode 100644 index 0000000..5a066ff --- /dev/null +++ b/TournamentOrganizer/Models/Team.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace TournamentOrganizer.Models; + +public class Team +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public string Name { get; set; } = "Example Team"; + + public required List Players { get; set; } + public required List Matches { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/Models/Tournament.cs b/TournamentOrganizer/Models/Tournament.cs new file mode 100644 index 0000000..69077c0 --- /dev/null +++ b/TournamentOrganizer/Models/Tournament.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; + +namespace TournamentOrganizer.Models; + +public class Tournament +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public int GameId { get; set; } + public int EventId { get; set; } + public DateTime Start { get; set; } + public DateTime End { get; set; } + + public RuleSet S1RuleSet { get; set; } + public int S1Groups; + public int S1GroupAdvances; + public RuleSet? S2RuleSet { get; set; } + + public required Game Game { get; set; } + public required Event Event { get; set; } + +} \ No newline at end of file diff --git a/TournamentOrganizer/TournamentOrganizer.csproj b/TournamentOrganizer/TournamentOrganizer.csproj new file mode 100644 index 0000000..dcb2473 --- /dev/null +++ b/TournamentOrganizer/TournamentOrganizer.csproj @@ -0,0 +1,29 @@ + + + net10.0 + enable + latest + true + + + + + + + + + + + + + None + All + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/TournamentOrganizer/ViewLocator.cs b/TournamentOrganizer/ViewLocator.cs new file mode 100644 index 0000000..3411c56 --- /dev/null +++ b/TournamentOrganizer/ViewLocator.cs @@ -0,0 +1,37 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using TournamentOrganizer.ViewModels; + +namespace TournamentOrganizer; + +/// +/// Given a view model, returns the corresponding view if possible. +/// +[RequiresUnreferencedCode( + "Default implementation of ViewLocator involves reflection which may be trimmed away.", + Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")] +public class ViewLocator : IDataTemplate +{ + public Control? Build(object? param) + { + if (param is null) + return null; + + var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); + var type = Type.GetType(name); + + if (type != null) + { + return (Control)Activator.CreateInstance(type)!; + } + + return new TextBlock { Text = "Not Found: " + name }; + } + + public bool Match(object? data) + { + return data is ViewModelBase; + } +} \ No newline at end of file diff --git a/TournamentOrganizer/ViewModels/MainViewModel.cs b/TournamentOrganizer/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..915baff --- /dev/null +++ b/TournamentOrganizer/ViewModels/MainViewModel.cs @@ -0,0 +1,9 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace TournamentOrganizer.ViewModels; + +public partial class MainViewModel : ViewModelBase +{ + [ObservableProperty] + private string _greeting = "Welcome to Avalonia!"; +} diff --git a/TournamentOrganizer/ViewModels/ViewModelBase.cs b/TournamentOrganizer/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..62dfdfd --- /dev/null +++ b/TournamentOrganizer/ViewModels/ViewModelBase.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace TournamentOrganizer.ViewModels; + +public abstract class ViewModelBase : ObservableObject +{ +} diff --git a/TournamentOrganizer/Views/MainView.axaml b/TournamentOrganizer/Views/MainView.axaml new file mode 100644 index 0000000..f3d9668 --- /dev/null +++ b/TournamentOrganizer/Views/MainView.axaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/TournamentOrganizer/Views/MainView.axaml.cs b/TournamentOrganizer/Views/MainView.axaml.cs new file mode 100644 index 0000000..8c27917 --- /dev/null +++ b/TournamentOrganizer/Views/MainView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace TournamentOrganizer.Views; + +public partial class MainView : UserControl +{ + public MainView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/TournamentOrganizer/Views/MainWindow.axaml b/TournamentOrganizer/Views/MainWindow.axaml new file mode 100644 index 0000000..925ca4a --- /dev/null +++ b/TournamentOrganizer/Views/MainWindow.axaml @@ -0,0 +1,12 @@ + + + diff --git a/TournamentOrganizer/Views/MainWindow.axaml.cs b/TournamentOrganizer/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..e8f8f0e --- /dev/null +++ b/TournamentOrganizer/Views/MainWindow.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace TournamentOrganizer.Views; + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/dotnet-tools.json b/dotnet-tools.json new file mode 100644 index 0000000..b6f4c2f --- /dev/null +++ b/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "10.0.5", + "commands": [ + "dotnet-ef" + ], + "rollForward": false + } + } +} \ No newline at end of file