diff --git a/TournamentOrganizer/Database/TournamentContext.cs b/TournamentOrganizer/Database/TournamentContext.cs index 486f4a3..c1e108d 100644 --- a/TournamentOrganizer/Database/TournamentContext.cs +++ b/TournamentOrganizer/Database/TournamentContext.cs @@ -35,6 +35,12 @@ public class TournamentContext : DbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); + + modelBuilder.Entity() + .HasOne(t => t.Leader) + .WithMany() + .HasForeignKey(t => t.LeaderId) + .OnDelete(DeleteBehavior.SetNull); } } diff --git a/TournamentOrganizer/Migrations/20260506061334_AddTeamLeader.Designer.cs b/TournamentOrganizer/Migrations/20260506061334_AddTeamLeader.Designer.cs new file mode 100644 index 0000000..2f6441e --- /dev/null +++ b/TournamentOrganizer/Migrations/20260506061334_AddTeamLeader.Designer.cs @@ -0,0 +1,348 @@ +// +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("20260506061334_AddTeamLeader")] + partial class AddTeamLeader + { + /// + 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("S1GroupAdvances") + .HasColumnType("INTEGER"); + + b.Property("S1Groups") + .HasColumnType("INTEGER"); + + 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("LeaderId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LeaderId"); + + 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("S1GroupAdvances") + .HasColumnType("INTEGER"); + + b.Property("S1Groups") + .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.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.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/20260506061334_AddTeamLeader.cs b/TournamentOrganizer/Migrations/20260506061334_AddTeamLeader.cs new file mode 100644 index 0000000..3d9cecd --- /dev/null +++ b/TournamentOrganizer/Migrations/20260506061334_AddTeamLeader.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TournamentOrganizer.Migrations +{ + /// + public partial class AddTeamLeader : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LeaderId", + table: "Teams", + type: "INTEGER", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Teams_LeaderId", + table: "Teams", + column: "LeaderId"); + + migrationBuilder.AddForeignKey( + name: "FK_Teams_Players_LeaderId", + table: "Teams", + column: "LeaderId", + principalTable: "Players", + principalColumn: "Id", + onDelete: ReferentialAction.SetNull); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Teams_Players_LeaderId", + table: "Teams"); + + migrationBuilder.DropIndex( + name: "IX_Teams_LeaderId", + table: "Teams"); + + migrationBuilder.DropColumn( + name: "LeaderId", + table: "Teams"); + } + } +} diff --git a/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs b/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs index 1a0c035..c22b73e 100644 --- a/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs +++ b/TournamentOrganizer/Migrations/TournamentContextModelSnapshot.cs @@ -149,12 +149,17 @@ namespace TournamentOrganizer.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("LeaderId") + .HasColumnType("INTEGER"); + b.Property("Name") .IsRequired() .HasColumnType("TEXT"); b.HasKey("Id"); + b.HasIndex("LeaderId"); + b.ToTable("Teams"); }); @@ -270,6 +275,16 @@ namespace TournamentOrganizer.Migrations 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") diff --git a/TournamentOrganizer/Models/Team.cs b/TournamentOrganizer/Models/Team.cs index 41fc113..474c951 100644 --- a/TournamentOrganizer/Models/Team.cs +++ b/TournamentOrganizer/Models/Team.cs @@ -11,6 +11,9 @@ public class Team public int Id { get; set; } public string Name { get; set; } = "Example Team"; + public int? LeaderId { get; set; } + public Player? Leader { get; set; } + public required List Players { get; set; } public required List Matches { get; set; } diff --git a/TournamentOrganizer/ViewModels/MainViewModel.cs b/TournamentOrganizer/ViewModels/MainViewModel.cs index 915baff..47b5eca 100644 --- a/TournamentOrganizer/ViewModels/MainViewModel.cs +++ b/TournamentOrganizer/ViewModels/MainViewModel.cs @@ -1,9 +1,41 @@ -using CommunityToolkit.Mvvm.ComponentModel; - -namespace TournamentOrganizer.ViewModels; - -public partial class MainViewModel : ViewModelBase -{ - [ObservableProperty] - private string _greeting = "Welcome to Avalonia!"; -} +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +namespace TournamentOrganizer.ViewModels; + +public partial class MainViewModel : ViewModelBase +{ + [ObservableProperty] + private ViewModelBase _currentView; + + [ObservableProperty] + private string _title = "Tournament Organizer"; + + public MainViewModel() + { + CurrentView = new HomeViewModel(); + } + + [RelayCommand] + private void NavigateToHome() + { + CurrentView = new HomeViewModel(); + Title = "Tournament Organizer"; + } + + [RelayCommand] + private async Task NavigateToTeams() + { + var teamsVm = new TeamsViewModel(); + CurrentView = teamsVm; + Title = "Teams Management"; + await teamsVm.LoadTeams(); + } +} + +public partial class HomeViewModel : ViewModelBase +{ + [ObservableProperty] + private string _welcomeMessage = "Welcome to Tournament Organizer!"; +} diff --git a/TournamentOrganizer/ViewModels/TeamsViewModel.cs b/TournamentOrganizer/ViewModels/TeamsViewModel.cs new file mode 100644 index 0000000..bf72e7a --- /dev/null +++ b/TournamentOrganizer/ViewModels/TeamsViewModel.cs @@ -0,0 +1,470 @@ +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 TeamsViewModel : ViewModelBase +{ + private readonly TournamentContext _context; + + [ObservableProperty] + private ObservableCollection _teams = []; + + [ObservableProperty] + private TeamDisplay? _selectedTeam; + + [ObservableProperty] + private string _teamName = string.Empty; + + [ObservableProperty] + private ObservableCollection _players = []; + + [ObservableProperty] + private PlayerEntry? _selectedPlayer; + + [ObservableProperty] + private PlayerEntry? _selectedLeader; + + [ObservableProperty] + private string _newPlayerName = string.Empty; + + [ObservableProperty] + private string _newPlayerContact = string.Empty; + + [ObservableProperty] + private string _filterMemberName = string.Empty; + + [ObservableProperty] + private string _filterEventName = string.Empty; + + [ObservableProperty] + private string _filterTournamentName = string.Empty; + + [ObservableProperty] + private bool _isEditing; + + [ObservableProperty] + private string _statusMessage = string.Empty; + + public TeamsViewModel() + { + _context = new TournamentContext(); + } + + public async Task LoadTeams() + { + var query = _context.Teams + .Include(t => t.Players) + .Include(t => t.Leader) + .Include(t => t.Matches) + .ThenInclude(tp => tp.Round) + .ThenInclude(m => m.Tournament) + .ThenInclude(t => t.Event) + .AsSplitQuery(); + + var allTeams = await query.ToListAsync(); + + var filtered = allTeams.AsEnumerable(); + + if (!string.IsNullOrWhiteSpace(FilterMemberName)) + { + var filter = FilterMemberName.ToLower(); + filtered = filtered.Where(t => t.Players.Any(p => p.Name.ToLower().Contains(filter))); + } + + if (!string.IsNullOrWhiteSpace(FilterEventName)) + { + var filter = FilterEventName.ToLower(); + filtered = filtered.Where(t => GetAssociatedEvents(t).Any(e => e.ToLower().Contains(filter))); + } + + if (!string.IsNullOrWhiteSpace(FilterTournamentName)) + { + var filter = FilterTournamentName.ToLower(); + filtered = filtered.Where(t => GetAssociatedTournaments(t).Any(tn => tn.ToLower().Contains(filter))); + } + + Teams.Clear(); + foreach (var team in filtered) + { + Teams.Add(new TeamDisplay(team)); + } + + SelectedTeam = null; + IsEditing = false; + } + + [RelayCommand] + private async Task RefreshTeams() + { + await LoadTeams(); + } + + [RelayCommand] + private void CreateNewTeam() + { + TeamName = "New Team"; + Players.Clear(); + SelectedLeader = null; + SelectedPlayer = null; + IsEditing = true; + SelectedTeam = null; + NewPlayerName = string.Empty; + NewPlayerContact = string.Empty; + StatusMessage = "Creating new team"; + } + + [RelayCommand] + private async Task SaveTeam() + { + if (string.IsNullOrWhiteSpace(TeamName)) + { + StatusMessage = "Team name is required"; + return; + } + + if (Players.Count == 0) + { + StatusMessage = "Team must have at least one member"; + return; + } + + Team? team; + if (SelectedTeam != null && SelectedTeam.Id > 0) + { + team = await _context.Teams + .Include(t => t.Players) + .FirstOrDefaultAsync(t => t.Id == SelectedTeam.Id); + + if (team == null) + { + StatusMessage = "Team not found"; + return; + } + + team.Name = TeamName; + + var existingPlayerIds = team.Players.Select(p => p.Id).ToHashSet(); + var currentPlayerIds = Players.Where(p => p.Id > 0).Select(p => p.Id).ToHashSet(); + + var playersToRemove = team.Players.Where(p => !currentPlayerIds.Contains(p.Id)).ToList(); + foreach (var player in playersToRemove) + { + team.Players.Remove(player); + _context.Players.Remove(player); + } + + foreach (var entry in Players) + { + if (entry.Id > 0) + { + var existing = team.Players.FirstOrDefault(p => p.Id == entry.Id); + if (existing != null) + { + existing.Name = entry.Name; + existing.Contact = entry.Contact; + } + } + else + { + var newPlayer = new Player + { + Name = entry.Name, + Contact = entry.Contact, + Team = team + }; + team.Players.Add(newPlayer); + entry.Id = newPlayer.Id; + } + } + + if (SelectedLeader != null) + { + var leader = team.Players.FirstOrDefault(p => + (SelectedLeader.Id > 0 && p.Id == SelectedLeader.Id) || + (SelectedLeader.Id == 0 && p.Name == SelectedLeader.Name && p.Contact == SelectedLeader.Contact)); + team.Leader = leader; + } + else + { + team.Leader = null; + } + } + else + { + team = new Team + { + Name = TeamName, + Players = [], + Matches = [] + }; + + var playerEntries = new List<(PlayerEntry Entry, Player Player)>(); + foreach (var entry in Players) + { + var player = new Player + { + Name = entry.Name, + Contact = entry.Contact, + Team = team + }; + team.Players.Add(player); + playerEntries.Add((entry, player)); + } + + _context.Teams.Add(team); + + await _context.SaveChangesAsync(); + + if (team.Players.Count > 0) + { + int leaderIndex = 0; + if (SelectedLeader != null) + { + var idx = Players.IndexOf(SelectedLeader); + if (idx >= 0) leaderIndex = idx; + } + + team.LeaderId = playerEntries[leaderIndex].Player.Id; + await _context.SaveChangesAsync(); + } + } + + await _context.SaveChangesAsync(); + StatusMessage = $"Team '{TeamName}' saved successfully"; + await LoadTeams(); + } + + [RelayCommand] + private async Task DeleteTeam() + { + if (SelectedTeam == null || SelectedTeam.Id == 0) + { + StatusMessage = "Select a team to delete"; + return; + } + + var team = await _context.Teams + .Include(t => t.Players) + .FirstOrDefaultAsync(t => t.Id == SelectedTeam.Id); + + if (team == null) + { + StatusMessage = "Team not found"; + return; + } + + _context.Teams.Remove(team); + await _context.SaveChangesAsync(); + StatusMessage = $"Team '{team.Name}' deleted"; + await LoadTeams(); + } + + [RelayCommand] + private void AddPlayer() + { + if (string.IsNullOrWhiteSpace(NewPlayerName)) + { + StatusMessage = "Player name is required"; + return; + } + + var entry = new PlayerEntry + { + Name = NewPlayerName, + Contact = NewPlayerContact + }; + Players.Add(entry); + + if (SelectedLeader == null) + { + SelectedLeader = entry; + } + + NewPlayerName = string.Empty; + NewPlayerContact = string.Empty; + StatusMessage = $"Player '{entry.Name}' added"; + } + + [RelayCommand] + private void RemovePlayer() + { + if (SelectedPlayer == null) + { + StatusMessage = "Select a player to remove"; + return; + } + + var wasLeader = SelectedLeader == SelectedPlayer; + Players.Remove(SelectedPlayer); + + if (wasLeader) + { + SelectedLeader = Players.FirstOrDefault(); + } + + SelectedPlayer = null; + StatusMessage = "Player removed"; + } + + [RelayCommand] + private void SetLeader() + { + if (SelectedPlayer == null) + { + StatusMessage = "Select a player to make leader"; + return; + } + + SelectedLeader = SelectedPlayer; + StatusMessage = $"{SelectedPlayer.Name} is now the leader"; + } + + partial void OnSelectedTeamChanged(TeamDisplay? value) + { + if (value == null) + { + IsEditing = false; + return; + } + + TeamName = value.Name; + Players.Clear(); + foreach (var player in value.Players) + { + Players.Add(player); + } + + SelectedLeader = Players.FirstOrDefault(p => p.Id == value.LeaderId); + SelectedPlayer = null; + IsEditing = true; + NewPlayerName = string.Empty; + NewPlayerContact = string.Empty; + StatusMessage = $"Editing team '{value.Name}'"; + } + + partial void OnFilterMemberNameChanged(string value) => ApplyFilters(); + partial void OnFilterEventNameChanged(string value) => ApplyFilters(); + partial void OnFilterTournamentNameChanged(string value) => ApplyFilters(); + + private async void ApplyFilters() + { + await LoadTeams(); + } + + private static List GetAssociatedEvents(Team team) + { + var events = new List(); + if (team.Matches != null) + { + foreach (var tp in team.Matches) + { + if (tp.Round?.Tournament?.Event != null) + { + var eventName = tp.Round.Tournament.Event.Name; + if (!events.Contains(eventName)) + { + events.Add(eventName); + } + } + } + } + return events; + } + + private static List GetAssociatedTournaments(Team team) + { + var tournaments = new List(); + if (team.Matches != null) + { + foreach (var tp in team.Matches) + { + if (tp.Round?.Tournament != null) + { + var tournamentName = GetTournamentDisplayName(tp.Round.Tournament); + if (!tournaments.Contains(tournamentName)) + { + tournaments.Add(tournamentName); + } + } + } + } + return tournaments; + } + + public static string GetTournamentDisplayName(Tournament tournament) + { + return $"{tournament.Game.Name} @ {tournament.Event.Name}"; + } +} + +public class TeamDisplay +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public int? LeaderId { get; set; } + public string? LeaderName { get; set; } + public List Players { get; set; } = []; + public List AssociatedEvents { get; set; } = []; + public List AssociatedTournaments { get; set; } = []; + + public TeamDisplay() { } + + public TeamDisplay(Team team) + { + Id = team.Id; + Name = team.Name; + LeaderId = team.LeaderId; + LeaderName = team.Leader?.Name; + Players = team.Players?.Select(p => new PlayerEntry(p)).ToList() ?? []; + + var events = new HashSet(); + var tournaments = new HashSet(); + + if (team.Matches != null) + { + foreach (var tp in team.Matches) + { + if (tp.Round?.Tournament != null) + { + tournaments.Add(TeamsViewModel.GetTournamentDisplayName(tp.Round.Tournament)); + if (tp.Round.Tournament.Event != null) + { + events.Add(tp.Round.Tournament.Event.Name); + } + } + } + } + + AssociatedEvents = events.ToList(); + AssociatedTournaments = tournaments.ToList(); + } +} + +public partial class PlayerEntry : ObservableObject +{ + [ObservableProperty] + private int _id; + + [ObservableProperty] + private string _name = string.Empty; + + [ObservableProperty] + private string _contact = string.Empty; + + public PlayerEntry() { } + + public PlayerEntry(Player player) + { + Id = player.Id; + Name = player.Name; + Contact = player.Contact; + } +} diff --git a/TournamentOrganizer/Views/HomeView.axaml b/TournamentOrganizer/Views/HomeView.axaml new file mode 100644 index 0000000..1f3c790 --- /dev/null +++ b/TournamentOrganizer/Views/HomeView.axaml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/TournamentOrganizer/Views/HomeView.axaml.cs b/TournamentOrganizer/Views/HomeView.axaml.cs new file mode 100644 index 0000000..ce2ad7c --- /dev/null +++ b/TournamentOrganizer/Views/HomeView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace TournamentOrganizer.Views; + +public partial class HomeView : UserControl +{ + public HomeView() + { + InitializeComponent(); + } +} diff --git a/TournamentOrganizer/Views/MainView.axaml b/TournamentOrganizer/Views/MainView.axaml index f3d9668..579b123 100644 --- a/TournamentOrganizer/Views/MainView.axaml +++ b/TournamentOrganizer/Views/MainView.axaml @@ -1,16 +1,25 @@ - - - - - - - - + + + + + + + + + +