Utopia-Canteen-System/App.xaml.cs

90 lines
3.0 KiB
C#

using System.Windows;
using System.Threading;
using Microsoft.EntityFrameworkCore;
using UtopiaCanteenSystem.Data;
using UtopiaCanteenSystem.Services;
using UtopiaCanteenSystem.ViewModels;
namespace UtopiaCanteenSystem;
/// <summary>
/// Application entry point. Initializes database, builds service graph, starts hourly sync timer.
/// </summary>
public partial class App : Application
{
private System.Timers.Timer? _syncTimer;
private int _isSyncRunning;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// Build services (simple composition; no DI container)
var dbFactory = new DbContextFactory();
// Auto-create SQLite database on first run
using (var db = dbFactory.CreateDbContext())
{
db.EnsureDatabaseCreated();
}
var configService = new ConfigService();
var rfidService = new RfidService(dbFactory, configService);
var syncService = new SyncService(dbFactory, configService);
var session = new AppSession();
var authenticationUrl = "https://portal.utopiaindustries.pk/uind/rest/auth/user/";
var authService = new AuthService(authenticationUrl);
// NavigationService: declare first so lambdas can capture it, then assign (avoids "used before declared")
NavigationService navigationService = null!;
navigationService = new NavigationService(
session,
() => new AdminLoginViewModel(authService, session, navigationService, configService),
() => new ScannerDashboardViewModel(rfidService, navigationService, session, configService),
() => new MainDashboardViewModel(navigationService, rfidService, configService, session),
() => new AdminSettingsAuthViewModel(authService, session, navigationService, configService),
() => new SettingsViewModel(configService, navigationService));
var mainViewModel = new MainViewModel(navigationService);
var mainWindow = new MainWindow
{
DataContext = mainViewModel
};
mainWindow.Show();
// Background sync: every 15 minutes, POST unsynced ScanRecords to API
_syncTimer = new System.Timers.Timer(TimeSpan.FromMinutes(15).TotalMilliseconds)
{
AutoReset = true
};
_syncTimer.Elapsed += async (_, _) =>
{
// Prevent overlapping sync runs; if one is still running, skip this tick.
if (Interlocked.Exchange(ref _isSyncRunning, 1) == 1)
return;
try
{
await syncService.SyncNowAsync().ConfigureAwait(false);
}
catch
{
// Ignore; will retry next tick
}
finally
{
Interlocked.Exchange(ref _isSyncRunning, 0);
}
};
_syncTimer.Start();
}
protected override void OnExit(ExitEventArgs e)
{
_syncTimer?.Stop();
_syncTimer?.Dispose();
base.OnExit(e);
}
}