feat(chat): envoi de messages dans un salon joint
- DTO ChatMessage (Name/Room/Message) pour l'evenement ReceiveMessage - ChatViewModel : MessageToSend, HasJoinedRoom, handler ReceiveMessage, SendMessageCommand (CanExecute: connecte + salon joint + texte non vide) - ChatPage : TextBox de saisie (Enter envoie) + bouton Envoyer, StatusBar repositionnee en Grid.Row=3
This commit is contained in:
parent
75bb2600b5
commit
51e445b5ba
3 changed files with 81 additions and 2 deletions
15
src/PostIt/PostIt/Models/ChatMessage.cs
Normal file
15
src/PostIt/PostIt/Models/ChatMessage.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace PostIt.ViewModels.Chat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DTO de message de salon, calqué sur la charge envoyée par
|
||||||
|
/// <c>ChatHub.Send</c> côté serveur ({ Name, Room, Message }).
|
||||||
|
/// Le protocole JSON de SignalR sérialise en camelCase ; la
|
||||||
|
/// désérialisation est insensible à la casse par défaut.
|
||||||
|
/// </summary>
|
||||||
|
public class ChatMessage
|
||||||
|
{
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Room { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,8 +45,17 @@ namespace PostIt.ViewModels.Chat
|
||||||
public partial StatusNotice Status { get; set; }
|
public partial StatusNotice Status { get; set; }
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendMessageCommand))]
|
||||||
public partial bool IsConnected { get; set; } = false;
|
public partial bool IsConnected { get; set; } = false;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendMessageCommand))]
|
||||||
|
public partial bool HasJoinedRoom { get; set; } = false;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyCanExecuteChangedFor(nameof(SendMessageCommand))]
|
||||||
|
public partial string MessageToSend { get; set; } = "";
|
||||||
|
|
||||||
// Listes dynamiques pour l'UI
|
// Listes dynamiques pour l'UI
|
||||||
public ObservableCollection<string> Messages { get; } = new();
|
public ObservableCollection<string> Messages { get; } = new();
|
||||||
public ObservableCollection<string> ConnectedUsers { get; } = new();
|
public ObservableCollection<string> ConnectedUsers { get; } = new();
|
||||||
|
|
@ -58,6 +67,28 @@ namespace PostIt.ViewModels.Chat
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public async Task JoinRoomCommand() => await JoinRoomAsync();
|
public async Task JoinRoomCommand() => await JoinRoomAsync();
|
||||||
|
|
||||||
|
// Le serveur (ChatHub.Send) refuse tout message d'un utilisateur
|
||||||
|
// qui n'a pas joint le salon ("NoJoinNoSend") : on garde la
|
||||||
|
// commande inactive tant que le Join n'a pas abouti.
|
||||||
|
private bool CanSendMessage() =>
|
||||||
|
IsConnected && HasJoinedRoom && !string.IsNullOrWhiteSpace(MessageToSend);
|
||||||
|
|
||||||
|
[RelayCommand(CanExecute = nameof(CanSendMessage))]
|
||||||
|
private async Task SendMessageAsync()
|
||||||
|
{
|
||||||
|
if (_connection == null) return;
|
||||||
|
var text = MessageToSend.Trim();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _connection.InvokeAsync("Send", CurrentRoom, text);
|
||||||
|
MessageToSend = string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Messages.Add($"Erreur d'envoi : {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanNavigateNext { get; protected set; } = false;
|
public override bool CanNavigateNext { get; protected set; } = false;
|
||||||
public override bool CanNavigatePrevious { get; protected set; } = true;
|
public override bool CanNavigatePrevious { get; protected set; } = true;
|
||||||
|
|
||||||
|
|
@ -70,6 +101,7 @@ namespace PostIt.ViewModels.Chat
|
||||||
_connection = null;
|
_connection = null;
|
||||||
}
|
}
|
||||||
IsConnected = false;
|
IsConnected = false;
|
||||||
|
HasJoinedRoom = false;
|
||||||
Status = new StatusNotice("Déconnecté", StatusSeverity.Info,
|
Status = new StatusNotice("Déconnecté", StatusSeverity.Info,
|
||||||
new RelayCheckCommand("Connecter", async () => await ConnectAsync()));
|
new RelayCheckCommand("Connecter", async () => await ConnectAsync()));
|
||||||
}
|
}
|
||||||
|
|
@ -140,11 +172,19 @@ namespace PostIt.ViewModels.Chat
|
||||||
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
Messages.Add($"Salon rejoint avec succès : {roomInfo.Name}");
|
Messages.Add($"Salon rejoint avec succès : {roomInfo.Name}");
|
||||||
|
HasJoinedRoom = true;
|
||||||
ConnectedUsers.Clear();
|
ConnectedUsers.Clear();
|
||||||
foreach (var u in roomInfo.Users) ConnectedUsers.Add(u);
|
foreach (var u in roomInfo.Users) ConnectedUsers.Add(u);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 4. Réception des messages du salon (diffusés par ChatHub.Send)
|
||||||
|
_connection.On<ChatMessage>("ReceiveMessage", (msg) =>
|
||||||
|
{
|
||||||
|
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||||
|
Messages.Add($"[{msg.Room}] {msg.Name} : {msg.Message}"));
|
||||||
|
});
|
||||||
|
|
||||||
await _connection.StartAsync();
|
await _connection.StartAsync();
|
||||||
IsConnected = true;
|
IsConnected = true;
|
||||||
Status = new StatusNotice("Connecté au Hub SignalR", StatusSeverity.Info, new RelayCheckCommand("Déconnecter", async () => await DisconnectAsync()));
|
Status = new StatusNotice("Connecté au Hub SignalR", StatusSeverity.Info, new RelayCheckCommand("Déconnecter", async () => await DisconnectAsync()));
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
<vm:ChatViewModel />
|
<vm:ChatViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
|
||||||
<Grid Margin="10" RowDefinitions="Auto, *, Auto">
|
<Grid Margin="10" RowDefinitions="Auto, *, Auto, Auto">
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|
@ -71,9 +71,33 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<!-- Saisie et envoi d'un message dans le salon joint -->
|
||||||
|
<Grid
|
||||||
|
Grid.Row="2"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
ColumnDefinitions="*, Auto">
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
AcceptsReturn="False"
|
||||||
|
IsEnabled="{Binding HasJoinedRoom}"
|
||||||
|
PlaceholderText="Votre message..."
|
||||||
|
Text="{Binding MessageToSend}">
|
||||||
|
<TextBox.KeyBindings>
|
||||||
|
<KeyBinding Command="{Binding SendMessageCommand}" Gesture="Enter" />
|
||||||
|
</TextBox.KeyBindings>
|
||||||
|
</TextBox>
|
||||||
|
<Button
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{Binding SendMessageCommand}"
|
||||||
|
Content="Envoyer" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<postitControls:StatusBar
|
<postitControls:StatusBar
|
||||||
x:Name="StatusBar"
|
x:Name="StatusBar"
|
||||||
Grid.Row="4"
|
Grid.Row="3"
|
||||||
DataContext="{Binding Status}" />
|
DataContext="{Binding Status}" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue