diff --git a/App.xaml.cs b/App.xaml.cs index a5754e4..23878ba 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -12,11 +12,21 @@ namespace UtopiaCanteenSystem; /// public partial class App : Application { + private static Mutex _mutex; private System.Timers.Timer? _syncTimer; private int _isSyncRunning; protected override void OnStartup(StartupEventArgs e) { + bool isNewInstance; + _mutex = new Mutex(true, "UtopiaCanteenSystemMutex", out isNewInstance); + + if (!isNewInstance) + { + MessageBox.Show("Another instance of the application is already running.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); + Current.Shutdown(); + return; + } base.OnStartup(e); // Build services (simple composition; no DI container) @@ -52,6 +62,8 @@ public partial class App : Application { DataContext = mainViewModel }; + // Set the window to open maximized + mainWindow.WindowState = WindowState.Maximized; mainWindow.Show(); // Background sync: every 15 minutes, POST unsynced lunch_order_transactions to API @@ -83,6 +95,7 @@ public partial class App : Application protected override void OnExit(ExitEventArgs e) { + _mutex.ReleaseMutex(); _syncTimer?.Stop(); _syncTimer?.Dispose(); base.OnExit(e); diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs index 1d2d490..0b2fe5b 100644 --- a/Data/AppDbContext.cs +++ b/Data/AppDbContext.cs @@ -7,13 +7,12 @@ namespace UtopiaCanteenSystem.Data; /// /// SQLite DbContext for Labour and lunch_order_transactions (scan records) tables. -/// Database file is created in application directory on first run. +/// Database file is stored under LocalApplicationData so it persists across app updates +/// when deployed from a file server. /// public class AppDbContext : DbContext { - private static readonly string DbPath = Path.Combine( - AppDomain.CurrentDomain.BaseDirectory, - "utopia_canteen.db"); + private static string DbPath => DatabasePath.GetDbPath(); public DbSet Labour { get; set; } public DbSet LunchOrderTransactions { get; set; } diff --git a/Data/DatabasePath.cs b/Data/DatabasePath.cs new file mode 100644 index 0000000..2bb96cb --- /dev/null +++ b/Data/DatabasePath.cs @@ -0,0 +1,94 @@ +using System.IO; + +namespace UtopiaCanteenSystem.Data; + +/// +/// Central location for persistent paths (database and config). Uses LocalApplicationData +/// so data survives app updates when the application is deployed from a file server. +/// +public static class DatabasePath +{ + private static string? _appDataFolder; + private static string? _dbPath; + + /// + /// Folder under LocalApplicationData for DB and config. Created on first use. + /// + public static string GetAppDataFolder() + { + if (_appDataFolder != null) + return _appDataFolder; + + _appDataFolder = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "UtopiaCanteenSystem"); + Directory.CreateDirectory(_appDataFolder); + return _appDataFolder; + } + + /// + /// Full path to the SQLite database file. If a DB exists in the legacy app-directory + /// location, it is copied to the new location once. + /// + public static string GetDbPath() + { + if (_dbPath != null) + return _dbPath; + + var folder = GetAppDataFolder(); + _dbPath = Path.Combine(folder, "utopia_canteen.db"); + MigrateLegacyDbIfNeeded(_dbPath); + return _dbPath; + } + + /// + /// Full path to appsettings.json (remember-me credentials and other config). + /// Stored in the same persistent folder so it survives updates. If a config exists + /// in the legacy app-directory location, it is copied to the new location once. + /// + public static string GetConfigPath() + { + var folder = GetAppDataFolder(); + var newPath = Path.Combine(folder, "appsettings.json"); + MigrateLegacyConfigIfNeeded(newPath); + return newPath; + } + + private static void MigrateLegacyDbIfNeeded(string newPath) + { + if (File.Exists(newPath)) + return; + + var legacyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "utopia_canteen.db"); + if (!File.Exists(legacyPath)) + return; + + try + { + File.Copy(legacyPath, newPath); + } + catch + { + // If copy fails, app will start with a new DB at new path. + } + } + + private static void MigrateLegacyConfigIfNeeded(string newPath) + { + if (File.Exists(newPath)) + return; + + var legacyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json"); + if (!File.Exists(legacyPath)) + return; + + try + { + File.Copy(legacyPath, newPath); + } + catch + { + // If copy fails, app will start with a new config at new path. + } + } +} diff --git a/Data/DbContextFactory.cs b/Data/DbContextFactory.cs index 2b7e811..0f74bcf 100644 --- a/Data/DbContextFactory.cs +++ b/Data/DbContextFactory.cs @@ -13,7 +13,7 @@ public class DbContextFactory : IDbContextFactory static DbContextFactory() { var builder = new DbContextOptionsBuilder(); - var dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "utopia_canteen.db"); + var dbPath = DatabasePath.GetDbPath(); builder.UseSqlite($"Data Source={dbPath}"); Options = builder.Options; } diff --git a/MainWindow.xaml b/MainWindow.xaml index c9ba628..9cd4240 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -5,7 +5,8 @@ Icon="pack://siteoforigin:,,,/assets/favicon.ico" MinHeight="400" MinWidth="480" Width="900" Height="700" - WindowStartupLocation="CenterScreen"> + WindowStartupLocation="CenterScreen" + WindowState="Maximized"> + + + + 10 + 1.0.0.* + True + Release + True + False + true + True + Unc + \\FileServer\Edata\Deployments-by-DotNet-Team\UtopiaCanteenSystem\ + True + False + True + False + Any CPU + bin\Release\net8.0-windows\win-x86\app.publish\ + \\FileServer\Edata\Deployments-by-DotNet-Team\UtopiaCanteenSystem\ + ClickOnce + False + True + win-x86 + True + (none) + False + false + net8.0-windows + True + Foreground + False + \\FileServer\Edata\Deployments-by-DotNet-Team\UtopiaCanteenSystem\ + Publish.html + True|2026-02-12T06:22:02.6537306Z||;True|2026-02-12T10:57:16.2775876+05:00||;True|2026-02-12T10:50:58.6968682+05:00||;False|2026-02-12T10:49:27.1867616+05:00||;True|2026-02-12T10:44:55.6022990+05:00||;True|2026-02-11T17:00:04.2786466+05:00||;True|2026-02-11T16:54:37.5052808+05:00||;True|2026-02-11T16:39:26.1892892+05:00||;True|2026-02-11T16:30:57.2420414+05:00||;True|2026-02-11T16:20:44.4749529+05:00||; + + \ No newline at end of file diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs index cda21f3..1c35bb2 100644 --- a/Services/ConfigService.cs +++ b/Services/ConfigService.cs @@ -3,11 +3,13 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.Json; +using UtopiaCanteenSystem.Data; namespace UtopiaCanteenSystem.Services; /// -/// Simple JSON-backed configuration stored alongside the app binaries. +/// JSON-backed configuration (including remember-me credentials) stored under +/// LocalApplicationData so it survives app updates when deployed from a file server. /// public class ConfigService : IConfigService { @@ -16,7 +18,7 @@ public class ConfigService : IConfigService public ConfigService() { - _configPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); + _configPath = DatabasePath.GetConfigPath(); _config = LoadConfig(); }