using CommunityToolkit.Maui.Alerts; using CommunityToolkit.Maui.Storage; using Microsoft.Maui.Controls; using Microsoft.Maui.Storage; namespace FrymasterBadgeApp; public partial class SettingsPage : ContentPage { private const string PhotoPathKey = "PhotoBasePath"; private const string LogoPathKey = "LogoBasePath"; private const string ImagesPathKey = "ImagesBasePath"; private const string ThemePrefKey = "AppTheme"; public SettingsPage() { InitializeComponent(); LoadCurrentSettings(); LoadCurrentThemePreference(); ThemePicker.SelectedIndexChanged += (s, e) => ApplyThemeSelection(); Shell.SetBackButtonBehavior( this, new BackButtonBehavior { TextOverride = "Back", Command = new Command(async () => await Shell.Current.GoToAsync("..")), } ); } private void LoadCurrentSettings() { PathEntry.Text = Preferences.Default.Get(PhotoPathKey, @"C:\FrymasterData\photos"); LogoPathEntry.Text = Preferences.Default.Get(LogoPathKey, @"C:\FrymasterData\logos"); ImagesPathEntry.Text = Preferences.Default.Get(ImagesPathKey, @"C:\FrymasterData\images"); } private void LoadCurrentThemePreference() { var pref = Preferences.Default.Get(ThemePrefKey, "System"); switch (pref) { case "Light": ThemePicker.SelectedIndex = 1; Application.Current.UserAppTheme = AppTheme.Light; break; case "Dark": ThemePicker.SelectedIndex = 2; Application.Current.UserAppTheme = AppTheme.Dark; break; default: ThemePicker.SelectedIndex = 0; Application.Current.UserAppTheme = AppTheme.Unspecified; break; } } private void ApplyThemeSelection() { if (ThemePicker == null) return; var sel = ThemePicker.SelectedIndex; switch (sel) { case 1: // Light Application.Current.UserAppTheme = AppTheme.Light; Preferences.Default.Set(ThemePrefKey, "Light"); break; case 2: // Dark Application.Current.UserAppTheme = AppTheme.Dark; Preferences.Default.Set(ThemePrefKey, "Dark"); break; default: // System Application.Current.UserAppTheme = AppTheme.Unspecified; Preferences.Default.Set(ThemePrefKey, "System"); break; } } private async void OnPickPhotoFolderClicked(object sender, EventArgs e) => await PickFolderAsync(r => PathEntry.Text = r.Folder.Path, "Select Photos Folder"); private async void OnPickLogoFolderClicked(object sender, EventArgs e) => await PickFolderAsync(r => LogoPathEntry.Text = r.Folder.Path, "Select Logos Folder"); private async void OnPickImagesFolderClicked(object sender, EventArgs e) => await PickFolderAsync(r => ImagesPathEntry.Text = r.Folder.Path, "Select Images Folder"); private async Task PickFolderAsync(Action onSuccess, string title) { try { var result = await FolderPicker.Default.PickAsync(title, CancellationToken.None); if (result.IsSuccessful) { onSuccess(result); VerifyDirectory(result.Folder.Path); } } catch (Exception ex) { await DisplayAlert("Error", ex.Message, "OK"); } } private async void OnSaveClicked(object sender, EventArgs e) { AppLogger.Info("Save settings clicked - start"); var photoPath = PathEntry?.Text?.Trim(); var logoPath = LogoPathEntry?.Text?.Trim(); var imagesPath = ImagesPathEntry?.Text?.Trim(); AppLogger.Info( $"Paths collected → Photos: '{photoPath ?? "null"}', Logos: '{logoPath ?? "null"}', Images: '{imagesPath ?? "null"}'" ); if ( string.IsNullOrWhiteSpace(photoPath) || string.IsNullOrWhiteSpace(logoPath) || string.IsNullOrWhiteSpace(imagesPath) ) { AppLogger.Warning("Validation failed - one or more paths empty"); await DisplayAlert("Error", "All folders must be selected.", "OK"); return; } try { AppLogger.Info("Saving preferences..."); Preferences.Default.Set(PhotoPathKey, photoPath); Preferences.Default.Set(LogoPathKey, logoPath); Preferences.Default.Set(ImagesPathKey, imagesPath); AppLogger.Info("Preferences saved OK"); StatusLabel.Text = "Settings saved successfully!"; StatusLabel.TextColor = Colors.Green; // Toast is optional & wrapped — comment out if still crashes try { await MainThread.InvokeOnMainThreadAsync(async () => { await Toast .Make("Settings saved ✓", CommunityToolkit.Maui.Core.ToastDuration.Short) .Show(); }); } catch (Exception toastEx) { AppLogger.Warn("Toast failed (non-critical)"); } // NO auto-navigation — let user press back button manually // This avoids 90% of known Shell navigation crashes } catch (Exception ex) { AppLogger.Error("Critical save failure", ex); StatusLabel.Text = $"Save failed: {ex.Message}"; StatusLabel.TextColor = Colors.Red; await DisplayAlert( "Save Error", $"{ex.GetType().Name}: {ex.Message}\n\nCheck logs for details.", "OK" ); } finally { AppLogger.Info("Save settings handler finished"); } } // private static void SafeCreateDirectory(string? path) // { // if (string.IsNullOrWhiteSpace(path)) return; // try // { // if (!Directory.Exists(path)) // { // AppLogger.Info($"Creating directory: {path}"); // Directory.CreateDirectory(path); // } // else // { // AppLogger.Info($"Directory already exists: {path}"); // } // } // catch (Exception ex) // { // AppLogger.Error($"Failed to create/verify directory '{path}'", ex); // throw; // rethrow so main catch can handle it // } // } // Helper - prevents crash on invalid paths private static void SafeCreateDirectory(string path) { if (string.IsNullOrWhiteSpace(path)) return; try { Directory.CreateDirectory(path); } catch (Exception ex) { // Log but don't crash the app System.Diagnostics.Debug.WriteLine( $"Directory creation failed for '{path}': {ex.Message}" ); // You could also show a warning here if needed } } private static void VerifyDirectory(string path) { if (!Directory.Exists(path)) Directory.CreateDirectory(path); } }