Nu är det ordning på funktionaliteten när det gäller att hantera spelare nya spelronder och den poänghistorik som lagras

This commit is contained in:
2025-09-23 22:11:02 +02:00
parent d20c0095cc
commit 8f8f8e70e9
14 changed files with 229 additions and 74 deletions

View File

@ -0,0 +1,29 @@
namespace GreadyPoang.Common;
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
BindingContext = AssociatedObject.BindingContext;
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.100" />
</ItemGroup>
</Project>

View File

@ -1,6 +1,6 @@
using System.Text.RegularExpressions;
namespace GreadyPoang.ViewHelpers;
namespace GreadyPoang.Common;
public class DigitsOnlyBehavior : Behavior<Entry>
{

View File

@ -0,0 +1,50 @@
using System.Reflection;
using System.Windows.Input;
namespace GreadyPoang.Common;
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
public string EventName { get; set; }
public static readonly BindableProperty CommandProperty =
BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(EventToCommandBehavior));
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
private EventInfo eventInfo;
private Delegate eventHandler;
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
if (bindable == null || string.IsNullOrEmpty(EventName))
return;
eventInfo = bindable.GetType().GetRuntimeEvent(EventName);
if (eventInfo == null)
throw new ArgumentException($"Event '{EventName}' not found on type '{bindable.GetType().Name}'");
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod(nameof(OnEvent));
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(bindable, eventHandler);
}
protected override void OnDetachingFrom(VisualElement bindable)
{
base.OnDetachingFrom(bindable);
if (eventInfo != null && eventHandler != null)
eventInfo.RemoveEventHandler(bindable, eventHandler);
}
private void OnEvent(object sender, object eventArgs)
{
if (Command?.CanExecute(eventArgs) == true)
Command.Execute(eventArgs);
}
}

View File

@ -1,6 +1,8 @@
namespace GreadyPoang.EntityLayer;
using Common.Library;
public class RoundBuilderGroup
namespace GreadyPoang.EntityLayer;
public class RoundBuilderGroup : EntityBase
{
public RoundBuilderGroup()
{
@ -47,6 +49,7 @@ public class RoundBuilderGroup
set
{
_elements = value;
RaisePropertyChanged(nameof(Elements));
// No need to raise property changed for this example
}
}

View File

@ -39,11 +39,12 @@ public class RoundRunningViewModel : ViewModelBase
private readonly IMethodSharingService<Participant> _sharingService;
private readonly ICombinedRepository _combined;
private readonly IObjectMessageService _objectMessage;
private ObservableCollection<RoundBuilderElement> _roundElements;
private ObservableCollection<RoundBuilderGroup> _GameRoundList = new();
private ObservableCollection<Participant> _ParticipantList = new();
private ObservableCollection<RoundBuilderElement> _roundElements;
private Collection<PlayerColumn> _playerColumns;
private RoundBuilderElement _builderObject;
public void TriggerRebuild()
{
@ -71,10 +72,6 @@ public class RoundRunningViewModel : ViewModelBase
}
}
private RoundBuilderElement _builderObject;
public RoundBuilderElement BuilderObject
{
get { return _builderObject; }
@ -103,14 +100,20 @@ public class RoundRunningViewModel : ViewModelBase
_roundElements.Add(item);
}
// Räkna ut vem som är nästa spelare
var nxt = nextPlayerElement();
// Aktuell spelare sätts som BuilderObject
BuilderObject.ParticipantName = _objectMessage.CurrentGroup.Elements[nxt].ParticipantName;
BuilderObject.GameRoundId = _objectMessage.CurrentGroup.GameRoundId;
BuilderObject.ParticipantId = _objectMessage.CurrentGroup.Elements[nxt].ParticipantId;
BuilderObject.Status = _objectMessage.CurrentGroup.Status;
// Alla poängposter från samtliga spelare i rundan samlas ihop och fördelas per deltagare
var localElements = _combined.roundBuilderElementsTotalById(_objectMessage.CurrentGroup.GameRoundId);
FillupResultTable(localElements);
FillupResultTable(localElements);
TriggerRebuild();
}
return RoundElements;
}
@ -118,7 +121,18 @@ public class RoundRunningViewModel : ViewModelBase
public void StoreAndHandlePoints()
{
var game = _roundsRepo.Get(BuilderObject.GameRoundId).GetAwaiter().GetResult();
var regNr = RoundElements.Count > 0 ? RoundElements.Max(e => e.GameRoundRegNr) + 1 : 1;
if (game.GameStatus == GamePointStatus.New)
{
game.GameStatus = GamePointStatus.InProgress;
regNr = regNr == 0 ? 1 : regNr;
_roundsRepo.Save(game);
}
BuilderObject.Status = game.GameStatus;
var points = BuilderObject.GameRegPoints;
var newPoint = new GamePoint
{
@ -135,6 +149,7 @@ public class RoundRunningViewModel : ViewModelBase
RoundElements.Clear();
foreach (var item in tmpElements)
{
item.Status = GamePointStatus.InProgress;
RoundElements.Add(item);
}
@ -179,7 +194,8 @@ public class RoundRunningViewModel : ViewModelBase
_playerColumns = new Collection<PlayerColumn>();
}
if (elements.Any(g => g.GameRegPoints > 0))
// if (elements.Any(g => g.GameRegPoints > 0))
if (BuilderObject.Status == GamePointStatus.InProgress)
{
PlayerColumn player = new PlayerColumn();

View File

@ -169,7 +169,8 @@ public class RoundStartingViewModel : ViewModelBase
GameRoundRegNr = p.GameRoundRegNr,
GameRegPoints = p.GameRegPoints,
GameRoundId = p.GameRoundId,
GameRoundStartDate = p.GameRoundStartDate
GameRoundStartDate = p.GameRoundStartDate,
Status = g.First().Status
}).ToList()
})
.ToList();

View File

@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreadyPoang.Migrations", "G
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreadyPoang.Services", "GreadyPoang.Services\GreadyPoang.Services.csproj", "{1C70F0EC-370D-4F48-AEDD-DB171D71EA2A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreadyPoang.Common", "GreadyPoang.Common\GreadyPoang.Common.csproj", "{BEA80096-7267-4583-8982-A8000192CB31}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -52,6 +54,10 @@ Global
{1C70F0EC-370D-4F48-AEDD-DB171D71EA2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C70F0EC-370D-4F48-AEDD-DB171D71EA2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C70F0EC-370D-4F48-AEDD-DB171D71EA2A}.Release|Any CPU.Build.0 = Release|Any CPU
{BEA80096-7267-4583-8982-A8000192CB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEA80096-7267-4583-8982-A8000192CB31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEA80096-7267-4583-8982-A8000192CB31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEA80096-7267-4583-8982-A8000192CB31}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -67,6 +67,7 @@
<ItemGroup>
<ProjectReference Include="..\Common.Library\Common.Library.csproj" />
<ProjectReference Include="..\GreadyPoang.Common\GreadyPoang.Common.csproj" />
<ProjectReference Include="..\GreadyPoang.DataLayer\GreadyPoang.DataLayer.csproj" />
<ProjectReference Include="..\GreadyPoang.EntityLayer\GreadyPoang.EntityLayer.csproj" />
<ProjectReference Include="..\GreadyPoang.Services\GreadyPoang.Services.csproj" />
@ -97,4 +98,8 @@
</MauiXaml>
</ItemGroup>
<ItemGroup>
<Folder Include="ViewHelpers\" />
</ItemGroup>
</Project>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.idoit4u.GreadyPoang" android:versionCode="1" android:versionName="conqueror" android:installLocation="auto">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true" android:label="GreadyPoang"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@ -4,6 +4,41 @@
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Style x:Key="StatusLabelStyle" TargetType="Label" >
<Style.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="New">
<Setter Property="TextColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="InProgress">
<Setter Property="TextColor" Value="DarkBlue" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="Completed">
<Setter Property="TextColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="TextColor" Value="DarkRed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="StatusBorderStyle" TargetType="Border">
<Style.Triggers>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="New">
<Setter Property="BackgroundColor" Value="LightGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="InProgress">
<Setter Property="BackgroundColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Completed">
<Setter Property="BackgroundColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="BackgroundColor" Value="LightCoral" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="ScoreCellStyle" TargetType="Border">
<Setter Property="Stroke" Value="Gray" />
<Setter Property="StrokeThickness" Value="1" />

View File

@ -4,7 +4,7 @@
xmlns:partial="clr-namespace:GreadyPoang.ViewsPartial"
x:Class="GreadyPoang.Views.RoundRunningView"
xmlns:vm ="clr-namespace:GreadyPoang.CommandClasses"
xmlns:behaviors="clr-namespace:GreadyPoang.ViewHelpers"
xmlns:behaviors="clr-namespace:GreadyPoang.Common;assembly=GreadyPoang.Common"
xmlns:local="clr-namespace:GreadyPoang.EntityLayer;assembly=GreadyPoang.EntityLayer"
xmlns:model="clr-namespace:GreadyPoang.EntityLayer;assembly=GreadyPoang.EntityLayer"
x:DataType="vm:RoundRunningViewModelCommands"
@ -33,27 +33,13 @@
<Border Stroke="Gray"
Padding="10"
Margin="5"
BackgroundColor="{Binding Status, Converter={StaticResource StatusToColorConverter}}"
StrokeShape="RoundRectangle 10">
StrokeShape="RoundRectangle 10"
Style="{StaticResource StatusBorderStyle}">
<Border.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={RelativeSource AncestorType={x:Type ContentPage}}, Path=BindingContext.ParticipantTappedCommand}"
CommandParameter="{Binding .}" />
</Border.GestureRecognizers>
<Border.Triggers>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="New">
<Setter Property="BackgroundColor" Value="LightGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="InProgress">
<Setter Property="BackgroundColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Completed">
<Setter Property="BackgroundColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="BackgroundColor" Value="LightCoral" />
</DataTrigger>
</Border.Triggers>
<Grid VerticalOptions="Fill" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@ -63,10 +49,10 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Text="Spelare" />
<Label Grid.Row="1" Text="{Binding ParticipantName}" FontAttributes="Bold" />
<Label Grid.Row="2" Text="{Binding GameRegPoints, StringFormat='Poäng: {0}'}" />
<Label Grid.Row="3" Text="{Binding Status}" />
<Label Grid.Row="4" Text="{Binding GameRoundStartDate, StringFormat='Start: {0:yyyy-MM-dd}'}" />
<Label Grid.Row="1" Text="{Binding ParticipantName}" FontAttributes="Bold" Style="{StaticResource StatusLabelStyle}" />
<Label Grid.Row="2" Text="{Binding GameRegPoints, StringFormat='Poäng: {0}'}" Style="{StaticResource StatusLabelStyle}" />
<Label Grid.Row="3" Text="{Binding Status}" Style="{StaticResource StatusLabelStyle}"/>
<Label Grid.Row="4" Text="{Binding GameRoundStartDate, StringFormat='Start: {0:yyyy-MM-dd}'}" Style="{StaticResource StatusLabelStyle}"/>
</Grid>
</Border>
</DataTemplate>
@ -91,6 +77,8 @@
<Entry Grid.Row="2" x:Name="Points" Placeholder="Latest Points" Text="{Binding BuilderObject.GameRegPoints}" FontAttributes="Bold" FontSize="20" >
<Entry.Behaviors>
<behaviors:DigitsOnlyBehavior/>
<behaviors:EventToCommandBehavior EventName="Completed"
Command="{Binding StoreAndHandlePointsCommand}" />
</Entry.Behaviors>
</Entry>
</Grid>

View File

@ -16,7 +16,7 @@ public partial class RoundRunningView : ContentPage
base.OnAppearing();
BindingContext = ViewModel;
ViewModel.Get();
BuildScoreGrid(ViewModel.PlayerColumns); // <-- h<>r bygger du layouten
//BuildScoreGrid(ViewModel.PlayerColumns); // <-- h<>r bygger du layouten
ViewModel.RebuildRequested += ViewModel_RebuildRequested;

View File

@ -9,6 +9,40 @@
x:DataType="vm:RoundStartingViewModelCommands"
x:Name="GameRoundStartingPage"
Title="Starta ny Runda">
<ContentPage.Resources>
<!--<Style x:Key="StatusLabelStyle" TargetType="Label" >
<Style.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="New">
<Setter Property="TextColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="InProgress">
<Setter Property="TextColor" Value="DarkBlue" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="Completed">
<Setter Property="TextColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="TextColor" Value="DarkRed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="StatusBorderStyle" TargetType="Border">
<Style.Triggers>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="New">
<Setter Property="BackgroundColor" Value="LightGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="InProgress">
<Setter Property="BackgroundColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Completed">
<Setter Property="BackgroundColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="BackgroundColor" Value="LightCoral" />
</DataTrigger>
</Style.Triggers>
</Style>-->
</ContentPage.Resources>
<Border Style="{StaticResource Border.Page}" StrokeThickness="4">
<Grid Style="{StaticResource Grid.Page}">
<Grid.RowDefinitions>
@ -33,6 +67,7 @@
<Picker ItemsSource="{Binding ParticipantList}"
ItemDisplayBinding="{Binding LastNameFirstName}"
SelectedItem="{Binding SelectedItem}"
TextColor="Black"
Title="Välj deltagare"/>
</Border>
<Border Stroke="Gold" StrokeThickness="2" BackgroundColor="LightCyan" >
@ -51,32 +86,19 @@
Stroke="LightGray"
StrokeThickness="1"
x:Name="RoundElementBorder"
BackgroundColor="{Binding Status, Converter={StaticResource StatusToColorConverter}}"
StrokeShape="RoundRectangle 10">
StrokeShape="RoundRectangle 10"
Style="{StaticResource StatusBorderStyle}"
>
<Border.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding BindingContext.ParticipantTappedCommand, Source={x:Reference Name=ParticipantList}}"
CommandParameter="{Binding .}" />
</Border.GestureRecognizers>
<Border.Triggers>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="New">
<Setter Property="BackgroundColor" Value="LightGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="InProgress">
<Setter Property="BackgroundColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Completed">
<Setter Property="BackgroundColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="BackgroundColor" Value="LightCoral" />
</DataTrigger>
</Border.Triggers>
<Border Margin="1" Padding="2" StrokeThickness="3" >
<VerticalStackLayout>
<Label Text="{Binding ParticipantName}" FontAttributes="Bold" FontSize="14" TextColor="Black"/>
<Label Text="{Binding GameRoundStartDateString}" FontAttributes="Bold" FontSize="14" TextColor="Black"/>
<Label Text="{Binding StatusString}" FontSize="14" TextColor="White" />
<Label Text="{Binding ParticipantName}" FontAttributes="Bold" FontSize="14" Style="{StaticResource StatusLabelStyle}"/>
<Label Text="{Binding GameRoundStartDateString}" FontAttributes="Bold" FontSize="14" Style="{StaticResource StatusLabelStyle}"/>
<Label Text="{Binding StatusString}" FontSize="14" Style="{StaticResource StatusLabelStyle}" />
</VerticalStackLayout>
</Border>
</Border>
@ -114,7 +136,7 @@
<!-- Gruppens rubrik -->
<HorizontalStackLayout>
<Label Text="{Binding GameRoundId, StringFormat='Runda: {0}'}" FontAttributes="Bold" FontSize="18" />
<Label Text="{Binding GameRoundStartDate, StringFormat='Startdatum: {0}'}" FontAttributes="Bold" FontSize="18" />
<Label Text="{Binding GameRoundStartDate, StringFormat='Startdatum: {0}'}" FontAttributes="Bold" FontSize="18"/>
<Label Text="{Binding Status, StringFormat='Status: {0}'}" FontAttributes="Bold" FontSize="18" />
</HorizontalStackLayout>
<!-- Horisontell lista med deltagare -->
@ -129,21 +151,7 @@
Stroke="Gray"
Padding="5"
Margin="5,0"
BackgroundColor="{Binding Status, Converter={StaticResource StatusToColorConverter}}" >
<Border.Triggers>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="New">
<Setter Property="BackgroundColor" Value="LightGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="InProgress">
<Setter Property="BackgroundColor" Value="LightYellow" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Completed">
<Setter Property="BackgroundColor" Value="DarkGreen" />
</DataTrigger>
<DataTrigger TargetType="Border" Binding="{Binding Status}" Value="Cancelled">
<Setter Property="BackgroundColor" Value="LightCoral" />
</DataTrigger>
</Border.Triggers>
Style="{StaticResource StatusBorderStyle}" >
<Border.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Path=BindingContext.ElementTappedCommand,Source={x:Reference OuterList}}"
@ -151,9 +159,9 @@
</Border.GestureRecognizers>
<VerticalStackLayout>
<Label Text="{Binding ParticipantName}" FontAttributes="Bold" />
<Label Text="{Binding GameRegPoints, StringFormat='Poäng: {0}'}" />
<Label Text="{Binding GameRoundRegNr, StringFormat='RegNr: {0}'}" />
<Label Text="{Binding ParticipantName}" FontAttributes="Bold" Style="{StaticResource StatusLabelStyle}" />
<Label Text="{Binding GameRegPoints, StringFormat='Poäng: {0}'}" Style="{StaticResource StatusLabelStyle}"/>
<Label Text="{Binding GameRoundRegNr, StringFormat='RegNr: {0}'}" Style="{StaticResource StatusLabelStyle}"/>
</VerticalStackLayout>
</Border>
</DataTemplate>