Tournament management
This commit is contained in:
@@ -17,6 +17,7 @@ public class TournamentContext : DbContext
|
|||||||
public DbSet<Round> Rounds { get; set; }
|
public DbSet<Round> Rounds { get; set; }
|
||||||
public DbSet<Team> Teams { get; set; }
|
public DbSet<Team> Teams { get; set; }
|
||||||
public DbSet<Tournament> Tournaments { get; set; }
|
public DbSet<Tournament> Tournaments { get; set; }
|
||||||
|
public DbSet<TournamentTeam> TournamentTeams { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
@@ -41,6 +42,18 @@ public class TournamentContext : DbContext
|
|||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey(t => t.LeaderId)
|
.HasForeignKey(t => t.LeaderId)
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TournamentTeam>()
|
||||||
|
.HasOne(tt => tt.Tournament)
|
||||||
|
.WithMany(t => t.TournamentTeams)
|
||||||
|
.HasForeignKey(tt => tt.TournamentId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TournamentTeam>()
|
||||||
|
.HasOne(tt => tt.Team)
|
||||||
|
.WithMany(t => t.TournamentTeams)
|
||||||
|
.HasForeignKey(tt => tt.TeamId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+392
@@ -0,0 +1,392 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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("20260506083354_AddTournamentTeam")]
|
||||||
|
partial class AddTournamentTeam
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Events");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Games");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
b.ToTable("Matches");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Contact")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RoundId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("RoundId", "PlayerId");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId");
|
||||||
|
|
||||||
|
b.ToTable("PlayerParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MatchId");
|
||||||
|
|
||||||
|
b.ToTable("Rounds");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LeaderId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LeaderId");
|
||||||
|
|
||||||
|
b.ToTable("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("MatchId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TeamParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EventId");
|
||||||
|
|
||||||
|
b.HasIndex("GameId");
|
||||||
|
|
||||||
|
b.ToTable("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("TournamentId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
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.Team", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Leader")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LeaderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Leader");
|
||||||
|
});
|
||||||
|
|
||||||
|
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.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddTournamentTeam : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TournamentTeams",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
TournamentId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
TeamId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Seed = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TournamentTeams", x => new { x.TournamentId, x.TeamId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TournamentTeams_Teams_TeamId",
|
||||||
|
column: x => x.TeamId,
|
||||||
|
principalTable: "Teams",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TournamentTeams_Tournaments_TournamentId",
|
||||||
|
column: x => x.TournamentId,
|
||||||
|
principalTable: "Tournaments",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TournamentTeams_TeamId",
|
||||||
|
table: "TournamentTeams",
|
||||||
|
column: "TeamId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TournamentTeams");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -223,6 +223,24 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.ToTable("Tournaments");
|
b.ToTable("Tournaments");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("TournamentId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
@@ -323,6 +341,25 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.Navigation("Game");
|
b.Navigation("Game");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Tournaments");
|
b.Navigation("Tournaments");
|
||||||
@@ -338,6 +375,13 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.Navigation("Matches");
|
b.Navigation("Matches");
|
||||||
|
|
||||||
b.Navigation("Players");
|
b.Navigation("Players");
|
||||||
|
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ public class Event
|
|||||||
public DateTime Start { get; set; }
|
public DateTime Start { get; set; }
|
||||||
public DateTime End { get; set; }
|
public DateTime End { get; set; }
|
||||||
|
|
||||||
public required List<Tournament> Tournaments { get; set; }
|
public List<Tournament> Tournaments { get; set; } = [];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -47,6 +47,6 @@ public class Game
|
|||||||
|
|
||||||
public RuleSet? S2RuleSet { get; set; }
|
public RuleSet? S2RuleSet { get; set; }
|
||||||
|
|
||||||
public required List<Tournament> Tournaments { get; set; }
|
public List<Tournament> Tournaments { get; set; } = [];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,8 @@ public class Match
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int TournamentId { get; set; }
|
public int TournamentId { get; set; }
|
||||||
|
|
||||||
public required List<TeamParticipant> Teams;
|
public List<TeamParticipant> Teams { get; set; } = [];
|
||||||
public required List<Round> Rounds;
|
public List<Round> Rounds { get; set; } = [];
|
||||||
public required Tournament Tournament { get; set; }
|
public Tournament Tournament { get; set; } = null!;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,9 +7,8 @@ public class PlayerParticipant
|
|||||||
{
|
{
|
||||||
public int RoundId { get; set; }
|
public int RoundId { get; set; }
|
||||||
public int PlayerId { get; set; }
|
public int PlayerId { get; set; }
|
||||||
|
public Player Player { get; set; } = null!;
|
||||||
public required Player Player { get; set; }
|
public Round Round { get; set; } = null!;
|
||||||
public required Round Round { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrimaryKey(nameof(MatchId), nameof(TeamId))]
|
[PrimaryKey(nameof(MatchId), nameof(TeamId))]
|
||||||
@@ -19,7 +18,16 @@ public class TeamParticipant
|
|||||||
public int TeamId { get; set; }
|
public int TeamId { get; set; }
|
||||||
public int Seed { get; set; }
|
public int Seed { get; set; }
|
||||||
public int Score { get; set; }
|
public int Score { get; set; }
|
||||||
|
public Team Team { get; set; } = null!;
|
||||||
|
public Match Round { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
public required Team Team { get; set; }
|
[PrimaryKey(nameof(TournamentId), nameof(TeamId))]
|
||||||
public required Match Round { get; set; }
|
public class TournamentTeam
|
||||||
}
|
{
|
||||||
|
public int TournamentId { get; set; }
|
||||||
|
public int TeamId { get; set; }
|
||||||
|
public int Seed { get; set; }
|
||||||
|
public Tournament Tournament { get; set; } = null!;
|
||||||
|
public Team Team { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ public class Player
|
|||||||
public string Contact { get; set; } = "discordname";
|
public string Contact { get; set; } = "discordname";
|
||||||
public int TeamId { get; set; }
|
public int TeamId { get; set; }
|
||||||
|
|
||||||
public required Team Team { get; set; }
|
public Team Team { get; set; } = null!;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ public class Round
|
|||||||
public int MatchId { get; set; }
|
public int MatchId { get; set; }
|
||||||
public RoundState State { get; set; } = RoundState.Waiting;
|
public RoundState State { get; set; } = RoundState.Waiting;
|
||||||
|
|
||||||
public required List<PlayerParticipant> Players;
|
public List<PlayerParticipant> Players { get; set; } = [];
|
||||||
public required Match Match { get; set; }
|
public Match Match { get; set; } = null!;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,8 @@ public class Team
|
|||||||
public int? LeaderId { get; set; }
|
public int? LeaderId { get; set; }
|
||||||
public Player? Leader { get; set; }
|
public Player? Leader { get; set; }
|
||||||
|
|
||||||
public required List<Player> Players { get; set; }
|
public List<Player> Players { get; set; } = [];
|
||||||
public required List<TeamParticipant> Matches { get; set; }
|
public List<TeamParticipant> Matches { get; set; } = [];
|
||||||
|
public List<TournamentTeam> TournamentTeams { get; set; } = [];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@@ -21,8 +22,9 @@ public class Tournament
|
|||||||
public int? S1GroupAdvances { get; set; }
|
public int? S1GroupAdvances { get; set; }
|
||||||
public RuleSet? S2RuleSet { get; set; }
|
public RuleSet? S2RuleSet { get; set; }
|
||||||
|
|
||||||
public required Game Game { get; set; }
|
public Game Game { get; set; } = null!;
|
||||||
public required Event Event { get; set; }
|
public Event Event { get; set; } = null!;
|
||||||
|
public List<TournamentTeam> TournamentTeams { get; set; } = [];
|
||||||
|
|
||||||
public static ValidationResult ValidateDates(DateTime date, ValidationContext context)
|
public static ValidationResult ValidateDates(DateTime date, ValidationContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
Title = "Events Management";
|
Title = "Events Management";
|
||||||
await eventsVm.LoadEvents();
|
await eventsVm.LoadEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task NavigateToTournaments()
|
||||||
|
{
|
||||||
|
var tournamentsVm = new TournamentsViewModel();
|
||||||
|
CurrentView = tournamentsVm;
|
||||||
|
Title = "Tournament Management";
|
||||||
|
await tournamentsVm.LoadTournaments();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class HomeViewModel : ViewModelBase
|
public partial class HomeViewModel : ViewModelBase
|
||||||
|
|||||||
@@ -137,14 +137,14 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
UpdateFilteredEvents();
|
UpdateFilteredEvents();
|
||||||
|
|
||||||
var games = await _context.Games.ToListAsync();
|
var tournaments = await _context.Tournaments
|
||||||
|
.Include(t => t.Game)
|
||||||
|
.Include(t => t.Event)
|
||||||
|
.ToListAsync();
|
||||||
AvailableTournaments.Clear();
|
AvailableTournaments.Clear();
|
||||||
foreach (var g in games)
|
foreach (var t in tournaments)
|
||||||
{
|
{
|
||||||
foreach (var e in events)
|
AvailableTournaments.Add(GetTournamentDisplayName(t));
|
||||||
{
|
|
||||||
AvailableTournaments.Add($"{g.Name} @ {e.Name}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UpdateFilteredTournaments();
|
UpdateFilteredTournaments();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,807 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TournamentOrganizer.Models;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
public partial class TournamentsViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly TournamentContext _context;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<EventOption> _availableEvents = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private EventOption? _selectedEvent;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TournamentOption> _availableTournaments = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private TournamentOption? _selectedTournament;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private DateTime _tournamentStart;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private DateTime _tournamentEnd;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private RuleSetOption? _selectedS1RuleSet;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int? _s1Groups;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int? _s1GroupAdvances;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private RuleSetOption? _selectedS2RuleSet;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TeamOption> _availableTeams = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<ParticipatingTeam> _participatingTeams = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private TeamOption? _selectedTeamToAdd;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ParticipatingTeam? _selectedParticipatingTeam;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<MatchDisplay> _matches = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private MatchDisplay? _selectedMatch;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _eventFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _tournamentFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEventDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isTournamentDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEditing;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _statusMessage = string.Empty;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<EventOption> _filteredEvents = [];
|
||||||
|
public ObservableCollection<EventOption> FilteredEvents => _filteredEvents;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<TournamentOption> _filteredTournaments = [];
|
||||||
|
public ObservableCollection<TournamentOption> FilteredTournaments => _filteredTournaments;
|
||||||
|
|
||||||
|
public ObservableCollection<RuleSetOption> S1RuleSetOptions { get; } = [];
|
||||||
|
public ObservableCollection<RuleSetOption> S2RuleSetOptions { get; } = [new RuleSetOption(null, "(None)")];
|
||||||
|
|
||||||
|
public bool IsTournamentFilterEnabled => SelectedEvent != null;
|
||||||
|
|
||||||
|
public TournamentsViewModel()
|
||||||
|
{
|
||||||
|
_context = new TournamentContext();
|
||||||
|
foreach (var rs in Enum.GetValues<RuleSet>())
|
||||||
|
{
|
||||||
|
S1RuleSetOptions.Add(new RuleSetOption(rs, rs.ToDisplayName()));
|
||||||
|
S2RuleSetOptions.Add(new RuleSetOption(rs, rs.ToDisplayName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnEventFilterSearchChanged(string value) => UpdateFilteredEvents();
|
||||||
|
partial void OnSelectedEventChanged(EventOption? value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsTournamentFilterEnabled));
|
||||||
|
UpdateAvailableTournaments();
|
||||||
|
UpdateFilteredTournaments();
|
||||||
|
SelectedTournament = null;
|
||||||
|
Matches.Clear();
|
||||||
|
ParticipatingTeams.Clear();
|
||||||
|
IsEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedTournamentChanged(TournamentOption? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
IsEditing = false;
|
||||||
|
Matches.Clear();
|
||||||
|
ParticipatingTeams.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TournamentStart = value.Tournament.Start;
|
||||||
|
TournamentEnd = value.Tournament.End;
|
||||||
|
SelectedS1RuleSet = S1RuleSetOptions.FirstOrDefault(o => o.Value == value.Tournament.S1RuleSet);
|
||||||
|
S1Groups = value.Tournament.S1Groups;
|
||||||
|
S1GroupAdvances = value.Tournament.S1GroupAdvances;
|
||||||
|
SelectedS2RuleSet = S2RuleSetOptions.FirstOrDefault(o => o.Value == value.Tournament.S2RuleSet);
|
||||||
|
IsEditing = true;
|
||||||
|
|
||||||
|
LoadTournamentDetails();
|
||||||
|
_ = LoadMatches();
|
||||||
|
StatusMessage = $"Editing tournament: {value.Tournament.Game.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedS1RuleSetChanged(RuleSetOption? value)
|
||||||
|
{
|
||||||
|
_ = RegenerateMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedS2RuleSetChanged(RuleSetOption? value)
|
||||||
|
{
|
||||||
|
if (value?.Value == null)
|
||||||
|
{
|
||||||
|
S1Groups = null;
|
||||||
|
S1GroupAdvances = null;
|
||||||
|
}
|
||||||
|
_ = RegenerateMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnTournamentFilterSearchChanged(string value) => UpdateFilteredTournaments();
|
||||||
|
|
||||||
|
private void UpdateFilteredEvents()
|
||||||
|
{
|
||||||
|
_filteredEvents.Clear();
|
||||||
|
foreach (var e in AvailableEvents.Where(e => string.IsNullOrWhiteSpace(EventFilterSearch) || e.DisplayName.ToLower().Contains(EventFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredEvents.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFilteredTournaments()
|
||||||
|
{
|
||||||
|
_filteredTournaments.Clear();
|
||||||
|
foreach (var t in AvailableTournaments.Where(t => string.IsNullOrWhiteSpace(TournamentFilterSearch) || t.DisplayName.ToLower().Contains(TournamentFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredTournaments.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectEventFilter(EventOption option)
|
||||||
|
{
|
||||||
|
SelectedEvent = option;
|
||||||
|
IsEventDropdownOpen = false;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearEventFilter()
|
||||||
|
{
|
||||||
|
SelectedEvent = null;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectTournamentFilter(TournamentOption option)
|
||||||
|
{
|
||||||
|
SelectedTournament = option;
|
||||||
|
IsTournamentDropdownOpen = false;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearTournamentFilter()
|
||||||
|
{
|
||||||
|
SelectedTournament = null;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadTournaments()
|
||||||
|
{
|
||||||
|
var events = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.ThenInclude(t => t.Game)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
AvailableEvents.Clear();
|
||||||
|
_filteredEvents.Clear();
|
||||||
|
foreach (var e in events)
|
||||||
|
{
|
||||||
|
var option = new EventOption(e);
|
||||||
|
AvailableEvents.Add(option);
|
||||||
|
_filteredEvents.Add(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAvailableTournaments();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAvailableTournaments()
|
||||||
|
{
|
||||||
|
AvailableTournaments.Clear();
|
||||||
|
if (SelectedEvent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in SelectedEvent.Event.Tournaments)
|
||||||
|
{
|
||||||
|
AvailableTournaments.Add(new TournamentOption(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadTournamentDetails()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournamentTeams = await _context.TournamentTeams
|
||||||
|
.Include(tt => tt.Team)
|
||||||
|
.ThenInclude(t => t.Players)
|
||||||
|
.Where(tt => tt.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
ParticipatingTeams.Clear();
|
||||||
|
foreach (var tt in tournamentTeams)
|
||||||
|
{
|
||||||
|
ParticipatingTeams.Add(new ParticipatingTeam(tt));
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedParticipatingTeam = null;
|
||||||
|
|
||||||
|
var allTeams = await _context.Teams
|
||||||
|
.Include(t => t.Players)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var participatingIds = ParticipatingTeams.Select(pt => pt.TeamId).ToHashSet();
|
||||||
|
AvailableTeams.Clear();
|
||||||
|
foreach (var team in allTeams)
|
||||||
|
{
|
||||||
|
if (!participatingIds.Contains(team.Id))
|
||||||
|
{
|
||||||
|
AvailableTeams.Add(new TeamOption(team));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedTeamToAdd = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMatches()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var matches = await _context.Matches
|
||||||
|
.Where(m => m.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.Include(m => m.Teams)
|
||||||
|
.ThenInclude(tp => tp.Team)
|
||||||
|
.Include(m => m.Rounds)
|
||||||
|
.ThenInclude(r => r.Players)
|
||||||
|
.ThenInclude(pp => pp.Player)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
Matches.Clear();
|
||||||
|
foreach (var match in matches)
|
||||||
|
{
|
||||||
|
Matches.Add(new MatchDisplay(match));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task SaveTournament()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a tournament to edit";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournament = await _context.Tournaments.FirstOrDefaultAsync(t => t.Id == SelectedTournament.Tournament.Id);
|
||||||
|
if (tournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Tournament not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tournament.Start = TournamentStart;
|
||||||
|
tournament.End = TournamentEnd;
|
||||||
|
tournament.S1RuleSet = SelectedS1RuleSet?.Value ?? tournament.S1RuleSet;
|
||||||
|
tournament.S1Groups = S1Groups;
|
||||||
|
tournament.S1GroupAdvances = S1GroupAdvances;
|
||||||
|
tournament.S2RuleSet = SelectedS2RuleSet?.Value;
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = "Tournament updated";
|
||||||
|
await LoadTournaments();
|
||||||
|
|
||||||
|
SelectedTournament = AvailableTournaments.FirstOrDefault(t => t.Tournament.Id == tournament.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task AddTeamToTournament()
|
||||||
|
{
|
||||||
|
if (SelectedTeamToAdd == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a team to add";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a tournament first";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournamentTeams = await _context.TournamentTeams
|
||||||
|
.Where(tt => tt.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (tournamentTeams.Any(tt => tt.TeamId == SelectedTeamToAdd.Team.Id))
|
||||||
|
{
|
||||||
|
StatusMessage = "Team is already in this tournament";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seed = tournamentTeams.Count + 1;
|
||||||
|
var tournamentTeam = new TournamentTeam
|
||||||
|
{
|
||||||
|
TournamentId = SelectedTournament.Tournament.Id,
|
||||||
|
TeamId = SelectedTeamToAdd.Team.Id,
|
||||||
|
Seed = seed,
|
||||||
|
Tournament = SelectedTournament.Tournament,
|
||||||
|
Team = SelectedTeamToAdd.Team
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.TournamentTeams.Add(tournamentTeam);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Added '{SelectedTeamToAdd.Team.Name}' to tournament";
|
||||||
|
|
||||||
|
await LoadTournamentDetails();
|
||||||
|
await RegenerateMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task RemoveTeamFromTournament()
|
||||||
|
{
|
||||||
|
if (SelectedParticipatingTeam == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a team to remove";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a tournament first";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournamentTeam = await _context.TournamentTeams
|
||||||
|
.FirstOrDefaultAsync(tt => tt.TournamentId == SelectedTournament.Tournament.Id && tt.TeamId == SelectedParticipatingTeam.TeamId);
|
||||||
|
|
||||||
|
if (tournamentTeam != null)
|
||||||
|
{
|
||||||
|
_context.TournamentTeams.Remove(tournamentTeam);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Removed '{SelectedParticipatingTeam.Name}' from tournament";
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadTournamentDetails();
|
||||||
|
await RegenerateMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task ReseedTeams()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a tournament first";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournamentTeams = await _context.TournamentTeams
|
||||||
|
.Where(tt => tt.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (tournamentTeams.Count < 2)
|
||||||
|
{
|
||||||
|
StatusMessage = "Need at least 2 teams to reseed";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rng = new Random();
|
||||||
|
var shuffled = tournamentTeams.OrderBy(_ => rng.Next()).ToList();
|
||||||
|
|
||||||
|
for (int i = 0; i < shuffled.Count; i++)
|
||||||
|
{
|
||||||
|
shuffled[i].Seed = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = "Teams reseeded";
|
||||||
|
await LoadTournamentDetails();
|
||||||
|
await RegenerateMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RegenerateMatches()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournamentTeams = await _context.TournamentTeams
|
||||||
|
.Include(tt => tt.Team)
|
||||||
|
.Where(tt => tt.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.OrderBy(tt => tt.Seed)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var existingMatches = await _context.Matches
|
||||||
|
.Where(m => m.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (existingMatches.Count > 0)
|
||||||
|
{
|
||||||
|
_context.Matches.RemoveRange(existingMatches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tournamentTeams.Count < 2)
|
||||||
|
{
|
||||||
|
Matches.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournament = await _context.Tournaments.FindAsync(SelectedTournament.Tournament.Id);
|
||||||
|
if (tournament == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var participants = tournamentTeams.Select(tt => new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = tt.TeamId,
|
||||||
|
Team = tt.Team,
|
||||||
|
Seed = tt.Seed,
|
||||||
|
Score = 0,
|
||||||
|
MatchId = 0,
|
||||||
|
Round = null!
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
var ruleSet = tournament.S2RuleSet ?? tournament.S1RuleSet;
|
||||||
|
|
||||||
|
switch (ruleSet)
|
||||||
|
{
|
||||||
|
case RuleSet.SingleElimination:
|
||||||
|
await GenerateSingleElimination(tournament, participants);
|
||||||
|
break;
|
||||||
|
case RuleSet.DoubleElimination:
|
||||||
|
await GenerateDoubleElimination(tournament, participants);
|
||||||
|
break;
|
||||||
|
case RuleSet.RoundRobin:
|
||||||
|
await GenerateRoundRobin(tournament, participants);
|
||||||
|
break;
|
||||||
|
case RuleSet.Swiss:
|
||||||
|
await GenerateSwiss(tournament, participants);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GenerateSingleElimination(Tournament tournament, List<TeamParticipant> teams)
|
||||||
|
{
|
||||||
|
int numTeams = teams.Count;
|
||||||
|
int nextPowerOf2 = 1;
|
||||||
|
while (nextPowerOf2 < numTeams)
|
||||||
|
{
|
||||||
|
nextPowerOf2 *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalRounds = (int)Math.Log2(nextPowerOf2);
|
||||||
|
var allMatches = new List<Match>();
|
||||||
|
|
||||||
|
for (int round = 0; round < totalRounds; round++)
|
||||||
|
{
|
||||||
|
int matchesInRound = nextPowerOf2 / (int)Math.Pow(2, round + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < matchesInRound; i++)
|
||||||
|
{
|
||||||
|
var match = CreateMatch(tournament);
|
||||||
|
|
||||||
|
if (round == 0)
|
||||||
|
{
|
||||||
|
int highSeed = i + 1;
|
||||||
|
int lowSeed = nextPowerOf2 - i;
|
||||||
|
|
||||||
|
if (highSeed <= numTeams)
|
||||||
|
AddTeamToMatch(match, teams[highSeed - 1], highSeed);
|
||||||
|
if (lowSeed <= numTeams)
|
||||||
|
AddTeamToMatch(match, teams[lowSeed - 1], lowSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
allMatches.Add(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Matches.AddRange(allMatches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GenerateDoubleElimination(Tournament tournament, List<TeamParticipant> teams)
|
||||||
|
{
|
||||||
|
int numTeams = teams.Count;
|
||||||
|
int nextPowerOf2 = 1;
|
||||||
|
while (nextPowerOf2 < numTeams)
|
||||||
|
{
|
||||||
|
nextPowerOf2 *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wbRounds = (int)Math.Log2(nextPowerOf2);
|
||||||
|
var allMatches = new List<Match>();
|
||||||
|
|
||||||
|
var wbMatchesByRound = new List<List<Match>>();
|
||||||
|
for (int r = 0; r < wbRounds; r++)
|
||||||
|
{
|
||||||
|
int matchesInRound = nextPowerOf2 / (int)Math.Pow(2, r + 1);
|
||||||
|
var roundMatches = new List<Match>();
|
||||||
|
for (int i = 0; i < matchesInRound; i++)
|
||||||
|
{
|
||||||
|
roundMatches.Add(CreateMatch(tournament));
|
||||||
|
}
|
||||||
|
allMatches.AddRange(roundMatches);
|
||||||
|
wbMatchesByRound.Add(roundMatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numTeams > 2)
|
||||||
|
{
|
||||||
|
var lbMatchesByRound = new List<List<Match>>();
|
||||||
|
for (int r = 0; r < wbRounds - 1; r++)
|
||||||
|
{
|
||||||
|
int matchesInRound = nextPowerOf2 / 4;
|
||||||
|
var roundMatches = new List<Match>();
|
||||||
|
for (int i = 0; i < matchesInRound; i++)
|
||||||
|
{
|
||||||
|
roundMatches.Add(CreateMatch(tournament));
|
||||||
|
}
|
||||||
|
allMatches.AddRange(roundMatches);
|
||||||
|
lbMatchesByRound.Add(roundMatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
var lbFinal = CreateMatch(tournament);
|
||||||
|
allMatches.Add(lbFinal);
|
||||||
|
|
||||||
|
var grandFinals = CreateMatch(tournament);
|
||||||
|
allMatches.Add(grandFinals);
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstRoundMatches = wbMatchesByRound[0];
|
||||||
|
for (int i = 0; i < nextPowerOf2 / 2; i++)
|
||||||
|
{
|
||||||
|
int highSeed = i + 1;
|
||||||
|
int lowSeed = nextPowerOf2 - i;
|
||||||
|
var match = firstRoundMatches[i];
|
||||||
|
|
||||||
|
if (highSeed <= numTeams)
|
||||||
|
AddTeamToMatch(match, teams[highSeed - 1], highSeed);
|
||||||
|
if (lowSeed <= numTeams)
|
||||||
|
AddTeamToMatch(match, teams[lowSeed - 1], lowSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Matches.AddRange(allMatches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Match CreateMatch(Tournament tournament)
|
||||||
|
{
|
||||||
|
var match = new Match
|
||||||
|
{
|
||||||
|
TournamentId = tournament.Id,
|
||||||
|
Tournament = tournament,
|
||||||
|
Teams = [],
|
||||||
|
Rounds = []
|
||||||
|
};
|
||||||
|
var r = new Round
|
||||||
|
{
|
||||||
|
MatchId = match.Id,
|
||||||
|
Match = match,
|
||||||
|
Players = []
|
||||||
|
};
|
||||||
|
match.Rounds.Add(r);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddTeamToMatch(Match match, TeamParticipant team, int seed)
|
||||||
|
{
|
||||||
|
match.Teams.Add(new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = team.TeamId,
|
||||||
|
Seed = seed,
|
||||||
|
Score = 0,
|
||||||
|
Team = team.Team,
|
||||||
|
MatchId = 0,
|
||||||
|
Round = match
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GenerateRoundRobin(Tournament tournament, List<TeamParticipant> teams)
|
||||||
|
{
|
||||||
|
var matches = new List<Match>();
|
||||||
|
|
||||||
|
for (int i = 0; i < teams.Count; i++)
|
||||||
|
{
|
||||||
|
for (int j = i + 1; j < teams.Count; j++)
|
||||||
|
{
|
||||||
|
var match = new Match
|
||||||
|
{
|
||||||
|
TournamentId = tournament.Id,
|
||||||
|
Tournament = tournament,
|
||||||
|
Teams =
|
||||||
|
[
|
||||||
|
new TeamParticipant { TeamId = teams[i].TeamId, Seed = teams[i].Seed, Score = 0, Team = teams[i].Team, MatchId = 0, Round = null! },
|
||||||
|
new TeamParticipant { TeamId = teams[j].TeamId, Seed = teams[j].Seed, Score = 0, Team = teams[j].Team, MatchId = 0, Round = null! }
|
||||||
|
],
|
||||||
|
Rounds = []
|
||||||
|
};
|
||||||
|
|
||||||
|
var round = new Round
|
||||||
|
{
|
||||||
|
MatchId = match.Id,
|
||||||
|
Match = match,
|
||||||
|
Players = []
|
||||||
|
};
|
||||||
|
match.Rounds.Add(round);
|
||||||
|
|
||||||
|
matches.Add(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Matches.AddRange(matches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
foreach (var match in matches)
|
||||||
|
{
|
||||||
|
foreach (var tp in match.Teams)
|
||||||
|
{
|
||||||
|
tp.Round = match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GenerateSwiss(Tournament tournament, List<TeamParticipant> teams)
|
||||||
|
{
|
||||||
|
var matches = new List<Match>();
|
||||||
|
|
||||||
|
int numRounds = (int)Math.Ceiling(Math.Log2(teams.Count));
|
||||||
|
var shuffledTeams = teams.OrderBy(_ => Guid.NewGuid()).ToList();
|
||||||
|
|
||||||
|
for (int round = 0; round < numRounds; round++)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < shuffledTeams.Count / 2; i++)
|
||||||
|
{
|
||||||
|
var team1 = shuffledTeams[i * 2];
|
||||||
|
var team2 = shuffledTeams[i * 2 + 1];
|
||||||
|
|
||||||
|
var match = new Match
|
||||||
|
{
|
||||||
|
TournamentId = tournament.Id,
|
||||||
|
Tournament = tournament,
|
||||||
|
Teams =
|
||||||
|
[
|
||||||
|
new TeamParticipant { TeamId = team1.TeamId, Seed = team1.Seed, Score = 0, Team = team1.Team, MatchId = 0, Round = null! },
|
||||||
|
new TeamParticipant { TeamId = team2.TeamId, Seed = team2.Seed, Score = 0, Team = team2.Team, MatchId = 0, Round = null! }
|
||||||
|
],
|
||||||
|
Rounds = []
|
||||||
|
};
|
||||||
|
|
||||||
|
var r = new Round
|
||||||
|
{
|
||||||
|
MatchId = match.Id,
|
||||||
|
Match = match,
|
||||||
|
Players = []
|
||||||
|
};
|
||||||
|
match.Rounds.Add(r);
|
||||||
|
|
||||||
|
matches.Add(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Matches.AddRange(matches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventOption
|
||||||
|
{
|
||||||
|
public Event Event { get; set; } = null!;
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public EventOption() { }
|
||||||
|
|
||||||
|
public EventOption(Event evt)
|
||||||
|
{
|
||||||
|
Event = evt;
|
||||||
|
DisplayName = evt.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TournamentOption
|
||||||
|
{
|
||||||
|
public Tournament Tournament { get; set; } = null!;
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public TournamentOption() { }
|
||||||
|
|
||||||
|
public TournamentOption(Tournament tournament)
|
||||||
|
{
|
||||||
|
Tournament = tournament;
|
||||||
|
DisplayName = $"{tournament.Game.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TeamOption
|
||||||
|
{
|
||||||
|
public Team Team { get; set; } = null!;
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public TeamOption() { }
|
||||||
|
|
||||||
|
public TeamOption(Team team)
|
||||||
|
{
|
||||||
|
Team = team;
|
||||||
|
DisplayName = team.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParticipatingTeam
|
||||||
|
{
|
||||||
|
public int TeamId { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public int Seed { get; set; }
|
||||||
|
public int Score { get; set; }
|
||||||
|
|
||||||
|
public ParticipatingTeam() { }
|
||||||
|
|
||||||
|
public ParticipatingTeam(TournamentTeam tt)
|
||||||
|
{
|
||||||
|
TeamId = tt.TeamId;
|
||||||
|
Name = tt.Team.Name;
|
||||||
|
Seed = tt.Seed;
|
||||||
|
Score = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatchDisplay
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string TeamsText { get; set; } = string.Empty;
|
||||||
|
public RoundState State { get; set; }
|
||||||
|
|
||||||
|
public MatchDisplay() { }
|
||||||
|
|
||||||
|
public MatchDisplay(Match match)
|
||||||
|
{
|
||||||
|
Id = match.Id;
|
||||||
|
if (match.Teams != null && match.Teams.Count >= 2)
|
||||||
|
{
|
||||||
|
TeamsText = $"{match.Teams[0].Team.Name} vs {match.Teams[1].Team.Name}";
|
||||||
|
}
|
||||||
|
else if (match.Teams != null && match.Teams.Count == 1)
|
||||||
|
{
|
||||||
|
TeamsText = $"{match.Teams[0].Team.Name} vs TBD";
|
||||||
|
}
|
||||||
|
|
||||||
|
State = match.Rounds?.LastOrDefault()?.State ?? RoundState.Waiting;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
<Button Content="Home" Command="{Binding NavigateToHomeCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Home" Command="{Binding NavigateToHomeCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
<Button Content="Events" Command="{Binding NavigateToEventsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Events" Command="{Binding NavigateToEventsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
<Button Content="Games" Command="{Binding NavigateToGamesCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Games" Command="{Binding NavigateToGamesCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
|
<Button Content="Tournaments" Command="{Binding NavigateToTournamentsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
<Button Content="Teams" Command="{Binding NavigateToTeamsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Teams" Command="{Binding NavigateToTeamsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -11,13 +11,24 @@
|
|||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Style Selector="Button.dropdown-item">
|
<Style Selector="ListBoxItem.dropdown-item">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item:selected">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-action">
|
||||||
<Setter Property="Padding" Value="8,4"/>
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
<Setter Property="BorderThickness" Value="0"/>
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Button.dropdown-item:pointerover">
|
<Style Selector="Button.dropdown-action:pointerover">
|
||||||
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
@@ -66,12 +77,13 @@
|
|||||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
<DockPanel MaxHeight="200">
|
<DockPanel MaxHeight="200">
|
||||||
<TextBox DockPanel.Dock="Top" Text="{Binding EventFilterSearch}" Watermark="Search events..." Margin="4" Padding="6,4"/>
|
<TextBox DockPanel.Dock="Top" Text="{Binding EventFilterSearch}" Watermark="Search events..." Margin="4" Padding="6,4"/>
|
||||||
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-item" Foreground="Gray" Margin="4,0,4,4"
|
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-action" Foreground="Gray" Margin="4,0,4,4"
|
||||||
Click="OnClearEventFilter"/>
|
Click="OnClearEventFilter"/>
|
||||||
<ListBox ItemsSource="{Binding FilteredEvents}" MaxHeight="160">
|
<ListBox ItemsSource="{Binding FilteredEvents}" MaxHeight="160" SelectionMode="Single"
|
||||||
|
SelectionChanged="OnEventSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="x:String">
|
<DataTemplate x:DataType="x:String">
|
||||||
<Button Content="{Binding}" Classes="dropdown-item" Click="OnEventSelected"/>
|
<TextBlock Text="{Binding}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
@@ -102,12 +114,13 @@
|
|||||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
<DockPanel MaxHeight="200">
|
<DockPanel MaxHeight="200">
|
||||||
<TextBox DockPanel.Dock="Top" Text="{Binding TournamentFilterSearch}" Watermark="Search tournaments..." Margin="4" Padding="6,4"/>
|
<TextBox DockPanel.Dock="Top" Text="{Binding TournamentFilterSearch}" Watermark="Search tournaments..." Margin="4" Padding="6,4"/>
|
||||||
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-item" Foreground="Gray" Margin="4,0,4,4"
|
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-action" Foreground="Gray" Margin="4,0,4,4"
|
||||||
Click="OnClearTournamentFilter"/>
|
Click="OnClearTournamentFilter"/>
|
||||||
<ListBox ItemsSource="{Binding FilteredTournaments}" MaxHeight="160">
|
<ListBox ItemsSource="{Binding FilteredTournaments}" MaxHeight="160" SelectionMode="Single"
|
||||||
|
SelectionChanged="OnTournamentSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="x:String">
|
<DataTemplate x:DataType="x:String">
|
||||||
<Button Content="{Binding}" Classes="dropdown-item" Click="OnTournamentSelected"/>
|
<TextBlock Text="{Binding}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ public partial class TeamsView : UserControl
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEventSelected(object? sender, RoutedEventArgs e)
|
private void OnEventSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button { Content: string eventName } && DataContext is TeamsViewModel vm)
|
if (sender is ListBox { SelectedItem: string eventName } && DataContext is TeamsViewModel vm)
|
||||||
{
|
{
|
||||||
vm.SelectEventFilter(eventName);
|
vm.SelectEventFilter(eventName);
|
||||||
if (EventFilterToggle != null)
|
if (EventFilterToggle != null)
|
||||||
@@ -21,9 +21,9 @@ public partial class TeamsView : UserControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTournamentSelected(object? sender, RoutedEventArgs e)
|
private void OnTournamentSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button { Content: string tournamentName } && DataContext is TeamsViewModel vm)
|
if (sender is ListBox { SelectedItem: string tournamentName } && DataContext is TeamsViewModel vm)
|
||||||
{
|
{
|
||||||
vm.SelectTournamentFilter(tournamentName);
|
vm.SelectTournamentFilter(tournamentName);
|
||||||
if (TournamentFilterToggle != null)
|
if (TournamentFilterToggle != null)
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="using:TournamentOrganizer.ViewModels"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600"
|
||||||
|
x:Class="TournamentOrganizer.Views.TournamentsView"
|
||||||
|
x:DataType="vm:TournamentsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:TournamentsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item:selected">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-action">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-action:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
|
||||||
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="0" Text="Tournament Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
||||||
|
|
||||||
|
<!-- Left Panel: Filters and Matches -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Matches" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||||
|
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
||||||
|
|
||||||
|
<!-- Event Filter Dropdown -->
|
||||||
|
<Panel Name="EventFilterPanel">
|
||||||
|
<ToggleButton Name="EventFilterToggle" HorizontalContentAlignment="Left" HorizontalAlignment="Stretch" Padding="8,6"
|
||||||
|
IsChecked="{Binding IsEventDropdownOpen}">
|
||||||
|
<ToggleButton.Template>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border Background="{TemplateBinding Background}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" HorizontalAlignment="Left"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</ToggleButton.Template>
|
||||||
|
<ToggleButton.Content>
|
||||||
|
<Panel>
|
||||||
|
<TextBlock Text="{Binding SelectedEvent.DisplayName, Mode=OneWay}" IsVisible="{Binding SelectedEvent, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
<TextBlock Text="Select an event..." Foreground="Gray" IsVisible="{Binding SelectedEvent, Converter={x:Static ObjectConverters.IsNull}}"/>
|
||||||
|
</Panel>
|
||||||
|
</ToggleButton.Content>
|
||||||
|
</ToggleButton>
|
||||||
|
<Popup IsOpen="{Binding IsEventDropdownOpen}" PlacementTarget="{Binding #EventFilterToggle}" Width="{Binding Bounds.Width, ElementName=EventFilterToggle}">
|
||||||
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<DockPanel MaxHeight="200">
|
||||||
|
<TextBox DockPanel.Dock="Top" Text="{Binding EventFilterSearch}" Watermark="Search events..." Margin="4" Padding="6,4"/>
|
||||||
|
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-action" Foreground="Gray" Margin="4,0,4,4"
|
||||||
|
Click="OnClearEventFilter"/>
|
||||||
|
<ListBox ItemsSource="{Binding FilteredEvents}" MaxHeight="160" SelectionMode="Single" Classes="dropdown-item"
|
||||||
|
SelectionChanged="OnEventSelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:EventOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
|
<!-- Tournament Filter Dropdown -->
|
||||||
|
<Panel Name="TournamentFilterPanel">
|
||||||
|
<ToggleButton Name="TournamentFilterToggle" HorizontalContentAlignment="Left" HorizontalAlignment="Stretch" Padding="8,6"
|
||||||
|
IsChecked="{Binding IsTournamentDropdownOpen}" IsEnabled="{Binding IsTournamentFilterEnabled}">
|
||||||
|
<ToggleButton.Template>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border Background="{TemplateBinding Background}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" HorizontalAlignment="Left"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</ToggleButton.Template>
|
||||||
|
<ToggleButton.Content>
|
||||||
|
<Panel>
|
||||||
|
<TextBlock Text="{Binding SelectedTournament.DisplayName, Mode=OneWay}" IsVisible="{Binding SelectedTournament, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
<TextBlock Text="Select an event first..." Foreground="Gray" IsVisible="{Binding SelectedTournament, Converter={x:Static ObjectConverters.IsNull}}"/>
|
||||||
|
</Panel>
|
||||||
|
</ToggleButton.Content>
|
||||||
|
</ToggleButton>
|
||||||
|
<Popup IsOpen="{Binding IsTournamentDropdownOpen}" PlacementTarget="{Binding #TournamentFilterToggle}" Width="{Binding Bounds.Width, ElementName=TournamentFilterToggle}">
|
||||||
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<DockPanel MaxHeight="200">
|
||||||
|
<TextBox DockPanel.Dock="Top" Text="{Binding TournamentFilterSearch}" Watermark="Search tournaments..." Margin="4" Padding="6,4"/>
|
||||||
|
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-action" Foreground="Gray" Margin="4,0,4,4"
|
||||||
|
Click="OnClearTournamentFilter"/>
|
||||||
|
<ListBox ItemsSource="{Binding FilteredTournaments}" MaxHeight="160" SelectionMode="Single" Classes="dropdown-item"
|
||||||
|
SelectionChanged="OnTournamentSelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TournamentOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Matches List -->
|
||||||
|
<ListBox ItemsSource="{Binding Matches}"
|
||||||
|
SelectedItem="{Binding SelectedMatch}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:MatchDisplay">
|
||||||
|
<StackPanel Spacing="2">
|
||||||
|
<TextBlock Text="{Binding TeamsText}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding State}" FontSize="11" Foreground="Gray"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Right Panel: Tournament Editor and Teams -->
|
||||||
|
<Border Grid.Column="1" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Tournament Details" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<Button DockPanel.Dock="Bottom" Content="Save Tournament" Command="{Binding SaveTournamentCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}" Margin="0,8,0,0"/>
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="8" IsEnabled="{Binding IsEditing}">
|
||||||
|
<!-- Dates -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Start Date" FontWeight="SemiBold"/>
|
||||||
|
<CalendarDatePicker SelectedDate="{Binding TournamentStart}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="End Date" FontWeight="SemiBold"/>
|
||||||
|
<CalendarDatePicker SelectedDate="{Binding TournamentEnd}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 1 Rule Set -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Stage 1 Rule Set" FontWeight="SemiBold"/>
|
||||||
|
<ComboBox ItemsSource="{Binding S1RuleSetOptions}" SelectedItem="{Binding SelectedS1RuleSet}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RuleSetOption">
|
||||||
|
<TextBlock Text="{Binding Label}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 1 Groups (only if Stage 2 is set) -->
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding SelectedS2RuleSet.Value, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<TextBlock Text="Stage 1 Groups" FontWeight="SemiBold"/>
|
||||||
|
<NumericUpDown Value="{Binding S1Groups}" Minimum="1" Maximum="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding SelectedS2RuleSet.Value, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<TextBlock Text="Stage 1 Group Advances" FontWeight="SemiBold"/>
|
||||||
|
<NumericUpDown Value="{Binding S1GroupAdvances}" Minimum="1" Maximum="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 2 Rule Set -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Stage 2 Rule Set (optional)" FontWeight="SemiBold"/>
|
||||||
|
<ComboBox ItemsSource="{Binding S2RuleSetOptions}" SelectedItem="{Binding SelectedS2RuleSet}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RuleSetOption">
|
||||||
|
<TextBlock Text="{Binding Label}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Teams Section -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Participating Teams" FontWeight="SemiBold"/>
|
||||||
|
|
||||||
|
<!-- Add Team -->
|
||||||
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="4">
|
||||||
|
<ComboBox Grid.Column="0" ItemsSource="{Binding AvailableTeams}" SelectedItem="{Binding SelectedTeamToAdd}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TeamOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
<Button Grid.Column="1" Content="Add" Command="{Binding AddTeamToTournamentCommand}" IsEnabled="{Binding SelectedTeamToAdd, Converter={x:Static ObjectConverters.IsNotNull}}" VerticalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Teams List -->
|
||||||
|
<ListBox ItemsSource="{Binding ParticipatingTeams}"
|
||||||
|
SelectedItem="{Binding SelectedParticipatingTeam}"
|
||||||
|
MinHeight="100"
|
||||||
|
MaxHeight="150">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:ParticipatingTeam">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<TextBlock Text="{Binding Seed, StringFormat='#{0}'}" FontWeight="SemiBold" Foreground="Gray"/>
|
||||||
|
<TextBlock Text="{Binding Name}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="*,*" ColumnSpacing="4">
|
||||||
|
<Button Grid.Column="0" Content="Remove" Command="{Binding RemoveTeamFromTournamentCommand}" IsEnabled="{Binding SelectedParticipatingTeam, Converter={x:Static ObjectConverters.IsNotNull}}" HorizontalAlignment="Stretch"/>
|
||||||
|
<Button Grid.Column="1" Content="Reseed" Command="{Binding ReseedTeamsCommand}" HorizontalAlignment="Stretch"/>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Status Bar -->
|
||||||
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="2" Text="{Binding StatusMessage}" Margin="8" Foreground="Gray" FontSize="12"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Views;
|
||||||
|
|
||||||
|
public partial class TournamentsView : UserControl
|
||||||
|
{
|
||||||
|
public TournamentsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEventSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: EventOption option } && DataContext is TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectEventFilter(option);
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTournamentSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: TournamentOption option } && DataContext is TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectTournamentFilter(option);
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearEventFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearEventFilter();
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearTournamentFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearTournamentFilter();
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user