Compare commits

..

4 Commits

Author SHA1 Message Date
tim
bf306a6c15 Merge pull request 'openwiki-update.yml: Actions & Schutzmechanismus verbessert' (#1) from openwiki/update into master
Some checks failed
OpenWiki Update / update (push) Has been cancelled
Reviewed-on: #1
2026-08-09 15:24:31 +00:00
Tim Krampitz
936c8bde28 openwiki-update.yml: Actions & Schutzmechanismus verbessert
All checks were successful
OpenWiki Update / update (push) Successful in 2m21s
- Actions checkout und setup-node auf neuere Versionen aktualisiert
- fetch-depth: 0 für vollständige Git-Historie gesetzt
- npm-Installationsbefehl für openwiki vereinfacht (immer neueste Version)
- Schritt „Restore protected workflow file“ hinzugefügt, um Überschreiben durch OpenWiki zu verhindern
- Kleine Anpassung im PR-Body (Leerzeile entfernt)
2026-08-08 21:15:23 +02:00
Tim Krampitz
2ce9bcd4c4 Update openwiki-update.yml 2026-08-08 21:07:50 +02:00
Tim Krampitz
18a9d1ab74 Robustere Initialisierung & Routing-Refaktor
- InitializeAsync in InitializeSafeAsync mit Fehlerbehandlung umbenannt, App-Start robuster gestaltet
- Asynchrone Initialisierung bei Window.Created
- Navigation vereinheitlicht: Routing.RegisterRoute statt Doppelslash, Navigation ohne Präfix
- Flyout-Menü in AppShell deaktiviert, ShellContent-Einträge entfernt
- Login/Register-ViewModels nutzen private Felder statt ObservableProperty
- SignalRService nutzt AccessToken aus AuthSessionService
- GameStateService: Automatischer Resync bei Verbindung, Fehlerhandling verbessert
- Navigation in ViewModels an neues Routing angepasst
- Aufräumarbeiten: Entfernte auskommentierte Messenger-Registrierungen, Initialisierung vereinheitlicht
2026-08-08 13:12:57 +02:00
12 changed files with 76 additions and 46 deletions

View File

@@ -49,7 +49,7 @@ jobs:
run: git checkout -- .github/workflows/openwiki-update.yml run: git checkout -- .github/workflows/openwiki-update.yml
- name: Create OpenWiki update pull request - name: Create OpenWiki update pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 uses: infinilabs/gitea-pr@v1
with: with:
add-paths: | add-paths: |
openwiki openwiki
@@ -58,6 +58,10 @@ jobs:
.github/workflows/openwiki-update.yml .github/workflows/openwiki-update.yml
branch: openwiki/update branch: openwiki/update
commit-message: "docs: update OpenWiki" commit-message: "docs: update OpenWiki"
url: ${{ secrets.URL }}
token: ${{ secrets.TOKEN }}
base_branch: master
head_branch: openwiki/update
title: "docs: update OpenWiki" title: "docs: update OpenWiki"
body: | body: |
Automated OpenWiki documentation update. Automated OpenWiki documentation update.

View File

@@ -1,8 +1,7 @@
var builder = DistributedApplication.CreateBuilder(args); var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("pgsql") var db = builder.AddPostgres("pgsql")
.AddDatabase("postgresdb") .AddDatabase("postgresdb");
;
var server = builder.AddProject<Projects.SlipItIn_Server>("server") var server = builder.AddProject<Projects.SlipItIn_Server>("server")
.WithReference(db) .WithReference(db)

View File

@@ -8,34 +8,47 @@ public partial class App : Application
public App() public App()
{ {
InitializeComponent(); InitializeComponent();
_ = InitializeAsync();
} }
protected override Window CreateWindow(IActivationState? activationState) protected override Window CreateWindow(IActivationState? activationState)
{ {
var window = new Window(new AppShell()); var window = new Window(new AppShell());
window.Created += async (_, _) =>
{
await InitializeSafeAsync();
};
window.Resumed += async (_, _) => window.Resumed += async (_, _) =>
{ {
var gameStateService = ServiceHelper.GetRequiredService<IGameStateService>(); var gameStateService = ServiceHelper.GetRequiredService<IGameStateService>();
await gameStateService.ResyncAsync(); await gameStateService.ResyncAsync();
}; };
return window; return window;
} }
private static async Task InitializeAsync() private static async Task InitializeSafeAsync()
{ {
var authSession = ServiceHelper.GetRequiredService<IAuthSessionService>(); try
var signalR = ServiceHelper.GetRequiredService<ISignalRService>();
var gameStateService = ServiceHelper.GetRequiredService<IGameStateService>();
await authSession.InitializeAsync();
await gameStateService.InitializeAsync();
if (!string.IsNullOrWhiteSpace(authSession.AccessToken))
{ {
var connected = await signalR.ConnectAsync(authSession.AccessToken); var authSession = ServiceHelper.GetRequiredService<IAuthSessionService>();
if (connected) var signalR = ServiceHelper.GetRequiredService<ISignalRService>();
await gameStateService.ResyncAsync(); var gameStateService = ServiceHelper.GetRequiredService<IGameStateService>();
await authSession.InitializeAsync();
await gameStateService.InitializeAsync();
if (!string.IsNullOrWhiteSpace(authSession.AccessToken))
{
var connected = await signalR.ConnectAsync(authSession.AccessToken);
if (connected)
await gameStateService.ResyncAsync();
}
}
catch
{
// Start darf nicht abstürzen, wenn Session/Netzwerk fehlschlägt.
} }
} }
} }

View File

@@ -3,22 +3,12 @@
x:Class="SlipItIn.AppShell" x:Class="SlipItIn.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:SlipItIn.Views"> xmlns:views="clr-namespace:SlipItIn.Views"
FlyoutBehavior="Disabled">
<ShellContent <ShellContent
Route="LoginPage" Title="Login"
Route="LoginPage"
ContentTemplate="{DataTemplate views:LoginPage}" /> ContentTemplate="{DataTemplate views:LoginPage}" />
<ShellContent
Route="RegisterPage"
ContentTemplate="{DataTemplate views:RegisterPage}" />
<ShellContent
Route="LobbyPage"
ContentTemplate="{DataTemplate views:LobbyPage}" />
<ShellContent
Route="GameBoardPage"
ContentTemplate="{DataTemplate views:GameBoardPage}" />
</Shell> </Shell>

View File

@@ -7,5 +7,8 @@ public partial class AppShell : Shell
public AppShell() public AppShell()
{ {
InitializeComponent(); InitializeComponent();
Routing.RegisterRoute(nameof(RegisterPage), typeof(RegisterPage));
Routing.RegisterRoute(nameof(LobbyPage), typeof(LobbyPage));
Routing.RegisterRoute(nameof(GameBoardPage), typeof(GameBoardPage));
} }
} }

View File

@@ -50,7 +50,21 @@ public class GameStateService : IGameStateService
}; };
_signalR.ErrorReceived += (_, error) => _messenger.Send(new ErrorOccurredMessage(error)); _signalR.ErrorReceived += (_, error) => _messenger.Send(new ErrorOccurredMessage(error));
_signalR.ConnectionStateChanged += (_, connected) => _messenger.Send(new ConnectionStateChangedMessage(connected)); _signalR.ConnectionStateChanged += async (_, connected) =>
{
_messenger.Send(new ConnectionStateChangedMessage(connected));
if (connected)
{
try
{
await ResyncAsync();
}
catch (Exception ex)
{
_messenger.Send(new ErrorOccurredMessage($"Resync fehlgeschlagen: {ex.Message}"));
}
}
};
} }
public async Task InitializeAsync() public async Task InitializeAsync()

View File

@@ -108,11 +108,17 @@ public class SignalRService : ISignalRService
_hubConnection = new HubConnectionBuilder() _hubConnection = new HubConnectionBuilder()
.WithUrl(_configuration.HubUrl, options => .WithUrl(_configuration.HubUrl, options =>
{ {
options.AccessTokenProvider = () => Task.FromResult<string?>(token); options.AccessTokenProvider = () => Task.FromResult<string?>(_authSession.AccessToken ?? token);
}) })
.WithAutomaticReconnect([TimeSpan.Zero, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30)]) .WithAutomaticReconnect([TimeSpan.Zero, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30)])
.Build(); .Build();
_hubConnection.Reconnecting += _ =>
{
ConnectionStateChanged?.Invoke(this, false);
return Task.CompletedTask;
};
_hubConnection.Closed += _ => _hubConnection.Closed += _ =>
{ {
ConnectionStateChanged?.Invoke(this, false); ConnectionStateChanged?.Invoke(this, false);

View File

@@ -110,6 +110,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MauiXaml Update="MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\ChallengeNotificationOverlay.xaml"> <MauiXaml Update="Views\ChallengeNotificationOverlay.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</MauiXaml> </MauiXaml>

View File

@@ -42,7 +42,6 @@ public partial class GameBoardViewModel : BaseViewModel,
_gameStateService = gameStateService; _gameStateService = gameStateService;
_authSession = authSession; _authSession = authSession;
WeakReferenceMessenger.Default.RegisterAll(this);
IsActive = true; IsActive = true;
} }

View File

@@ -42,7 +42,6 @@ public partial class LobbyViewModel : BaseViewModel,
_apiService = apiService; _apiService = apiService;
IsConnected = _signalR.IsConnected; IsConnected = _signalR.IsConnected;
//WeakReferenceMessenger.Default.RegisterAll(this);
IsActive = true; IsActive = true;
} }
@@ -127,7 +126,7 @@ public partial class LobbyViewModel : BaseViewModel,
public async void Receive(GameStartedMessage message) public async void Receive(GameStartedMessage message)
{ {
await MainThread.InvokeOnMainThreadAsync(() => Shell.Current.GoToAsync($"//{nameof(Views.GameBoardPage)}")); await MainThread.InvokeOnMainThreadAsync(() => Shell.Current.GoToAsync(nameof(Views.GameBoardPage)));
} }
public void Receive(ErrorOccurredMessage message) public void Receive(ErrorOccurredMessage message)

View File

@@ -14,10 +14,10 @@ public partial class LoginViewModel : BaseViewModel
private readonly IGameStateService _gameStateService; private readonly IGameStateService _gameStateService;
[ObservableProperty] [ObservableProperty]
public partial string Email { get; set; } private string email = string.Empty;
[ObservableProperty] [ObservableProperty]
public partial string Password { get; set; } private string password = string.Empty;
public LoginViewModel(IApiService apiService, IAuthSessionService authSession, ISignalRService signalR, IGameStateService gameStateService) public LoginViewModel(IApiService apiService, IAuthSessionService authSession, ISignalRService signalR, IGameStateService gameStateService)
{ {
@@ -28,7 +28,7 @@ public partial class LoginViewModel : BaseViewModel
} }
[RelayCommand] [RelayCommand]
private Task GoToRegisterAsync() => Shell.Current.GoToAsync($"//{nameof(RegisterPage)}"); private Task GoToRegisterAsync() => Shell.Current.GoToAsync(nameof(RegisterPage));
[RelayCommand] [RelayCommand]
private async Task LoginAsync() private async Task LoginAsync()
@@ -44,7 +44,7 @@ public partial class LoginViewModel : BaseViewModel
await _authSession.SetSessionAsync(response); await _authSession.SetSessionAsync(response);
await _signalR.ConnectAsync(response.Token); await _signalR.ConnectAsync(response.Token);
await _gameStateService.InitializeAsync(); await _gameStateService.InitializeAsync();
await Shell.Current.GoToAsync($"//{nameof(LobbyPage)}"); await Shell.Current.GoToAsync(nameof(LobbyPage));
}, "Anmeldung läuft..."); }, "Anmeldung läuft...");
} }
@@ -53,9 +53,9 @@ public partial class LoginViewModel : BaseViewModel
{ {
bool isAuthenticated = _authSession.IsAuthenticated; bool isAuthenticated = _authSession.IsAuthenticated;
if ( isAuthenticated) if (isAuthenticated)
{ {
await Shell.Current.GoToAsync($"//{nameof(LobbyPage)}"); await Shell.Current.GoToAsync(nameof(LobbyPage));
} }
} }
} }

View File

@@ -13,13 +13,13 @@ public partial class RegisterViewModel : BaseViewModel
private readonly ISignalRService _signalR; private readonly ISignalRService _signalR;
[ObservableProperty] [ObservableProperty]
public partial string Username { get; set; } = string.Empty; private string username = string.Empty;
[ObservableProperty] [ObservableProperty]
public partial string Email { get; set; } = string.Empty; private string email = string.Empty;
[ObservableProperty] [ObservableProperty]
public partial string Password { get; set; } = string.Empty; private string password = string.Empty;
public RegisterViewModel(IApiService apiService, IAuthSessionService authSession, ISignalRService signalR) public RegisterViewModel(IApiService apiService, IAuthSessionService authSession, ISignalRService signalR)
{ {
@@ -45,7 +45,7 @@ public partial class RegisterViewModel : BaseViewModel
await _authSession.SetSessionAsync(response); await _authSession.SetSessionAsync(response);
await _signalR.ConnectAsync(response.Token); await _signalR.ConnectAsync(response.Token);
await Shell.Current.GoToAsync($"//{nameof(LobbyPage)}"); await Shell.Current.GoToAsync(nameof(LobbyPage));
}, "Registrierung läuft..."); }, "Registrierung läuft...");
} }
} }