using System.Text.Json; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Data.Sqlite; using TodoList.Application; using TodoList.Application.Data; using TodoList.Maui.Models; using TodoList.Maui.Services; using TodoList.Maui.Services.Platforms; namespace TodoList.Maui; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); var appSettings = LoadAppSettings(); // Set default connection string if not provided if (string.IsNullOrEmpty(appSettings.WebServer.ConnectionString)) { var dbPath = Path.Combine(FileSystem.AppDataDirectory, "todolist.db"); appSettings.WebServer.ConnectionString = $"Data Source={dbPath}"; } builder.Services.AddSingleton(appSettings); var connectionString = appSettings.WebServer.ConnectionString; builder.Services.AddApplicationServices(connectionString); builder.Services.AddSingleton(sp => new HotKeySettingsService(sp.GetRequiredService())); builder.Services.AddSingleton(sp => GlobalHotKeyServiceFactory.Create()); builder.Services.AddSingleton(sp => { #if WINDOWS return new WindowsSystemTrayService(); #else return new NullSystemTrayService(); #endif }); builder.Services.AddSingleton(); #if DEBUG builder.Logging.AddDebug(); #endif var app = builder.Build(); // Ensure database directory exists and apply migrations using (var scope = app.Services.CreateScope()) { try { var dbContext = scope.ServiceProvider.GetRequiredService(); // Ensure database directory exists for the actual connection string var sqliteBuilder = new SqliteConnectionStringBuilder(connectionString); var actualDbPath = sqliteBuilder.DataSource; if (!string.IsNullOrEmpty(actualDbPath)) { // If it's a relative path, we might need to resolve it, // but for SQLite, it's usually better to have absolute paths. // For MAUI, FileSystem.AppDataDirectory returns an absolute path. var dbDir = Path.GetDirectoryName(actualDbPath); if (!string.IsNullOrEmpty(dbDir) && !Directory.Exists(dbDir)) { Directory.CreateDirectory(dbDir); } } // Ensure database is up to date dbContext.Database.Migrate(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Database initialization failed: {ex.Message}"); // Fallback to EnsureCreated if Migrate fails (though Migrate is preferred) using var context = scope.ServiceProvider.GetRequiredService(); context.Database.EnsureCreated(); } } var webServer = app.Services.GetRequiredService(); _ = webServer.StartAsync(); return app; } private static AppSettings LoadAppSettings() { var settingsPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); if (!File.Exists(settingsPath)) { return new AppSettings(); } var json = File.ReadAllText(settingsPath); return JsonSerializer.Deserialize(json) ?? new AppSettings(); } }