Skip to content

Commit e273d26

Browse files
Merge pull request #93 from CodebreakerApp/92-animations-and-infomessages
92 animations and infomessages
2 parents 27d9cc4 + ffc2a33 commit e273d26

6 files changed

Lines changed: 79 additions & 19 deletions

File tree

src/Codebreaker.ViewModels/Pages/GamePageViewModel.cs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ IInfoBarService infoBarService
5252
};
5353
}
5454

55-
/// <summary>
56-
/// Information on the game - messages, errors, etc. See <see cref="InfoBarMessageService"/>.
57-
/// </summary>
58-
public InfoBarService InfoBarMessageService { get; } = new();
59-
6055
private Game? _game;
6156
/// <summary>
6257
/// <see cref="Models.Game"/> instance."/>
@@ -121,7 +116,7 @@ public Game? Game
121116
/// Updates the <see cref="GameStatus"/> property.
122117
/// Initializes <see cref="Game"/>).
123118
/// Increments the move number.
124-
/// Shows <see cref="IDialogService"/> messages or <see cref="InfoBarMessageService"/> messages with errors.
119+
/// Shows <see cref="IDialogService"/> messages or <see cref="_infoBarService"/> messages with errors.
125120
/// </summary>
126121
/// <returns>A task</returns>
127122
[RelayCommand(AllowConcurrentExecutions = false, FlowExceptionsToTaskScheduler = true)]
@@ -219,17 +214,17 @@ private async Task SetMoveAsync()
219214
if (isVictory)
220215
{
221216
GameStatus = GameMode.Won;
222-
InfoBarMessageService.New.IsSuccessMessage().WithMessage("Congratulations - you won!").Show();
217+
_infoBarService.New.IsSuccessMessage().WithMessage("Congratulations - you won!").Show();
223218
}
224219
else if (ended)
225220
{
226221
GameStatus = GameMode.Lost;
227-
InfoBarMessageService.New.WithMessage("Sorry, you didn't find the matching colors!").Show();
222+
_infoBarService.New.WithMessage("Sorry, you didn't find the matching colors!").Show();
228223
}
229224
}
230225
catch (Exception ex)
231226
{
232-
InfoBarMessageService.New.WithMessage(ex.Message).IsErrorMessage().Show();
227+
_infoBarService.New.WithMessage(ex.Message).IsErrorMessage().Show();
233228
}
234229
finally
235230
{
@@ -254,7 +249,7 @@ private void InitializeValues()
254249
ClearSelectedColor();
255250
GameMoves.Clear();
256251
GameStatus = GameMode.NotRunning;
257-
InfoBarMessageService.Clear();
252+
_infoBarService.Clear();
258253
_moveNumber = 0;
259254
}
260255
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace System.Linq;
2+
3+
internal static class LinqExtensions
4+
{
5+
public static IEnumerable<T> Foreach<T>(this IEnumerable<T> enumerable, Action<T> action)
6+
{
7+
foreach (var item in enumerable)
8+
action(item);
9+
10+
return enumerable;
11+
}
12+
13+
public static IEnumerable<T> Foreach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
14+
{
15+
int i = 0;
16+
17+
foreach (var item in enumerable)
18+
action(item, i++);
19+
20+
return enumerable;
21+
}
22+
}

src/Codebreaker.WinUI/Views/Components/PegSelectionComponent.xaml.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
using Codebreaker.ViewModels;
2+
using CommunityToolkit.Mvvm.Messaging;
3+
using Microsoft.UI.Xaml.Media.Animation;
24

35
namespace CodeBreaker.WinUI.Views.Components;
46

5-
internal sealed partial class PegSelectionComponent : UserControl
7+
internal sealed partial class PegSelectionComponent : UserControl, IRecipient<GameMoveMessage>
68
{
79
public PegSelectionComponent()
810
{
911
InitializeComponent();
12+
WeakReferenceMessenger.Default.Register(this);
13+
WeakReferenceMessenger.Default.UnregisterAllOnUnloaded(this);
1014
}
1115

1216
public GamePageViewModel ViewModel
@@ -22,4 +26,13 @@ public GamePageViewModel ViewModel
2226
public static readonly DependencyProperty ViewModelProperty =
2327
DependencyProperty.Register("ViewModel", typeof(GamePageViewModel), typeof(PegSelectionComponent), new PropertyMetadata(null));
2428

29+
public void Receive(GameMoveMessage message)
30+
{
31+
if (message.GameMoveValue is not GameMoveValue.Started)
32+
return;
33+
34+
var animationService = ConnectedAnimationService.GetForCurrentView();
35+
this.FindItemsOfType<ComboBox>(this)
36+
.Foreach((comboBox, i) => animationService.PrepareToAnimate($"guess{i}", comboBox));
37+
}
2538
}

src/Codebreaker.WinUI/Views/Pages/GamePage.xaml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@
2121
</Page.Resources>
2222
<Grid x:Name="ContentArea">
2323
<Grid.RowDefinitions>
24-
<RowDefinition Height="auto" />
2524
<RowDefinition Height="auto" />
2625
<RowDefinition Height="auto" />
2726
<RowDefinition Height="*" />
2827
</Grid.RowDefinitions>
2928
<!--Startgame section-->
3029
<Grid
31-
Grid.Row="1"
30+
Grid.Row="0"
3231
ColumnSpacing="25"
3332
Visibility="{x:Bind ViewModel.GameStatus, Mode=OneWay, Converter={StaticResource GameStatusVisibility}, ConverterParameter=Start}">
3433
<Grid.ColumnDefinitions>
@@ -85,15 +84,18 @@
8584
<TextBlock Text="{cme:ResourceString Name=GamePage_CancelButtonText}" />
8685
</StackPanel>
8786
</Button>-->
88-
<components:PegSelectionComponent
89-
Grid.Row="2"
90-
ViewModel="{x:Bind ViewModel, Mode=OneWay}" />
87+
<components:PegSelectionComponent
88+
Grid.Row="3"
89+
Margin="65,0,0,0"
90+
ViewModel="{x:Bind ViewModel, Mode=OneWay}" />
9191
</StackPanel>
9292
<!--Move section-->
9393
<ListBox
9494
x:Name="listGameMoves"
95-
Grid.Row="3"
95+
Grid.Row="2"
9696
Background="Transparent"
97+
SelectedIndex="-1"
98+
IsHitTestVisible="False"
9799
Visibility="{x:Bind ViewModel.GameStatus, Mode=OneWay, Converter={StaticResource GameStatusVisibility}, ConverterParameter=Running}"
98100
ItemsSource="{x:Bind ViewModel.GameMoves, Mode=OneWay}"
99101
ItemTemplate="{StaticResource PegsTemplate}" />
Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,45 @@
11
using Codebreaker.ViewModels;
2+
using CommunityToolkit.Mvvm.Messaging;
3+
using Microsoft.UI.Xaml.Media.Animation;
4+
using Microsoft.UI.Xaml.Shapes;
25

36
namespace CodeBreaker.WinUI.Views.Pages;
47

58
/// <summary>
69
/// An empty page that can be used on its own or navigated to within a Frame.
710
/// </summary>
8-
public sealed partial class GamePage : Page
11+
public sealed partial class GamePage : Page, IRecipient<GameMoveMessage>
912
{
1013
public GamePageViewModel ViewModel { get; }
1114

1215
public GamePage()
1316
{
1417
ViewModel = App.GetService<GamePageViewModel>();
1518
InitializeComponent();
19+
WeakReferenceMessenger.Default.Register(this);
20+
WeakReferenceMessenger.Default.UnregisterAllOnUnloaded(this);
21+
}
22+
23+
public void Receive(GameMoveMessage message)
24+
{
25+
if (message.GameMoveValue is not GameMoveValue.Completed)
26+
return;
27+
28+
var selectionAndKeyPegs = message.SelectionAndKeyPegs ?? throw new InvalidOperationException();
29+
var animationService = ConnectedAnimationService.GetForCurrentView();
30+
animationService.DefaultDuration = TimeSpan.FromMilliseconds(500);
31+
var container = listGameMoves.ItemContainerGenerator.ContainerFromItem(selectionAndKeyPegs);
32+
this.FindItemsOfType<Ellipse>(container)
33+
.Foreach((ellipse, i) =>
34+
{
35+
ConnectedAnimation? animation = animationService.GetAnimation($"guess{i}");
36+
37+
// No animation found for this ellipxe -> the ellipse is most likely a key-peg
38+
if (animation is null)
39+
return;
40+
41+
animation.Configuration = new BasicConnectedAnimationConfiguration();
42+
animation.TryStart(ellipse);
43+
});
1644
}
1745
}

src/Codebreaker.WinUI/Views/Templates/CodeBreakerTemplates.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<ColumnDefinition Width="auto" />
1818
<ColumnDefinition Width="auto" />
1919
</Grid.ColumnDefinitions>
20-
<TextBlock Grid.Column="0" Text="{Binding Path=MoveNumber, Mode=OneTime}" FontSize="{ThemeResource LargeFontSize}" Margin="48,0" VerticalAlignment="Center" />
20+
<TextBlock Grid.Column="0" Text="{Binding Path=MoveNumber, Mode=OneTime}" FontSize="{ThemeResource LargeFontSize}" Margin="48,0,10,0" VerticalAlignment="Center" />
2121
<Border Grid.Column="1" Margin="20,0,0,0" Padding="7" x:Name="ShadowTarget">
2222
<ItemsControl ItemsSource="{Binding Path=GuessPegs, Mode=OneTime}">
2323
<ItemsControl.ItemsPanel>

0 commit comments

Comments
 (0)