SignalR chat connection OK
This commit is contained in:
parent
bb773ba29a
commit
b22a26f61e
43 changed files with 430 additions and 252 deletions
|
|
@ -4,6 +4,7 @@
|
|||
<application
|
||||
android:label="PostIt"
|
||||
android:icon="@drawable/Icon"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:hardwareAccelerated="true">
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Net.Http;
|
||||
using PostIt.Models;
|
||||
using PostIt.ViewModels;
|
||||
using Yavsc;
|
||||
using Yavsc.Api.Client;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using Avalonia.Controls;
|
|||
using Avalonia.Headless.XUnit;
|
||||
using Avalonia.VisualTree;
|
||||
using PostIt.Controls;
|
||||
using PostIt.Models;
|
||||
using PostIt.ViewModels;
|
||||
|
||||
namespace PostIt.Tests;
|
||||
|
|
@ -21,7 +22,9 @@ public class StatusBarTests
|
|||
[AvaloniaFact]
|
||||
public void Status_message_is_rendered_by_a_SelectableTextBlock()
|
||||
{
|
||||
var bar = new StatusBar { DataContext = StatusNotice.Error("Échec de la suppression : boom") };
|
||||
var bar = new StatusBar {
|
||||
DataContext =
|
||||
StatusNotice.Error("Échec de la suppression : boom") };
|
||||
var window = new Window { Content = bar };
|
||||
window.Show();
|
||||
|
||||
|
|
@ -32,4 +35,4 @@ public class StatusBarTests
|
|||
Assert.NotNull(message);
|
||||
Assert.Equal("Échec de la suppression : boom", message!.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,16 +10,18 @@
|
|||
Padding="8">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="{Binding Glyph}"
|
||||
FontWeight="Bold"
|
||||
Foreground="{Binding Foreground}"
|
||||
VerticalAlignment="Top"/>
|
||||
<!-- SelectableTextBlock so the user can select + copy the
|
||||
status message (TextBlock is not selectable in
|
||||
Avalonia). Keeps Text/TextWrapping/Foreground. -->
|
||||
FontWeight="Bold"
|
||||
Foreground="{Binding Foreground}"
|
||||
VerticalAlignment="Top"/>
|
||||
<SelectableTextBlock Text="{Binding Message}"
|
||||
Foreground="{Binding Foreground}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Center"/>
|
||||
Foreground="{Binding Foreground}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Center"/>
|
||||
<Button Content="{Binding CheckCommandLabel}"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding HasCheckCommand}"
|
||||
Command="{Binding CheckCommand}"
|
||||
/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</UserControl>
|
||||
|
|
|
|||
14
src/PostIt/PostIt/Models/ChatMessageDto.cs
Normal file
14
src/PostIt/PostIt/Models/ChatMessageDto.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace PostIt.ViewModels.Chat
|
||||
{
|
||||
/// <summary>
|
||||
/// DTO minimal calqué sur l'objet anonyme émis par le hub
|
||||
/// (<c>{ Name, Room, Message }</c>) via l'événement
|
||||
/// <c>ReceiveMessage</c>.
|
||||
/// </summary>
|
||||
public class ChatMessageDto
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? Room { get; set; }
|
||||
public string? Message { get; set; }
|
||||
}
|
||||
}
|
||||
11
src/PostIt/PostIt/Models/ChatRoomInfo.cs
Normal file
11
src/PostIt/PostIt/Models/ChatRoomInfo.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace PostIt.ViewModels.Chat
|
||||
{
|
||||
// DTO minimal calqué sur votre logique serveur ChatRoomInfo
|
||||
public class ChatRoomInfo
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public List<string> Users { get; set; } = new();
|
||||
}
|
||||
}
|
||||
6
src/PostIt/PostIt/Models/IWithLabel.cs
Normal file
6
src/PostIt/PostIt/Models/IWithLabel.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace PostIt.ViewModels;
|
||||
|
||||
internal interface IWithLabel
|
||||
{
|
||||
string Label { get; }
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
namespace PostIt.ViewModels;
|
||||
|
||||
public enum StatusSeverity
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public sealed class StatusNotice
|
||||
{
|
||||
public string Message { get; }
|
||||
public StatusSeverity Severity { get; }
|
||||
public string Glyph { get; }
|
||||
public string Background { get; }
|
||||
public string BorderBrush { get; }
|
||||
public string Foreground { get; }
|
||||
|
||||
public StatusNotice(string message, StatusSeverity severity)
|
||||
{
|
||||
Message = string.IsNullOrWhiteSpace(message) ? "Pret." : message;
|
||||
Severity = severity;
|
||||
|
||||
(Glyph, Background, BorderBrush, Foreground) = severity switch
|
||||
{
|
||||
StatusSeverity.Error => ("!", "#7F1D1D", "#C62828", "#e1f0f6"),
|
||||
StatusSeverity.Warning => ("~", "#7C4A03", "#E6A700", "#eaeaea"),
|
||||
_ => ("i", "#E8F0FE", "#5B8DEF", "#1E3A8A"),
|
||||
};
|
||||
}
|
||||
|
||||
public static StatusNotice Info(string message) => new(message, StatusSeverity.Info);
|
||||
public static StatusNotice Warning(string message) => new(message, StatusSeverity.Warning);
|
||||
public static StatusNotice Error(string message) => new(message, StatusSeverity.Error);
|
||||
}
|
||||
8
src/PostIt/PostIt/Models/StatusSeverity.cs
Normal file
8
src/PostIt/PostIt/Models/StatusSeverity.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace PostIt.Models;
|
||||
|
||||
public enum StatusSeverity
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using Avalonia;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PostIt.Helpers;
|
||||
using PostIt.Models;
|
||||
using PostIt.Services;
|
||||
using Yavsc.Api.Client;
|
||||
using Yavsc.Api.Client.Dtos;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Yavsc.Api.Client.Dtos;
|
|||
using Yavsc.Abstract.BlogSpot;
|
||||
using Yavsc.Abstract.Identity.Security;
|
||||
using System.Net.Http;
|
||||
using PostIt.Models;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Avalonia;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Helpers;
|
||||
using PostIt.Models;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using PostIt.Helpers;
|
|||
using Yavsc;
|
||||
using Yavsc.Api.Client;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using PostIt.Models;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
|
|
|
|||
|
|
@ -388,4 +388,4 @@ public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionSt
|
|||
QueryStatus.Success => "V",
|
||||
_ => "i",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Avalonia;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Helpers;
|
||||
using PostIt.Models;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Avalonia;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Helpers;
|
||||
using PostIt.Models;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Avalonia;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Helpers;
|
||||
using PostIt.Models;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using PostIt.Helpers;
|
|||
using Yavsc;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using Yavsc.Api.Client;
|
||||
using PostIt.Models;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Yavsc.Api.Client;
|
|||
using Yavsc.Abstract.Files;
|
||||
using PostIt.Helpers;
|
||||
using AvaloniaEdit.Document;
|
||||
using PostIt.Models;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,18 +4,37 @@ using System.Threading.Tasks;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PostIt.Models;
|
||||
using PostIt.Services;
|
||||
using Yavsc;
|
||||
|
||||
namespace PostIt.ViewModels.Chat
|
||||
{
|
||||
/// <summary>
|
||||
/// ViewModel pour la gestion du chat,
|
||||
/// incluant la connexion au Hub SignalR,
|
||||
/// la gestion des salons et des utilisateurs connectés.
|
||||
/// </summary>
|
||||
|
||||
public partial class ChatViewModel : ViewModelBase
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private readonly YavscApiClient? _api;
|
||||
|
||||
// Le paramètre optionnel permet l'instanciation design-time
|
||||
// (Design.DataContext dans ChatPage.axaml) sans conteneur DI.
|
||||
public ChatViewModel(YavscApiClient? api = null)
|
||||
{
|
||||
var app = App.Current as App;
|
||||
_settings = app!.ServiceProvider!.GetRequiredService<Settings>(); // Assurez-vous que _settings est initialisé avant utilisation.
|
||||
_api = api;
|
||||
Status = new StatusNotice("Déconnecté", StatusSeverity.Info,
|
||||
new RelayCheckCommand("Connecter", async () => await ConnectAsync()));
|
||||
}
|
||||
|
||||
private HubConnection? _connection;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string ServerUrl { get; protected set; } = "https://yavsc.pschneider.fr/chathub";
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string CurrentRoom { get; set; } = "General";
|
||||
|
||||
|
|
@ -24,7 +43,6 @@ namespace PostIt.ViewModels.Chat
|
|||
|
||||
[ObservableProperty]
|
||||
public partial StatusNotice Status { get; set; }
|
||||
= new StatusNotice("Déconnecté", StatusSeverity.Info);
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsConnected { get; set; } = false;
|
||||
|
|
@ -40,20 +58,61 @@ namespace PostIt.ViewModels.Chat
|
|||
[RelayCommand]
|
||||
public async Task JoinRoomCommand() => await JoinRoomAsync();
|
||||
|
||||
[RelayCommand]
|
||||
public async Task ChangeNickCommand() => await ChangeNickAsync();
|
||||
|
||||
public override bool CanNavigateNext { get; protected set; } = false;
|
||||
public override bool CanNavigatePrevious { get; protected set; } = true;
|
||||
|
||||
private async Task DisconnectAsync()
|
||||
{
|
||||
if (_connection != null)
|
||||
{
|
||||
await _connection.StopAsync();
|
||||
await _connection.DisposeAsync();
|
||||
_connection = null;
|
||||
}
|
||||
IsConnected = false;
|
||||
Status = new StatusNotice("Déconnecté", StatusSeverity.Info,
|
||||
new RelayCheckCommand("Connecter", async () => await ConnectAsync()));
|
||||
}
|
||||
|
||||
private async Task ConnectAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Status = new StatusNotice("Connexion en cours...", StatusSeverity.Info);
|
||||
Status = new StatusNotice("Connexion en cours...", StatusSeverity.Info,
|
||||
new RelayCheckCommand("Vérifier la connexion", async () => await CheckConnectionAsync()));
|
||||
|
||||
if (_api == null || !_api.HasValidSession)
|
||||
{
|
||||
Status = new StatusNotice("Session expirée : reconnectez-vous avant d'ouvrir le chat.", StatusSeverity.Error,
|
||||
new RelayCheckCommand("Reconnecter", async () => await ConnectAsync()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Le hub est mappé à la racine du service ("/chathub"),
|
||||
// pas sous le préfixe versionné "/api/v1" : on le retire.
|
||||
var hubBase = _settings.ApiUrl.TrimEnd('/');
|
||||
if (hubBase.EndsWith("/api/v1", StringComparison.OrdinalIgnoreCase))
|
||||
hubBase = hubBase[..^"/api/v1".Length];
|
||||
var hubUrl = hubBase + "/" + Constants.ChatHubPath;
|
||||
|
||||
_connection = new HubConnectionBuilder()
|
||||
.WithUrl(ServerUrl)
|
||||
.WithUrl(hubUrl,
|
||||
|
||||
options =>
|
||||
{
|
||||
// Le hub est [Authorize] : on attache le Bearer OIDC.
|
||||
// AccessTokenProvider est rappelé à chaque reconnexion,
|
||||
// donc on tente un refresh silencieux à chaque appel.
|
||||
// Un refresh mort (invalid_grant) ne doit pas faire
|
||||
// échouer StartAsync avec une exception interne : on
|
||||
// renvoie le token courant (éventuellement expiré) et
|
||||
// le serveur répondra un 401 propre, surfacé à l'UI.
|
||||
options.AccessTokenProvider = async () =>
|
||||
{
|
||||
await _api.TrySilentLoginAsync();
|
||||
return _api.CurrentAccessToken;
|
||||
};
|
||||
})
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
|
||||
|
|
@ -88,15 +147,20 @@ namespace PostIt.ViewModels.Chat
|
|||
|
||||
await _connection.StartAsync();
|
||||
IsConnected = true;
|
||||
Status = new StatusNotice("Connecté au Hub SignalR", StatusSeverity.Info);
|
||||
Status = new StatusNotice("Connecté au Hub SignalR", StatusSeverity.Info, new RelayCheckCommand("Déconnecter", async () => await DisconnectAsync()));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Status = new StatusNotice($"Erreur : {ex.Message}", StatusSeverity.Error);
|
||||
Status = new StatusNotice($"Erreur : {ex.Message}", StatusSeverity.Error, new RelayCheckCommand("Reconnecter", async () => await ConnectAsync()));
|
||||
IsConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckConnectionAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task JoinRoomAsync()
|
||||
{
|
||||
if (_connection == null || string.IsNullOrWhiteSpace(CurrentRoom)) return;
|
||||
|
|
@ -115,21 +179,5 @@ namespace PostIt.ViewModels.Chat
|
|||
Messages.Add($"Erreur Join: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ChangeNickAsync()
|
||||
{
|
||||
if (_connection == null || string.IsNullOrWhiteSpace(NickName)) return;
|
||||
|
||||
try
|
||||
{
|
||||
// Appel de la méthode publique 'Nick' du Hub (void)
|
||||
await _connection.InvokeAsync("Nick", NickName);
|
||||
Messages.Add($"Demande de changement de pseudo vers '{NickName}' envoyée.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Messages.Add($"Erreur Nick: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
33
src/PostIt/PostIt/ViewModels/Chat/RelayCheckCommand.cs
Normal file
33
src/PostIt/PostIt/ViewModels/Chat/RelayCheckCommand.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace PostIt.ViewModels.Chat
|
||||
{
|
||||
internal class RelayCheckCommand : ICommand, IWithLabel
|
||||
{
|
||||
public string Label { get; }
|
||||
private Func<Task> value;
|
||||
|
||||
public RelayCheckCommand(string v, Func<Task> value)
|
||||
{
|
||||
this.Label = v;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
public bool CanExecute(object? parameter)
|
||||
{
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public void Execute(object? parameter)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
_ = value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Models;
|
||||
using Yavsc;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using Yavsc.Api.Client;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Net;
|
|||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using PostIt.Models;
|
||||
using Yavsc.Abstract.Workflow;
|
||||
using Yavsc.Api.Client;
|
||||
using Yavsc.Models.Billing;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using PostIt.Models;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public interface IActionStatusViewModel
|
||||
|
|
@ -29,4 +31,4 @@ public static class ActionStatusViewModelExtensions
|
|||
_ => StatusNotice.Info(normalizedMessage),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Avalonia;
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PostIt.Helpers;
|
||||
using PostIt.Models;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
|
@ -226,4 +227,4 @@ public partial class MyFilesViewModel : ViewModelBase, IActionStatusViewModel
|
|||
var idx = current.LastIndexOf('/');
|
||||
return idx < 0 ? string.Empty : current[..idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Net.Http;
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Globalization;
|
||||
using PostIt.Models;
|
||||
|
||||
[assembly: InternalsVisibleTo("PostIt.Tests")]
|
||||
|
||||
|
|
|
|||
43
src/PostIt/PostIt/ViewModels/StatusNotice.cs
Normal file
43
src/PostIt/PostIt/ViewModels/StatusNotice.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
using System.Windows.Input;
|
||||
using PostIt.Models;
|
||||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public sealed class StatusNotice
|
||||
{
|
||||
public string Message { get; }
|
||||
public StatusSeverity Severity { get; }
|
||||
public string Glyph { get; }
|
||||
public string Background { get; }
|
||||
public string BorderBrush { get; }
|
||||
public string Foreground { get; }
|
||||
|
||||
public bool HasCheckCommand { get; }
|
||||
|
||||
public ICommand? CheckCommand { get; }
|
||||
|
||||
public string CheckCommandLabel { get; }
|
||||
|
||||
public StatusNotice(string message, StatusSeverity severity, ICommand? checkCommand)
|
||||
{
|
||||
Message = string.IsNullOrWhiteSpace(message) ? "Pret." : message;
|
||||
Severity = severity;
|
||||
|
||||
(Glyph, Background, BorderBrush, Foreground) = severity switch
|
||||
{
|
||||
StatusSeverity.Error => ("!", "#7F1D1D", "#C62828", "#e1f0f6"),
|
||||
StatusSeverity.Warning => ("~", "#7C4A03", "#E6A700", "#eaeaea"),
|
||||
_ => ("i", "#E8F0FE", "#5B8DEF", "#1E3A8A"),
|
||||
};
|
||||
HasCheckCommand = checkCommand != null;
|
||||
CheckCommand = checkCommand;
|
||||
CheckCommandLabel = HasCheckCommand ? "Check" :
|
||||
checkCommand == null ?
|
||||
string.Empty :
|
||||
checkCommand is IWithLabel labeled ? labeled.Label : string.Empty;
|
||||
}
|
||||
|
||||
public static StatusNotice Info(string message, ICommand? checkCommand = null) => new(message, StatusSeverity.Info, checkCommand);
|
||||
public static StatusNotice Warning(string message, ICommand? checkCommand = null) => new(message, StatusSeverity.Warning, checkCommand);
|
||||
public static StatusNotice Error(string message, ICommand? checkCommand = null) => new(message, StatusSeverity.Error, checkCommand);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<ContentPage
|
||||
x:Class="PostIt.Views.Chat.ChatPage"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
|
||||
|
|
@ -9,38 +10,71 @@
|
|||
xmlns:postitControls="using:PostIt.Controls"
|
||||
xmlns:views="using:PostIt.Views.Chat"
|
||||
xmlns:vm="using:PostIt.ViewModels.Chat"
|
||||
x:Class="PostIt.Views.Chat.ChatPage"
|
||||
x:DataType="vm:ChatViewModel" >
|
||||
x:DataType="vm:ChatViewModel"
|
||||
>
|
||||
<Design.DataContext>
|
||||
<vm:ChatViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid RowDefinitions="Auto, *, Auto" Margin="10">
|
||||
<Grid Margin="10" RowDefinitions="Auto, *, Auto">
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*, 200" Margin="0,0,0,10">
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Margin="0,0,0,10"
|
||||
ColumnDefinitions="*, 200">
|
||||
|
||||
<!-- Journal des flux de messages & notifications -->
|
||||
<Grid Grid.Column="0" RowDefinitions="Auto, *">
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="10" Margin="0,0,0,5">
|
||||
<TextBox Text="{Binding CurrentRoom}" Watermark="Nom du salon" Width="200" VerticalAlignment="Center"/>
|
||||
<Button Content="Rejoindre Salon (Join)" Command="{Binding JoinRoomCommand}"/>
|
||||
</StackPanel>
|
||||
<!-- Journal des flux de messages & notifications -->
|
||||
<Grid Grid.Column="0" RowDefinitions="Auto, *">
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,5"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
<TextBox
|
||||
Width="200"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding CurrentRoom}"
|
||||
PlaceholderText="Nom du salon" />
|
||||
<Button Command="{Binding JoinRoomCommand}" Content="Rejoindre Salon (Join)" />
|
||||
</StackPanel>
|
||||
|
||||
<ListBox Grid.Row="1" ItemsSource="{Binding Messages}" BorderBrush="#E0E0E0" BorderThickness="1">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" TextWrapping="Wrap"/>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
<ListBox
|
||||
Grid.Row="1"
|
||||
BorderBrush="#E0E0E0"
|
||||
BorderThickness="1"
|
||||
ItemsSource="{Binding Messages}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" TextWrapping="Wrap" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
|
||||
<!-- Liste des utilisateurs présents (MàJ via l'événement 'joint') -->
|
||||
<Border Grid.Column="1" Margin="10,0,0,0" BorderBrush="#E0E0E0" BorderThickness="1" >
|
||||
<Grid RowDefinitions="Auto, *">
|
||||
<TextBlock Grid.Row="0" Text="Membres Présents" FontWeight="Bold" Margin="5" HorizontalAlignment="Center"/>
|
||||
<ListBox Grid.Row="1" ItemsSource="{Binding ConnectedUsers}" BorderThickness="0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Liste des utilisateurs présents (MàJ via l'événement 'joint') -->
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Margin="10,0,0,0"
|
||||
BorderBrush="#E0E0E0"
|
||||
BorderThickness="1">
|
||||
<Grid RowDefinitions="Auto, *">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Center"
|
||||
FontWeight="Bold"
|
||||
Text="Membres Présents" />
|
||||
<ListBox
|
||||
Grid.Row="1"
|
||||
BorderThickness="0"
|
||||
ItemsSource="{Binding ConnectedUsers}" />
|
||||
</Grid>
|
||||
<postitControls:StatusBar Grid.Row="4" DataContext="{Binding Status}" x:Name="StatusBar" />
|
||||
|
||||
</Border>
|
||||
</Grid>
|
||||
<postitControls:StatusBar
|
||||
x:Name="StatusBar"
|
||||
Grid.Row="4"
|
||||
DataContext="{Binding Status}" />
|
||||
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ public partial class ChatPage : ContentPage
|
|||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
<DockPanel LastChildFill="True">
|
||||
<views:SessionStatusBanner
|
||||
x:Name="SessionBanner"
|
||||
DataContext="{Binding SessionStatus}"
|
||||
DockPanel.Dock="Bottom"/>
|
||||
<NavigationPage x:Name="NavRoot"/>
|
||||
</DockPanel>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PostIt.Models;
|
||||
using PostIt.Services;
|
||||
using PostIt.ViewModels;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue