teams: slightly changed the design and improved filtering options
This commit is contained in:
@@ -42,10 +42,28 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
private string _filterMemberName = string.Empty;
|
private string _filterMemberName = string.Empty;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _filterEventName = string.Empty;
|
private string? _selectedEventFilter;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _filterTournamentName = string.Empty;
|
private string? _selectedTournamentFilter;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<string> _availableEvents = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<string> _availableTournaments = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _eventFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _tournamentFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEventDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isTournamentDropdownOpen;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isEditing;
|
private bool _isEditing;
|
||||||
@@ -53,6 +71,34 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _statusMessage = string.Empty;
|
private string _statusMessage = string.Empty;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<string> _filteredEvents = [];
|
||||||
|
public ObservableCollection<string> FilteredEvents => _filteredEvents;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<string> _filteredTournaments = [];
|
||||||
|
public ObservableCollection<string> FilteredTournaments => _filteredTournaments;
|
||||||
|
|
||||||
|
partial void OnEventFilterSearchChanged(string value) => UpdateFilteredEvents();
|
||||||
|
|
||||||
|
partial void OnTournamentFilterSearchChanged(string value) => UpdateFilteredTournaments();
|
||||||
|
|
||||||
|
private void UpdateFilteredEvents()
|
||||||
|
{
|
||||||
|
_filteredEvents.Clear();
|
||||||
|
foreach (var e in AvailableEvents.Where(e => string.IsNullOrWhiteSpace(EventFilterSearch) || e.ToLower().Contains(EventFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredEvents.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFilteredTournaments()
|
||||||
|
{
|
||||||
|
_filteredTournaments.Clear();
|
||||||
|
foreach (var t in AvailableTournaments.Where(t => string.IsNullOrWhiteSpace(TournamentFilterSearch) || t.ToLower().Contains(TournamentFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredTournaments.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TeamsViewModel()
|
public TeamsViewModel()
|
||||||
{
|
{
|
||||||
_context = new TournamentContext();
|
_context = new TournamentContext();
|
||||||
@@ -60,6 +106,25 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
|
|
||||||
public async Task LoadTeams()
|
public async Task LoadTeams()
|
||||||
{
|
{
|
||||||
|
var events = await _context.Events.ToListAsync();
|
||||||
|
AvailableEvents.Clear();
|
||||||
|
foreach (var e in events)
|
||||||
|
{
|
||||||
|
AvailableEvents.Add(e.Name);
|
||||||
|
}
|
||||||
|
UpdateFilteredEvents();
|
||||||
|
|
||||||
|
var games = await _context.Games.ToListAsync();
|
||||||
|
AvailableTournaments.Clear();
|
||||||
|
foreach (var g in games)
|
||||||
|
{
|
||||||
|
foreach (var e in events)
|
||||||
|
{
|
||||||
|
AvailableTournaments.Add($"{g.Name} @ {e.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateFilteredTournaments();
|
||||||
|
|
||||||
var query = _context.Teams
|
var query = _context.Teams
|
||||||
.Include(t => t.Players)
|
.Include(t => t.Players)
|
||||||
.Include(t => t.Leader)
|
.Include(t => t.Leader)
|
||||||
@@ -79,15 +144,15 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
filtered = filtered.Where(t => t.Players.Any(p => p.Name.ToLower().Contains(filter)));
|
filtered = filtered.Where(t => t.Players.Any(p => p.Name.ToLower().Contains(filter)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(FilterEventName))
|
if (!string.IsNullOrWhiteSpace(SelectedEventFilter))
|
||||||
{
|
{
|
||||||
var filter = FilterEventName.ToLower();
|
var filter = SelectedEventFilter.ToLower();
|
||||||
filtered = filtered.Where(t => GetAssociatedEvents(t).Any(e => e.ToLower().Contains(filter)));
|
filtered = filtered.Where(t => GetAssociatedEvents(t).Any(e => e.ToLower().Contains(filter)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(FilterTournamentName))
|
if (!string.IsNullOrWhiteSpace(SelectedTournamentFilter))
|
||||||
{
|
{
|
||||||
var filter = FilterTournamentName.ToLower();
|
var filter = SelectedTournamentFilter.ToLower();
|
||||||
filtered = filtered.Where(t => GetAssociatedTournaments(t).Any(tn => tn.ToLower().Contains(filter)));
|
filtered = filtered.Where(t => GetAssociatedTournaments(t).Any(tn => tn.ToLower().Contains(filter)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +166,36 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
IsEditing = false;
|
IsEditing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SelectEventFilter(string eventName)
|
||||||
|
{
|
||||||
|
SelectedEventFilter = eventName;
|
||||||
|
IsEventDropdownOpen = false;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearEventFilter()
|
||||||
|
{
|
||||||
|
SelectedEventFilter = null;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectTournamentFilter(string tournamentName)
|
||||||
|
{
|
||||||
|
SelectedTournamentFilter = tournamentName;
|
||||||
|
IsTournamentDropdownOpen = false;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearTournamentFilter()
|
||||||
|
{
|
||||||
|
SelectedTournamentFilter = null;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task RefreshTeams()
|
private async Task RefreshTeams()
|
||||||
{
|
{
|
||||||
@@ -351,8 +446,6 @@ public partial class TeamsViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
partial void OnFilterMemberNameChanged(string value) => ApplyFilters();
|
partial void OnFilterMemberNameChanged(string value) => ApplyFilters();
|
||||||
partial void OnFilterEventNameChanged(string value) => ApplyFilters();
|
|
||||||
partial void OnFilterTournamentNameChanged(string value) => ApplyFilters();
|
|
||||||
|
|
||||||
private async void ApplyFilters()
|
private async void ApplyFilters()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,26 +10,116 @@
|
|||||||
<vm:TeamsViewModel />
|
<vm:TeamsViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="Button.dropdown-item">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-item:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
|
||||||
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
|
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
|
||||||
<TextBlock Grid.ColumnSpan="2" Grid.Row="0" Text="Teams Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="0" Text="Teams Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
||||||
|
|
||||||
<!-- Left Panel: Team List and Filters -->
|
<!-- Left Panel: Team List and Filters -->
|
||||||
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<TextBlock DockPanel.Dock="Top" Text="Teams" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
<!-- Header with New Team button -->
|
||||||
|
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||||
|
<Button Command="{Binding CreateNewTeamCommand}" DockPanel.Dock="Right" Padding="8,4">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||||
|
<TextBlock Text="+" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="New Team" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<TextBlock Text="Teams" FontSize="16" FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
<!-- Filters -->
|
<!-- Filters -->
|
||||||
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||||
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
||||||
<TextBox Watermark="Filter by member name..." Text="{Binding FilterMemberName}"/>
|
<TextBox Watermark="Filter by member name..." Text="{Binding FilterMemberName}"/>
|
||||||
<TextBox Watermark="Filter by event..." Text="{Binding FilterEventName}"/>
|
|
||||||
<TextBox Watermark="Filter by tournament..." Text="{Binding FilterTournamentName}"/>
|
<!-- 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 SelectedEventFilter, Mode=OneWay}"/>
|
||||||
|
<TextBlock Text="Filter by event..." Foreground="Gray" IsVisible="{Binding SelectedEventFilter, 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-item" Foreground="Gray" Margin="4,0,4,4"
|
||||||
|
Click="OnClearEventFilter"/>
|
||||||
|
<ListBox ItemsSource="{Binding FilteredEvents}" MaxHeight="160">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<Button Content="{Binding}" Classes="dropdown-item" Click="OnEventSelected"/>
|
||||||
|
</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}">
|
||||||
|
<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 SelectedTournamentFilter, Mode=OneWay}"/>
|
||||||
|
<TextBlock Text="Filter by tournament..." Foreground="Gray" IsVisible="{Binding SelectedTournamentFilter, 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-item" Foreground="Gray" Margin="4,0,4,4"
|
||||||
|
Click="OnClearTournamentFilter"/>
|
||||||
|
<ListBox ItemsSource="{Binding FilteredTournaments}" MaxHeight="160">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<Button Content="{Binding}" Classes="dropdown-item" Click="OnTournamentSelected"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Team List -->
|
<!-- Team List -->
|
||||||
<ListBox ItemsSource="{Binding Teams}"
|
<ListBox ItemsSource="{Binding Teams}"
|
||||||
SelectedItem="{Binding SelectedTeam}"
|
SelectedItem="{Binding SelectedTeam}">
|
||||||
Margin="0,0,0,8">
|
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:TeamDisplay">
|
<DataTemplate x:DataType="vm:TeamDisplay">
|
||||||
<StackPanel Spacing="2">
|
<StackPanel Spacing="2">
|
||||||
@@ -54,8 +144,6 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
|
|
||||||
<Button DockPanel.Dock="Bottom" Content="New Team" Command="{Binding CreateNewTeamCommand}" HorizontalAlignment="Stretch"/>
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
namespace TournamentOrganizer.Views;
|
namespace TournamentOrganizer.Views;
|
||||||
|
|
||||||
@@ -8,4 +10,44 @@ public partial class TeamsView : UserControl
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEventSelected(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is Button { Content: string eventName } && DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectEventFilter(eventName);
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTournamentSelected(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is Button { Content: string tournamentName } && DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectTournamentFilter(tournamentName);
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearEventFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearEventFilter();
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearTournamentFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearTournamentFilter();
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user