FrymasterBadgeApp/SettingsPage.xaml.cs

231 lines
7.3 KiB
C#

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<FolderPickerResult> 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);
}
}