From 001b7cabb338ca543de09ac25b5e8f1c0a0ca8da Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Fri, 24 Oct 2025 07:02:04 +0200
Subject: [PATCH 01/16] feat: added FolderPicker for installation popup to
choose installation location
---
.../Popups/InstallGamePopup.xaml | 12 +-
.../Popups/InstallGamePopup.xaml.cs | 95 +++++++++++----
.../Dictionary/LanguageResources.ar.xaml | 2 +
.../Dictionary/LanguageResources.de.xaml | 6 +-
.../Dictionary/LanguageResources.en.xaml | 4 +-
.../Dictionary/LanguageResources.es.xaml | 2 +
.../Dictionary/LanguageResources.fr.xaml | 2 +
.../Dictionary/LanguageResources.hu.xaml | 3 +
.../Dictionary/LanguageResources.it.xaml | 2 +
.../Dictionary/LanguageResources.nl.xaml | 2 +
.../Dictionary/LanguageResources.no.xaml | 2 +
.../Dictionary/LanguageResources.pl.xaml | 2 +
.../Dictionary/LanguageResources.ru.xaml | 2 +
.../Dictionary/LanguageResources.sv.xaml | 2 +
.../Dictionary/LanguageResources.tr.xaml | 4 +-
.../Utils/FolderPicker.cs | 113 ++++++++++++++++++
16 files changed, 223 insertions(+), 32 deletions(-)
create mode 100644 src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index 31ce196..c14ba04 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -62,14 +62,18 @@
-
-
-
+
+
-
+
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index 38815dd..f96461f 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -11,38 +11,91 @@ namespace BfmeFoundationProject.AllInOneLauncher.Popups;
public partial class InstallGamePopup : PopupBody
{
private static readonly Dictionary Drives = DriveInfo.GetDrives().ToDictionary(x => x.RootDirectory.FullName);
+ private string _defaultPath = string.Empty;
public InstallGamePopup()
{
InitializeComponent();
+ // Initialize the select-folder button with the first available drive as default
+ try
+ {
+ var firstReady = Drives.Values.FirstOrDefault(d => d.IsReady);
+ if (firstReady != null)
+ {
+ _defaultPath = firstReady.RootDirectory.FullName;
+ SelectFolderError.Visibility = Visibility.Collapsed;
+ SelectFolderButton.Visibility = Visibility.Visible;
+ SetSelectedPath(_defaultPath);
+ }
+ }
+ catch (Exception ex)
+ {
+ PopupVisualizer.ShowPopup(new ErrorPopup(ex), OnPopupClosed: () => Dismiss());
+ }
+ }
- locations.Children.Clear();
- foreach (var drive in Drives.Values)
+ private void SetSelectedPath(string path)
+ {
+ string _selectedPath;
+ var _selectedFreeText = string.Empty;
+ try
{
- if (!drive.IsReady)
- continue;
+ _selectedPath = Path.GetFullPath(path); // validate path
+ var drive = GetReadyDriveForPath(_selectedPath);
+ if(drive == null) {
+ _selectedPath = _defaultPath;
+ }
+ }
+ catch {
+ _selectedPath = _defaultPath;
+ }
- try
- {
- locations.Children.Add(new Selectable()
- {
- Title = new LibraryDriveHeader()
- {
- LibraryDriveName = string.Concat(drive.VolumeLabel, " (", drive.Name.Replace(@"\", ""), ")"),
- LibraryDriveSize = $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}",
- Mini = true
- },
- Tag = drive.RootDirectory.FullName,
- Margin = new Thickness(0, 0, 0, 5),
- UseLayoutRounding = true,
- SnapsToDevicePixels = true
- });
+ try
+ {
+ var drive = GetReadyDriveForPath(_selectedPath);
+ if(drive != null) {
+ _selectedFreeText = $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}";
}
- catch { }
+ }
+ catch { /* ignore errors here */ }
+
+ SelectedPathText.Text = _selectedPath;
+ SelectedFreeText.Text = _selectedFreeText;
+ ButtonAccept.IsEnabled = !string.IsNullOrWhiteSpace(_selectedPath);
+ }
+
+ private DriveInfo? GetReadyDriveForPath(string path)
+ {
+ var driveRoot = Path.GetPathRoot(path);
+ if (driveRoot != null && Drives.TryGetValue(driveRoot, out var drive) && drive.IsReady)
+ {
+ return drive;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ var ownerWindow = Window.GetWindow(this);
+ var folderDialogTitle = (string)App.Current.FindResource("InstallGamePopupSelectFolder");
+ var _selectedPath = SelectedPathText.Text;
+ var selected = Utils.FolderPicker.ShowDialog(ownerWindow, folderDialogTitle, _selectedPath);
+ if (!string.IsNullOrWhiteSpace(selected))
+ SetSelectedPath(selected);
+ }
+ catch (Exception ex)
+ {
+ PopupVisualizer.ShowPopup(new ErrorPopup(ex));
+ Dismiss();
}
}
- private void OnInstallClicked(object sender, RoutedEventArgs e) => Submit(LanguageDropdown.SelectedValue, Selectable.GetSelectedTagInContainer(locations)!.ToString()!);
+ private void OnInstallClicked(object sender, RoutedEventArgs e) => Submit(LanguageDropdown.SelectedValue, SelectedPathText.Text);
private void OnCancelClicked(object sender, RoutedEventArgs e) => Dismiss();
}
\ No newline at end of file
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml
index b83cc5b..d972a5b 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml
@@ -107,6 +107,8 @@
تثبيت اللعبة
اللغة
الموقع
+ اختر مجلد التثبيت
+ لا توجد أقراص متاحة
إضافة إلى المكتبة
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
index 2ab564d..80a7457 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
@@ -15,13 +15,11 @@
LADEN
SPIELEN
HINZUFÜGEN
- KOSTENLOS
+ FREI
BESTÄTIGEN
JA
NEIN
-
-
EINZELSPIELER
Mehrspieler
@@ -119,6 +117,8 @@
SPIEL INSTALLIEREN
Sprache
Standort
+ Installationsordner wählen
+ Keine Laufwerke verfügbar
ZUR BIBLIOTHEK HINZUFÜGEN
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml
index 4af525c..6c2c246 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml
@@ -20,8 +20,6 @@
YES
NO
-
-
SINGLEPLAYER
MULTIPLAYER
@@ -121,6 +119,8 @@
INSTALL GAME
Language
Location
+ Select installation folder
+ No drives available
ADD TO LIBRARY
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml
index 5ffe176..55a13ca 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml
@@ -107,6 +107,8 @@
INSTALAR JUEGO
Idioma
Ubicación
+ Seleccionar carpeta de instalación
+ No hay unidades disponibles
AÑADIR A LA BIBLIOTECA
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml
index 91e8193..61bf5f0 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml
@@ -107,6 +107,8 @@
INSTALLER LE JEU
Langue
Emplacement
+ Sélectionner le dossier d'installation
+ Aucun disque disponible
AJOUTER À LA BIBLIOTHÈQUE
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml
index 3b22fb9..1cc442d 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml
@@ -17,6 +17,7 @@
IGEN
IGEN
NEM
+ FIGYELMEZTETÉS
EGYJÁTÉKOS
@@ -107,6 +108,8 @@
JÁTÉK TELEPÍTÉSE
Nyelv
Helyszín
+ Válassza ki a telepítési mappát
+ Nincsenek elérhető meghajtók
KÖNYVTÁRBAN HOZZÁADÁS
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml
index 46b8eaf..a6acf63 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml
@@ -107,6 +107,8 @@
INSTALLA GIOCO
Lingua
Posizione
+ Seleziona la cartella di installazione
+ Nessun disco disponibile
AGGIUNGI ALLA BIBLIOTECA
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml
index 960e47e..40ec691 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml
@@ -107,6 +107,8 @@
GAME INSTALLEREN
Taal
Locatie
+ Selecteer installatiemap
+ Geen stations beschikbaar
TOEVOEGEN AAN BIBLIOTHEEK
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml
index 65a5a5b..194a134 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml
@@ -107,6 +107,8 @@
INSTALLER SPILL
Språk
Beliggenhet
+ Velg installasjonsmappe
+ Ingen stasjoner tilgjengelig
LEGG TIL I BIBLIOTEKET
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml
index eda66b0..cba0a00 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml
@@ -107,6 +107,8 @@
INSTALUJ GRĘ
Język
Lokalizacja
+ Wybierz folder instalacyjny
+ Brak dostępnych dysków
DODAJ DO BIBLIOTEKI
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml
index 9733594..164d4d7 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml
@@ -107,6 +107,8 @@
УСТАНОВКА ИГРЫ
Язык
Местоположение
+ Выберите папку для установки
+ Дисков не найдено
ДОБАВИТЬ В БИБЛИОТЕКУ
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml
index 16ecd23..9945626 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml
@@ -107,6 +107,8 @@
INSTALLERA SPEL
Språk
Plats
+ Välj installationsmapp
+ Inga enheter tillgängliga
LÄGG TILL I BIBLIOTEKET
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml
index 76a3df6..754d9ea 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml
@@ -20,8 +20,6 @@
EVET
HAYIR
-
-
TEK OYUNCU
ÇOK OYUNCULU
@@ -121,6 +119,8 @@
OYUNU YÜKLE
Dil
Konum
+ Yükleme klasörünü seçin
+ Hiçbir sürücü bulunamadı
KÜTÜPHANEYE EKLE
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs b/src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs
new file mode 100644
index 0000000..4e94148
--- /dev/null
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows;
+
+namespace BfmeFoundationProject.AllInOneLauncher.Utils
+{
+ internal static class FolderPicker
+ {
+ public static string? ShowDialog(Window owner, string title = "", string? initialPath = null)
+ {
+ IntPtr ownerHandle = new System.Windows.Interop.WindowInteropHelper(owner).Handle;
+ return InternalShowDialog(ownerHandle, title, initialPath);
+ }
+
+ private static string? InternalShowDialog(IntPtr ownerHandle, string title, string? initialPath)
+ {
+ // Constants
+ const int MAX_PATH = 260;
+ const uint BIF_RETURNONLYFSDIRS = 0x0001;
+ const uint BIF_NEWDIALOGSTYLE = 0x0040;
+ const uint BIF_EDITBOX = 0x0010;
+ const uint BIF_SHAREABLE = 0x8000;
+ const int BFFM_INITIALIZED = 1;
+ const int BFFM_SETSELECTIONW = 0x0467; // WM_USER + 103 (Unicode)
+
+ BrowseCallbackProc callback = (hwnd, msg, lParam, lpData) =>
+ {
+ if (msg == BFFM_INITIALIZED && lpData != IntPtr.Zero)
+ {
+ // lpData contains pointer to initial path (Unicode)
+ SendMessage(hwnd, BFFM_SETSELECTIONW, new IntPtr(1), lpData);
+ }
+ return 0;
+ };
+
+ IntPtr pidl = IntPtr.Zero;
+ IntPtr pszDisplayName = IntPtr.Zero;
+ IntPtr initialPathPtr = IntPtr.Zero;
+ try
+ {
+ pszDisplayName = Marshal.AllocHGlobal(MAX_PATH * 2);
+
+ var bi = new BROWSEINFO
+ {
+ hwndOwner = ownerHandle,
+ pidlRoot = IntPtr.Zero,
+ pszDisplayName = pszDisplayName,
+ lpszTitle = title,
+ ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_SHAREABLE,
+ lpfn = callback,
+ lParam = IntPtr.Zero,
+ iImage = 0
+ };
+
+ if (!string.IsNullOrWhiteSpace(initialPath))
+ {
+ initialPathPtr = Marshal.StringToHGlobalUni(initialPath);
+ bi.lParam = initialPathPtr;
+ }
+
+ pidl = SHBrowseForFolder(ref bi);
+ if (pidl == IntPtr.Zero)
+ return null;
+
+ var sb = new StringBuilder(MAX_PATH);
+ if (SHGetPathFromIDList(pidl, sb))
+ {
+ return sb.ToString();
+ }
+
+ return null;
+ }
+ finally
+ {
+ if (initialPathPtr != IntPtr.Zero) Marshal.FreeHGlobal(initialPathPtr);
+ if (pszDisplayName != IntPtr.Zero) Marshal.FreeHGlobal(pszDisplayName);
+ if (pidl != IntPtr.Zero) CoTaskMemFree(pidl);
+ }
+ }
+
+ #region Native
+ private delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ private struct BROWSEINFO
+ {
+ public IntPtr hwndOwner;
+ public IntPtr pidlRoot;
+ public IntPtr pszDisplayName;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string lpszTitle;
+ public uint ulFlags;
+ [MarshalAs(UnmanagedType.FunctionPtr)]
+ public BrowseCallbackProc lpfn;
+ public IntPtr lParam;
+ public int iImage;
+ }
+
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
+ private static extern IntPtr SHBrowseForFolder([In] ref BROWSEINFO lpbi);
+
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
+ private static extern bool SHGetPathFromIDList(IntPtr pidl, [Out] StringBuilder pszPath);
+
+ [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
+ private static extern void CoTaskMemFree(IntPtr pv);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
+ #endregion
+ }
+}
From ad30719660f9a10bcbfa20f723116007eedb6faa Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Fri, 24 Oct 2025 20:02:28 +0200
Subject: [PATCH 02/16] fix: Move FolderPicker
---
.../Elements/Native/FolderPicker.cs | 112 +++++++++++++++++
.../Popups/InstallGamePopup.xaml.cs | 3 +-
.../Utils/FolderPicker.cs | 113 ------------------
3 files changed, 114 insertions(+), 114 deletions(-)
create mode 100644 src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
delete mode 100644 src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
new file mode 100644
index 0000000..0c502d1
--- /dev/null
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows;
+
+namespace BfmeFoundationProject.AllInOneLauncher.Elements.Native;
+
+internal static class FolderPicker
+{
+ public static string? ShowDialog(Window owner, string title = "", string? initialPath = null)
+ {
+ IntPtr ownerHandle = new System.Windows.Interop.WindowInteropHelper(owner).Handle;
+ return InternalShowDialog(ownerHandle, title, initialPath);
+ }
+
+ private static string? InternalShowDialog(IntPtr ownerHandle, string title, string? initialPath)
+ {
+ // Constants
+ const int MAX_PATH = 260;
+ const uint BIF_RETURNONLYFSDIRS = 0x0001;
+ const uint BIF_NEWDIALOGSTYLE = 0x0040;
+ const uint BIF_EDITBOX = 0x0010;
+ const uint BIF_SHAREABLE = 0x8000;
+ const int BFFM_INITIALIZED = 1;
+ const int BFFM_SETSELECTIONW = 0x0467; // WM_USER + 103 (Unicode)
+
+ BrowseCallbackProc callback = (hwnd, msg, lParam, lpData) =>
+ {
+ if (msg == BFFM_INITIALIZED && lpData != IntPtr.Zero)
+ {
+ // lpData contains pointer to initial path (Unicode)
+ SendMessage(hwnd, BFFM_SETSELECTIONW, new IntPtr(1), lpData);
+ }
+ return 0;
+ };
+
+ IntPtr pidl = IntPtr.Zero;
+ IntPtr pszDisplayName = IntPtr.Zero;
+ IntPtr initialPathPtr = IntPtr.Zero;
+ try
+ {
+ pszDisplayName = Marshal.AllocHGlobal(MAX_PATH * 2);
+
+ var bi = new BROWSEINFO
+ {
+ hwndOwner = ownerHandle,
+ pidlRoot = IntPtr.Zero,
+ pszDisplayName = pszDisplayName,
+ lpszTitle = title,
+ ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_SHAREABLE,
+ lpfn = callback,
+ lParam = IntPtr.Zero,
+ iImage = 0
+ };
+
+ if (!string.IsNullOrWhiteSpace(initialPath))
+ {
+ initialPathPtr = Marshal.StringToHGlobalUni(initialPath);
+ bi.lParam = initialPathPtr;
+ }
+
+ pidl = SHBrowseForFolder(ref bi);
+ if (pidl == IntPtr.Zero)
+ return null;
+
+ var sb = new StringBuilder(MAX_PATH);
+ if (SHGetPathFromIDList(pidl, sb))
+ {
+ return sb.ToString();
+ }
+
+ return null;
+ }
+ finally
+ {
+ if (initialPathPtr != IntPtr.Zero) Marshal.FreeHGlobal(initialPathPtr);
+ if (pszDisplayName != IntPtr.Zero) Marshal.FreeHGlobal(pszDisplayName);
+ if (pidl != IntPtr.Zero) CoTaskMemFree(pidl);
+ }
+ }
+
+ #region Native
+ private delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ private struct BROWSEINFO
+ {
+ public IntPtr hwndOwner;
+ public IntPtr pidlRoot;
+ public IntPtr pszDisplayName;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string lpszTitle;
+ public uint ulFlags;
+ [MarshalAs(UnmanagedType.FunctionPtr)]
+ public BrowseCallbackProc lpfn;
+ public IntPtr lParam;
+ public int iImage;
+ }
+
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
+ private static extern IntPtr SHBrowseForFolder([In] ref BROWSEINFO lpbi);
+
+ [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
+ private static extern bool SHGetPathFromIDList(IntPtr pidl, [Out] StringBuilder pszPath);
+
+ [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
+ private static extern void CoTaskMemFree(IntPtr pv);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
+ #endregion
+}
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index f96461f..4fc2573 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -5,6 +5,7 @@
using System.Windows;
using BfmeFoundationProject.AllInOneLauncher.Elements.Disk;
using BfmeFoundationProject.AllInOneLauncher.Elements.Generic;
+using BfmeFoundationProject.AllInOneLauncher.Elements.Native;
namespace BfmeFoundationProject.AllInOneLauncher.Popups;
@@ -84,7 +85,7 @@ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
var ownerWindow = Window.GetWindow(this);
var folderDialogTitle = (string)App.Current.FindResource("InstallGamePopupSelectFolder");
var _selectedPath = SelectedPathText.Text;
- var selected = Utils.FolderPicker.ShowDialog(ownerWindow, folderDialogTitle, _selectedPath);
+ var selected = FolderPicker.ShowDialog(ownerWindow, folderDialogTitle, _selectedPath);
if (!string.IsNullOrWhiteSpace(selected))
SetSelectedPath(selected);
}
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs b/src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs
deleted file mode 100644
index 4e94148..0000000
--- a/src/BfmeFoundationProject_AllInOneLauncher/Utils/FolderPicker.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Windows;
-
-namespace BfmeFoundationProject.AllInOneLauncher.Utils
-{
- internal static class FolderPicker
- {
- public static string? ShowDialog(Window owner, string title = "", string? initialPath = null)
- {
- IntPtr ownerHandle = new System.Windows.Interop.WindowInteropHelper(owner).Handle;
- return InternalShowDialog(ownerHandle, title, initialPath);
- }
-
- private static string? InternalShowDialog(IntPtr ownerHandle, string title, string? initialPath)
- {
- // Constants
- const int MAX_PATH = 260;
- const uint BIF_RETURNONLYFSDIRS = 0x0001;
- const uint BIF_NEWDIALOGSTYLE = 0x0040;
- const uint BIF_EDITBOX = 0x0010;
- const uint BIF_SHAREABLE = 0x8000;
- const int BFFM_INITIALIZED = 1;
- const int BFFM_SETSELECTIONW = 0x0467; // WM_USER + 103 (Unicode)
-
- BrowseCallbackProc callback = (hwnd, msg, lParam, lpData) =>
- {
- if (msg == BFFM_INITIALIZED && lpData != IntPtr.Zero)
- {
- // lpData contains pointer to initial path (Unicode)
- SendMessage(hwnd, BFFM_SETSELECTIONW, new IntPtr(1), lpData);
- }
- return 0;
- };
-
- IntPtr pidl = IntPtr.Zero;
- IntPtr pszDisplayName = IntPtr.Zero;
- IntPtr initialPathPtr = IntPtr.Zero;
- try
- {
- pszDisplayName = Marshal.AllocHGlobal(MAX_PATH * 2);
-
- var bi = new BROWSEINFO
- {
- hwndOwner = ownerHandle,
- pidlRoot = IntPtr.Zero,
- pszDisplayName = pszDisplayName,
- lpszTitle = title,
- ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_SHAREABLE,
- lpfn = callback,
- lParam = IntPtr.Zero,
- iImage = 0
- };
-
- if (!string.IsNullOrWhiteSpace(initialPath))
- {
- initialPathPtr = Marshal.StringToHGlobalUni(initialPath);
- bi.lParam = initialPathPtr;
- }
-
- pidl = SHBrowseForFolder(ref bi);
- if (pidl == IntPtr.Zero)
- return null;
-
- var sb = new StringBuilder(MAX_PATH);
- if (SHGetPathFromIDList(pidl, sb))
- {
- return sb.ToString();
- }
-
- return null;
- }
- finally
- {
- if (initialPathPtr != IntPtr.Zero) Marshal.FreeHGlobal(initialPathPtr);
- if (pszDisplayName != IntPtr.Zero) Marshal.FreeHGlobal(pszDisplayName);
- if (pidl != IntPtr.Zero) CoTaskMemFree(pidl);
- }
- }
-
- #region Native
- private delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData);
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- private struct BROWSEINFO
- {
- public IntPtr hwndOwner;
- public IntPtr pidlRoot;
- public IntPtr pszDisplayName;
- [MarshalAs(UnmanagedType.LPWStr)]
- public string lpszTitle;
- public uint ulFlags;
- [MarshalAs(UnmanagedType.FunctionPtr)]
- public BrowseCallbackProc lpfn;
- public IntPtr lParam;
- public int iImage;
- }
-
- [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
- private static extern IntPtr SHBrowseForFolder([In] ref BROWSEINFO lpbi);
-
- [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
- private static extern bool SHGetPathFromIDList(IntPtr pidl, [Out] StringBuilder pszPath);
-
- [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
- private static extern void CoTaskMemFree(IntPtr pv);
-
- [DllImport("user32.dll", CharSet = CharSet.Unicode)]
- private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
- #endregion
- }
-}
From 8972c6cee628fc0ab192fd50fe4a61c5dde78421 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Fri, 24 Oct 2025 20:36:32 +0200
Subject: [PATCH 03/16] fix: refactored code to DriveUtils class
---
.../Popups/InstallGamePopup.xaml.cs | 24 +++---------
.../Utils/DriveUtils.cs | 39 +++++++++++++++++++
2 files changed, 45 insertions(+), 18 deletions(-)
create mode 100644 src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index 4fc2573..82ce8e7 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Windows;
+using BfmeFoundationProject.AllInOneLauncher.Core.Utils;
using BfmeFoundationProject.AllInOneLauncher.Elements.Disk;
using BfmeFoundationProject.AllInOneLauncher.Elements.Generic;
using BfmeFoundationProject.AllInOneLauncher.Elements.Native;
@@ -11,19 +12,18 @@ namespace BfmeFoundationProject.AllInOneLauncher.Popups;
public partial class InstallGamePopup : PopupBody
{
- private static readonly Dictionary Drives = DriveInfo.GetDrives().ToDictionary(x => x.RootDirectory.FullName);
+ private static readonly List _drives = DriveUtils.GetValidDrives();
private string _defaultPath = string.Empty;
public InstallGamePopup()
{
InitializeComponent();
- // Initialize the select-folder button with the first available drive as default
try
{
- var firstReady = Drives.Values.FirstOrDefault(d => d.IsReady);
+ var firstReady = _drives.FirstOrDefault();
if (firstReady != null)
{
- _defaultPath = firstReady.RootDirectory.FullName;
+ _defaultPath = DriveUtils.GetDriveRootName(firstReady);
SelectFolderError.Visibility = Visibility.Collapsed;
SelectFolderButton.Visibility = Visibility.Visible;
SetSelectedPath(_defaultPath);
@@ -42,7 +42,7 @@ private void SetSelectedPath(string path)
try
{
_selectedPath = Path.GetFullPath(path); // validate path
- var drive = GetReadyDriveForPath(_selectedPath);
+ var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
if(drive == null) {
_selectedPath = _defaultPath;
}
@@ -53,7 +53,7 @@ private void SetSelectedPath(string path)
try
{
- var drive = GetReadyDriveForPath(_selectedPath);
+ var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
if(drive != null) {
_selectedFreeText = $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}";
}
@@ -65,18 +65,6 @@ private void SetSelectedPath(string path)
ButtonAccept.IsEnabled = !string.IsNullOrWhiteSpace(_selectedPath);
}
- private DriveInfo? GetReadyDriveForPath(string path)
- {
- var driveRoot = Path.GetPathRoot(path);
- if (driveRoot != null && Drives.TryGetValue(driveRoot, out var drive) && drive.IsReady)
- {
- return drive;
- }
- else
- {
- return null;
- }
- }
private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
{
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
new file mode 100644
index 0000000..f2f2a44
--- /dev/null
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
@@ -0,0 +1,39 @@
+using System;
+using System.IO;
+
+namespace BfmeFoundationProject.AllInOneLauncher.Core.Utils;
+
+public class DriveUtils
+{
+ /**
+ Only Local Disk drives that are ready are valid.
+ No Network or removable drives.
+ */
+ public static bool IsValidDrive(DriveInfo drive)
+ {
+ return drive.DriveType == DriveType.Fixed && drive.IsReady;
+ }
+
+ public static List GetValidDrives()
+ {
+ return DriveInfo.GetDrives().Where(d => IsValidDrive(d)).ToList();
+ }
+
+ public static DriveInfo? GetDriveForPath(List somedrives, string path)
+ {
+ DriveInfo? drive = null;
+
+ var driveRoot = Path.GetPathRoot(path);
+ if (driveRoot != null)
+ {
+ drive = somedrives.FirstOrDefault(d => GetDriveRootName(d).Equals(driveRoot, StringComparison.OrdinalIgnoreCase));
+ }
+
+ return drive;
+ }
+
+ public static string GetDriveRootName(DriveInfo drive)
+ {
+ return drive.RootDirectory.FullName;
+ }
+}
From 6191e6e49e7555a3ff48349d0a6c43baf9ebe9a1 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 26 Oct 2025 01:18:19 +0200
Subject: [PATCH 04/16] fix: update folderpicker
---
.../Elements/Native/FolderPicker.cs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
index 0c502d1..b8b292d 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
@@ -19,8 +19,6 @@ internal static class FolderPicker
const int MAX_PATH = 260;
const uint BIF_RETURNONLYFSDIRS = 0x0001;
const uint BIF_NEWDIALOGSTYLE = 0x0040;
- const uint BIF_EDITBOX = 0x0010;
- const uint BIF_SHAREABLE = 0x8000;
const int BFFM_INITIALIZED = 1;
const int BFFM_SETSELECTIONW = 0x0467; // WM_USER + 103 (Unicode)
@@ -47,7 +45,7 @@ internal static class FolderPicker
pidlRoot = IntPtr.Zero,
pszDisplayName = pszDisplayName,
lpszTitle = title,
- ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_SHAREABLE,
+ ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE,
lpfn = callback,
lParam = IntPtr.Zero,
iImage = 0
From d75401538bf3706bc5a9bc1c0776f6fb637c210d Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 26 Oct 2025 02:38:23 +0100
Subject: [PATCH 05/16] feat: Location selektion updates. Use old behavior as
default, but make advanced selektion possible
---
.../Converter/BooleanToVisibilityConverter.cs | 58 ++++++++++++++++
.../Popups/InstallGamePopup.xaml | 53 ++++++++++++--
.../Popups/InstallGamePopup.xaml.cs | 69 ++++++++++++++-----
.../Dictionary/LanguageResources.ar.xaml | 1 +
.../Dictionary/LanguageResources.de.xaml | 1 +
.../Dictionary/LanguageResources.en.xaml | 1 +
.../Dictionary/LanguageResources.es.xaml | 1 +
.../Dictionary/LanguageResources.fr.xaml | 1 +
.../Dictionary/LanguageResources.hu.xaml | 1 +
.../Dictionary/LanguageResources.it.xaml | 1 +
.../Dictionary/LanguageResources.nl.xaml | 1 +
.../Dictionary/LanguageResources.no.xaml | 1 +
.../Dictionary/LanguageResources.pl.xaml | 1 +
.../Dictionary/LanguageResources.ru.xaml | 1 +
.../Dictionary/LanguageResources.sv.xaml | 1 +
.../Dictionary/LanguageResources.tr.xaml | 1 +
.../Utils/DriveUtils.cs | 10 ++-
17 files changed, 180 insertions(+), 23 deletions(-)
create mode 100644 src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
new file mode 100644
index 0000000..bf5e517
--- /dev/null
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace BfmeFoundationProject.AllInOneLauncher.Elements.Converter
+{
+ ///
+ /// Converts a boolean to Visibility.
+ /// Supports optional inversion via ConverterParameter="invert" (case-insensitive).
+ /// Also supports hiding mode via ConverterParameter="hidden" to return Visibility.Hidden instead of Collapsed when false.
+ /// You can combine parameters with a comma: "invert,hidden".
+ ///
+ public class BooleanToVisibilityConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ bool isTrue = false;
+
+ if (value is bool b)
+ isTrue = b;
+ else if (value is bool?)
+ isTrue = (bool?)value ?? false;
+
+ bool invert = false;
+ bool useHidden = false;
+
+ if (parameter is string s && !string.IsNullOrWhiteSpace(s))
+ {
+ var parts = s.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var p in parts)
+ {
+ var tp = p.Trim().ToLowerInvariant();
+ if (tp == "invert" || tp == "!" )
+ invert = true;
+ if (tp == "hidden")
+ useHidden = true;
+ }
+ }
+
+ if (invert)
+ isTrue = !isTrue;
+
+ if (isTrue)
+ return Visibility.Visible;
+
+ return useHidden ? Visibility.Hidden : Visibility.Collapsed;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is Visibility v)
+ return v == Visibility.Visible;
+
+ return DependencyProperty.UnsetValue;
+ }
+ }
+}
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index c14ba04..36287c3 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -5,10 +5,16 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Popups"
xmlns:elements="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements"
+ xmlns:converter="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements.Converter"
xmlns:system="clr-namespace:System;assembly=netstandard"
xmlns:generic="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements.Generic"
mc:Ignorable="d"
Width="700" HorizontalAlignment="Center" VerticalAlignment="Center">
+
+
+
+
+
@@ -17,7 +23,7 @@
-
+
@@ -45,6 +51,8 @@
+
+
@@ -62,13 +70,48 @@
-
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index 82ce8e7..8be727d 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -13,20 +13,45 @@ namespace BfmeFoundationProject.AllInOneLauncher.Popups;
public partial class InstallGamePopup : PopupBody
{
private static readonly List _drives = DriveUtils.GetValidDrives();
- private string _defaultPath = string.Empty;
+ private string _defaultPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
public InstallGamePopup()
{
InitializeComponent();
try
{
- var firstReady = _drives.FirstOrDefault();
- if (firstReady != null)
+ if (_drives.Count == 0)
{
- _defaultPath = DriveUtils.GetDriveRootName(firstReady);
- SelectFolderError.Visibility = Visibility.Collapsed;
- SelectFolderButton.Visibility = Visibility.Visible;
- SetSelectedPath(_defaultPath);
+ SelectLocationError.Visibility = Visibility.Visible;
+ SelectLocationList.Visibility = Visibility.Collapsed;
+ SelectFolderButton.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ locations.Children.Clear();
+ _drives.ForEach(drive =>
+ {
+ locations.Children.Add(new Selectable()
+ {
+ Title = new LibraryDriveHeader()
+ {
+ LibraryDriveName = string.Concat(drive.VolumeLabel, " (", drive.Name.Replace(@"\", ""), ")"),
+ LibraryDriveSize = GetDriveFreeSpaceFormatted(drive),
+ Mini = true
+ },
+ Tag = DriveUtils.GetDriveRootName(drive),
+ Margin = new Thickness(0, 0, 0, 5),
+ UseLayoutRounding = true,
+ SnapsToDevicePixels = true
+ });
+
+ });
+
+ var firstReady = _drives.FirstOrDefault();
+ if (firstReady != null)
+ {
+ SetSelectedPath(_defaultPath);
+ }
}
}
catch (Exception ex)
@@ -37,34 +62,41 @@ public InstallGamePopup()
private void SetSelectedPath(string path)
{
- string _selectedPath;
+ string? _selectedPath;
var _selectedFreeText = string.Empty;
try
{
- _selectedPath = Path.GetFullPath(path); // validate path
+ _selectedPath = DriveUtils.GetValidPath(path);
var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
- if(drive == null) {
+ if (drive == null)
+ {
_selectedPath = _defaultPath;
}
}
- catch {
+ catch
+ {
_selectedPath = _defaultPath;
- }
+ }
try
{
var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
- if(drive != null) {
- _selectedFreeText = $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}";
+ if (drive != null)
+ {
+ _selectedFreeText = GetDriveFreeSpaceFormatted(drive);
}
}
catch { /* ignore errors here */ }
SelectedPathText.Text = _selectedPath;
- SelectedFreeText.Text = _selectedFreeText;
+ SelectedFreeSpaceText.Text = _selectedFreeText;
ButtonAccept.IsEnabled = !string.IsNullOrWhiteSpace(_selectedPath);
}
+ private static string GetDriveFreeSpaceFormatted(DriveInfo drive)
+ {
+ return $"{Math.Floor(drive.AvailableFreeSpace / Math.Pow(1024, 3)):N0} GB {App.Current.FindResource("GenericFree")}";
+ }
private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
{
@@ -84,7 +116,12 @@ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
}
}
- private void OnInstallClicked(object sender, RoutedEventArgs e) => Submit(LanguageDropdown.SelectedValue, SelectedPathText.Text);
+ private void OnInstallClicked(object sender, RoutedEventArgs e)
+ {
+ var language = LanguageDropdown.SelectedValue;
+ var path = (SelectLocationAdvancedToggle.IsChecked == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
+ Submit(language, path);
+ }
private void OnCancelClicked(object sender, RoutedEventArgs e) => Dismiss();
}
\ No newline at end of file
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml
index d972a5b..d91ea84 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ar.xaml
@@ -107,6 +107,7 @@
تثبيت اللعبة
اللغة
الموقع
+ متقدم
اختر مجلد التثبيت
لا توجد أقراص متاحة
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
index 80a7457..e0a860d 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
@@ -117,6 +117,7 @@
SPIEL INSTALLIEREN
Sprache
Standort
+ Fortgeschritten
Installationsordner wählen
Keine Laufwerke verfügbar
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml
index 6c2c246..f5f9458 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.en.xaml
@@ -119,6 +119,7 @@
INSTALL GAME
Language
Location
+ Advanced
Select installation folder
No drives available
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml
index 55a13ca..80ad24c 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.es.xaml
@@ -107,6 +107,7 @@
INSTALAR JUEGO
Idioma
Ubicación
+ Avanzado
Seleccionar carpeta de instalación
No hay unidades disponibles
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml
index 61bf5f0..0306ecf 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.fr.xaml
@@ -107,6 +107,7 @@
INSTALLER LE JEU
Langue
Emplacement
+ Avancé
Sélectionner le dossier d'installation
Aucun disque disponible
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml
index 1cc442d..76fd584 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.hu.xaml
@@ -108,6 +108,7 @@
JÁTÉK TELEPÍTÉSE
Nyelv
Helyszín
+ Haladó
Válassza ki a telepítési mappát
Nincsenek elérhető meghajtók
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml
index a6acf63..ff9a199 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.it.xaml
@@ -107,6 +107,7 @@
INSTALLA GIOCO
Lingua
Posizione
+ Avanzato
Seleziona la cartella di installazione
Nessun disco disponibile
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml
index 40ec691..e397551 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.nl.xaml
@@ -107,6 +107,7 @@
GAME INSTALLEREN
Taal
Locatie
+ Geavanceerd
Selecteer installatiemap
Geen stations beschikbaar
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml
index 194a134..582ce87 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.no.xaml
@@ -107,6 +107,7 @@
INSTALLER SPILL
Språk
Beliggenhet
+ Avansert
Velg installasjonsmappe
Ingen stasjoner tilgjengelig
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml
index cba0a00..5274176 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.pl.xaml
@@ -107,6 +107,7 @@
INSTALUJ GRĘ
Język
Lokalizacja
+ Zaawansowane
Wybierz folder instalacyjny
Brak dostępnych dysków
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml
index 164d4d7..47d7b4a 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.ru.xaml
@@ -107,6 +107,7 @@
УСТАНОВКА ИГРЫ
Язык
Местоположение
+ Дополнительно
Выберите папку для установки
Дисков не найдено
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml
index 9945626..24d1f3c 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.sv.xaml
@@ -107,6 +107,7 @@
INSTALLERA SPEL
Språk
Plats
+ Avancerat
Välj installationsmapp
Inga enheter tillgängliga
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml
index 754d9ea..fb82d6d 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.tr.xaml
@@ -119,6 +119,7 @@
OYUNU YÜKLE
Dil
Konum
+ Gelişmiş
Yükleme klasörünü seçin
Hiçbir sürücü bulunamadı
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
index f2f2a44..c61efbb 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
@@ -19,12 +19,12 @@ public static List GetValidDrives()
return DriveInfo.GetDrives().Where(d => IsValidDrive(d)).ToList();
}
- public static DriveInfo? GetDriveForPath(List somedrives, string path)
+ public static DriveInfo? GetDriveForPath(List somedrives, string? path)
{
DriveInfo? drive = null;
var driveRoot = Path.GetPathRoot(path);
- if (driveRoot != null)
+ if (!string.IsNullOrWhiteSpace(driveRoot))
{
drive = somedrives.FirstOrDefault(d => GetDriveRootName(d).Equals(driveRoot, StringComparison.OrdinalIgnoreCase));
}
@@ -36,4 +36,10 @@ public static string GetDriveRootName(DriveInfo drive)
{
return drive.RootDirectory.FullName;
}
+
+ internal static string? GetValidPath(string path)
+ {
+ var fullpath = Path.GetFullPath(path);
+ return !fullpath.Contains(":\\Windows") && !fullpath.Contains("\\OneDrive") ? fullpath : null;
+ }
}
From 58b32f08bc139b492e73f0ad31d5f30b9f2becce Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 26 Oct 2025 21:56:17 +0100
Subject: [PATCH 06/16] feat: update layout and simplify error handling
---
.../Pages/Primary/Offline.xaml.cs | 11 ++-
.../Popups/InstallGamePopup.xaml | 92 ++++++++++---------
.../Popups/InstallGamePopup.xaml.cs | 59 ++++++------
3 files changed, 85 insertions(+), 77 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Pages/Primary/Offline.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Pages/Primary/Offline.xaml.cs
index e16a98e..5bad012 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Pages/Primary/Offline.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Pages/Primary/Offline.xaml.cs
@@ -113,8 +113,15 @@ private void OnLaunchGameClicked(object sender, EventArgs e)
private void OnInstallGameClicked(object sender, EventArgs e)
{
- PopupVisualizer.ShowPopup(new InstallGamePopup(),
- OnPopupSubmited: async (submittedData) => await BfmeSyncManager.InstallGame((BfmeGame)gameTabs.SelectedIndex, submittedData[0], submittedData[1]));
+ try
+ {
+ PopupVisualizer.ShowPopup(new InstallGamePopup(),
+ OnPopupSubmited: async (submittedData) => await BfmeSyncManager.InstallGame((BfmeGame)gameTabs.SelectedIndex, submittedData[0], submittedData[1]));
+ }
+ catch (Exception ex)
+ {
+ PopupVisualizer.ShowPopup(new ErrorPopup(ex));
+ }
}
private async void TabChanged(object sender, EventArgs e)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index 36287c3..aa0a8a4 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -51,8 +51,6 @@
-
-
@@ -70,48 +68,58 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index 8be727d..3f9766d 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -18,46 +18,39 @@ public partial class InstallGamePopup : PopupBody
public InstallGamePopup()
{
InitializeComponent();
- try
+
+ if (_drives.Count <= 0)
{
- if (_drives.Count == 0)
- {
- SelectLocationError.Visibility = Visibility.Visible;
- SelectLocationList.Visibility = Visibility.Collapsed;
- SelectFolderButton.Visibility = Visibility.Collapsed;
- }
- else
+ SelectLocationError.Visibility = Visibility.Visible;
+ SelectLocationArea.Visibility = Visibility.Collapsed;
+ }
+ else
+ {
+ locations.Children.Clear();
+ _drives.ForEach(drive =>
{
- locations.Children.Clear();
- _drives.ForEach(drive =>
+ locations.Children.Add(new Selectable()
{
- locations.Children.Add(new Selectable()
+ Title = new LibraryDriveHeader()
{
- Title = new LibraryDriveHeader()
- {
- LibraryDriveName = string.Concat(drive.VolumeLabel, " (", drive.Name.Replace(@"\", ""), ")"),
- LibraryDriveSize = GetDriveFreeSpaceFormatted(drive),
- Mini = true
- },
- Tag = DriveUtils.GetDriveRootName(drive),
- Margin = new Thickness(0, 0, 0, 5),
- UseLayoutRounding = true,
- SnapsToDevicePixels = true
- });
-
+ LibraryDriveName = string.Concat(drive.VolumeLabel, " (", drive.Name.Replace(@"\", ""), ")"),
+ LibraryDriveSize = GetDriveFreeSpaceFormatted(drive),
+ Mini = true
+ },
+ Tag = DriveUtils.GetDriveRootName(drive),
+ Margin = new Thickness(0, 0, 0, 5),
+ UseLayoutRounding = true,
+ SnapsToDevicePixels = true
});
- var firstReady = _drives.FirstOrDefault();
- if (firstReady != null)
- {
- SetSelectedPath(_defaultPath);
- }
+ });
+
+ var firstReady = _drives.FirstOrDefault();
+ if (firstReady != null)
+ {
+ SetSelectedPath(_defaultPath);
}
}
- catch (Exception ex)
- {
- PopupVisualizer.ShowPopup(new ErrorPopup(ex), OnPopupClosed: () => Dismiss());
- }
}
private void SetSelectedPath(string path)
@@ -119,7 +112,7 @@ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
private void OnInstallClicked(object sender, RoutedEventArgs e)
{
var language = LanguageDropdown.SelectedValue;
- var path = (SelectLocationAdvancedToggle.IsChecked == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
+ var path = (SelectLocationAdvancedToggle.IsChecked == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
Submit(language, path);
}
From b0d0392ee80acadebd8e78ea93e4e6dc1c4e8c71 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 26 Oct 2025 21:56:28 +0100
Subject: [PATCH 07/16] fix: cleanup
---
.../Elements/Converter/BooleanToVisibilityConverter.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
index bf5e517..141e3cd 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
@@ -7,7 +7,7 @@ namespace BfmeFoundationProject.AllInOneLauncher.Elements.Converter
{
///
/// Converts a boolean to Visibility.
- /// Supports optional inversion via ConverterParameter="invert" (case-insensitive).
+ /// Supports optional inversion via ConverterParameter="invert" or ConverterParameter="!" (case-insensitive).
/// Also supports hiding mode via ConverterParameter="hidden" to return Visibility.Hidden instead of Collapsed when false.
/// You can combine parameters with a comma: "invert,hidden".
///
@@ -17,17 +17,17 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
{
bool isTrue = false;
- if (value is bool b)
- isTrue = b;
+ if (value is bool valueBool)
+ isTrue = valueBool;
else if (value is bool?)
isTrue = (bool?)value ?? false;
bool invert = false;
bool useHidden = false;
- if (parameter is string s && !string.IsNullOrWhiteSpace(s))
+ if (parameter is string paramString && !string.IsNullOrWhiteSpace(paramString))
{
- var parts = s.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
+ var parts = paramString.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries);
foreach (var p in parts)
{
var tp = p.Trim().ToLowerInvariant();
From b8f5d6c4b6b97d8c916a9057e1a01acabfc32d85 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 26 Oct 2025 22:33:00 +0100
Subject: [PATCH 08/16] fix: cleanup
---
.../Popups/InstallGamePopup.xaml | 2 +-
.../Popups/InstallGamePopup.xaml.cs | 19 ++++---------------
.../Utils/DriveUtils.cs | 15 ++++++++++++---
3 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index aa0a8a4..92adbcf 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -114,7 +114,7 @@
-
+
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index 3f9766d..e05d9bd 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -45,17 +45,13 @@ public InstallGamePopup()
});
- var firstReady = _drives.FirstOrDefault();
- if (firstReady != null)
- {
- SetSelectedPath(_defaultPath);
- }
+ SetSelectedPath(_defaultPath);
}
}
private void SetSelectedPath(string path)
{
- string? _selectedPath;
+ string? _selectedPath = null;
var _selectedFreeText = string.Empty;
try
{
@@ -63,17 +59,10 @@ private void SetSelectedPath(string path)
var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
if (drive == null)
{
- _selectedPath = _defaultPath;
+ _selectedPath = DriveUtils.GetValidPath(_defaultPath);
+ drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
}
- }
- catch
- {
- _selectedPath = _defaultPath;
- }
- try
- {
- var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
if (drive != null)
{
_selectedFreeText = GetDriveFreeSpaceFormatted(drive);
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
index c61efbb..dd4e251 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
@@ -13,7 +13,7 @@ public static bool IsValidDrive(DriveInfo drive)
{
return drive.DriveType == DriveType.Fixed && drive.IsReady;
}
-
+
public static List GetValidDrives()
{
return DriveInfo.GetDrives().Where(d => IsValidDrive(d)).ToList();
@@ -39,7 +39,16 @@ public static string GetDriveRootName(DriveInfo drive)
internal static string? GetValidPath(string path)
{
- var fullpath = Path.GetFullPath(path);
- return !fullpath.Contains(":\\Windows") && !fullpath.Contains("\\OneDrive") ? fullpath : null;
+ string? fullpath;
+ try
+ {
+ fullpath = Path.GetFullPath(path);
+ }
+ catch
+ {
+ fullpath = null;
+ }
+ var noExcludedFolders = fullpath != null && !fullpath.Contains(":\\Windows") && !fullpath.Contains("\\OneDrive");
+ return noExcludedFolders ? fullpath : null;
}
}
From 271d6a44aedd398a555ae88d400bff831efe5baf Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 26 Oct 2025 23:44:31 +0100
Subject: [PATCH 09/16] fix: Revert: introduce in another pr
---
.../Resources/Dictionary/LanguageResources.de.xaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
index e0a860d..33680fa 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Resources/Dictionary/LanguageResources.de.xaml
@@ -15,7 +15,7 @@
LADEN
SPIELEN
HINZUFÜGEN
- FREI
+ KOSTENLOS
BESTÄTIGEN
JA
NEIN
From 601581997702b19edb1723dca5620a15422be802 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Mon, 27 Oct 2025 00:43:44 +0100
Subject: [PATCH 10/16] fix: use existing toggleable element. align style to
system settings toggleable
---
.../Converter/BooleanToVisibilityConverter.cs | 58 -------------------
.../Popups/InstallGamePopup.xaml | 44 ++------------
.../Popups/InstallGamePopup.xaml.cs | 14 +++--
3 files changed, 15 insertions(+), 101 deletions(-)
delete mode 100644 src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
deleted file mode 100644
index 141e3cd..0000000
--- a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Converter/BooleanToVisibilityConverter.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using System.Globalization;
-using System.Windows;
-using System.Windows.Data;
-
-namespace BfmeFoundationProject.AllInOneLauncher.Elements.Converter
-{
- ///
- /// Converts a boolean to Visibility.
- /// Supports optional inversion via ConverterParameter="invert" or ConverterParameter="!" (case-insensitive).
- /// Also supports hiding mode via ConverterParameter="hidden" to return Visibility.Hidden instead of Collapsed when false.
- /// You can combine parameters with a comma: "invert,hidden".
- ///
- public class BooleanToVisibilityConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- bool isTrue = false;
-
- if (value is bool valueBool)
- isTrue = valueBool;
- else if (value is bool?)
- isTrue = (bool?)value ?? false;
-
- bool invert = false;
- bool useHidden = false;
-
- if (parameter is string paramString && !string.IsNullOrWhiteSpace(paramString))
- {
- var parts = paramString.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries);
- foreach (var p in parts)
- {
- var tp = p.Trim().ToLowerInvariant();
- if (tp == "invert" || tp == "!" )
- invert = true;
- if (tp == "hidden")
- useHidden = true;
- }
- }
-
- if (invert)
- isTrue = !isTrue;
-
- if (isTrue)
- return Visibility.Visible;
-
- return useHidden ? Visibility.Hidden : Visibility.Collapsed;
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value is Visibility v)
- return v == Visibility.Visible;
-
- return DependencyProperty.UnsetValue;
- }
- }
-}
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index 92adbcf..58f9669 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -5,16 +5,11 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Popups"
xmlns:elements="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements"
- xmlns:converter="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements.Converter"
xmlns:system="clr-namespace:System;assembly=netstandard"
xmlns:generic="clr-namespace:BfmeFoundationProject.AllInOneLauncher.Elements.Generic"
mc:Ignorable="d"
Width="700" HorizontalAlignment="Center" VerticalAlignment="Center">
-
-
-
-
@@ -76,43 +71,16 @@
-
-
-
-
-
-
-
-
+
+
+
+
-
+
-
+
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index e05d9bd..a780834 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
+using System.IO;
using System.Windows;
using BfmeFoundationProject.AllInOneLauncher.Core.Utils;
using BfmeFoundationProject.AllInOneLauncher.Elements.Disk;
@@ -98,10 +95,17 @@ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
}
}
+ private void OnAdvancedSettingsSwitched(object sender, EventArgs e)
+ {
+ var isActive = SelectLocationAdvancedToggle.IsToggled;
+ SelectLocationList.Visibility = isActive ? Visibility.Collapsed : Visibility.Visible;
+ SelectFolderButton.Visibility = isActive ? Visibility.Visible : Visibility.Collapsed;
+ }
+
private void OnInstallClicked(object sender, RoutedEventArgs e)
{
var language = LanguageDropdown.SelectedValue;
- var path = (SelectLocationAdvancedToggle.IsChecked == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
+ var path = (SelectLocationAdvancedToggle.IsToggled == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
Submit(language, path);
}
From dc160c8c6e90e90ea99ebcea017ae44fcd9f83ce Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Thu, 30 Oct 2025 00:29:53 +0100
Subject: [PATCH 11/16] fix: use Win32 FolderDialog
---
.../Elements/Native/FolderPicker.cs | 121 ++++--------------
.../Utils/DriveUtils.cs | 10 +-
2 files changed, 25 insertions(+), 106 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
index b8b292d..adfce4f 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Elements/Native/FolderPicker.cs
@@ -1,7 +1,7 @@
using System;
-using System.Runtime.InteropServices;
-using System.Text;
+using System.IO;
using System.Windows;
+using Microsoft.Win32;
namespace BfmeFoundationProject.AllInOneLauncher.Elements.Native;
@@ -9,102 +9,25 @@ internal static class FolderPicker
{
public static string? ShowDialog(Window owner, string title = "", string? initialPath = null)
{
- IntPtr ownerHandle = new System.Windows.Interop.WindowInteropHelper(owner).Handle;
- return InternalShowDialog(ownerHandle, title, initialPath);
+ var dlg = new OpenFolderDialog
+ {
+ Title = title,
+ ValidateNames = true,
+ };
+
+ if (Directory.Exists(initialPath))
+ {
+ dlg.InitialDirectory = initialPath;
+ }
+
+ bool? result = dlg.ShowDialog(owner);
+ if (result == true)
+ {
+ var selected = dlg.FolderName;
+ if (Directory.Exists(selected))
+ return selected;
+ }
+
+ return null;
}
-
- private static string? InternalShowDialog(IntPtr ownerHandle, string title, string? initialPath)
- {
- // Constants
- const int MAX_PATH = 260;
- const uint BIF_RETURNONLYFSDIRS = 0x0001;
- const uint BIF_NEWDIALOGSTYLE = 0x0040;
- const int BFFM_INITIALIZED = 1;
- const int BFFM_SETSELECTIONW = 0x0467; // WM_USER + 103 (Unicode)
-
- BrowseCallbackProc callback = (hwnd, msg, lParam, lpData) =>
- {
- if (msg == BFFM_INITIALIZED && lpData != IntPtr.Zero)
- {
- // lpData contains pointer to initial path (Unicode)
- SendMessage(hwnd, BFFM_SETSELECTIONW, new IntPtr(1), lpData);
- }
- return 0;
- };
-
- IntPtr pidl = IntPtr.Zero;
- IntPtr pszDisplayName = IntPtr.Zero;
- IntPtr initialPathPtr = IntPtr.Zero;
- try
- {
- pszDisplayName = Marshal.AllocHGlobal(MAX_PATH * 2);
-
- var bi = new BROWSEINFO
- {
- hwndOwner = ownerHandle,
- pidlRoot = IntPtr.Zero,
- pszDisplayName = pszDisplayName,
- lpszTitle = title,
- ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE,
- lpfn = callback,
- lParam = IntPtr.Zero,
- iImage = 0
- };
-
- if (!string.IsNullOrWhiteSpace(initialPath))
- {
- initialPathPtr = Marshal.StringToHGlobalUni(initialPath);
- bi.lParam = initialPathPtr;
- }
-
- pidl = SHBrowseForFolder(ref bi);
- if (pidl == IntPtr.Zero)
- return null;
-
- var sb = new StringBuilder(MAX_PATH);
- if (SHGetPathFromIDList(pidl, sb))
- {
- return sb.ToString();
- }
-
- return null;
- }
- finally
- {
- if (initialPathPtr != IntPtr.Zero) Marshal.FreeHGlobal(initialPathPtr);
- if (pszDisplayName != IntPtr.Zero) Marshal.FreeHGlobal(pszDisplayName);
- if (pidl != IntPtr.Zero) CoTaskMemFree(pidl);
- }
- }
-
- #region Native
- private delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData);
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- private struct BROWSEINFO
- {
- public IntPtr hwndOwner;
- public IntPtr pidlRoot;
- public IntPtr pszDisplayName;
- [MarshalAs(UnmanagedType.LPWStr)]
- public string lpszTitle;
- public uint ulFlags;
- [MarshalAs(UnmanagedType.FunctionPtr)]
- public BrowseCallbackProc lpfn;
- public IntPtr lParam;
- public int iImage;
- }
-
- [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
- private static extern IntPtr SHBrowseForFolder([In] ref BROWSEINFO lpbi);
-
- [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
- private static extern bool SHGetPathFromIDList(IntPtr pidl, [Out] StringBuilder pszPath);
-
- [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
- private static extern void CoTaskMemFree(IntPtr pv);
-
- [DllImport("user32.dll", CharSet = CharSet.Unicode)]
- private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
- #endregion
}
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
index dd4e251..7aa5a07 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Utils/DriveUtils.cs
@@ -39,15 +39,11 @@ public static string GetDriveRootName(DriveInfo drive)
internal static string? GetValidPath(string path)
{
- string? fullpath;
- try
- {
+ string? fullpath = null;
+ if(Directory.Exists(path)) {
fullpath = Path.GetFullPath(path);
}
- catch
- {
- fullpath = null;
- }
+
var noExcludedFolders = fullpath != null && !fullpath.Contains(":\\Windows") && !fullpath.Contains("\\OneDrive");
return noExcludedFolders ? fullpath : null;
}
From aaeb4bee4935681a1634ad78d9f8790689828e9d Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Thu, 30 Oct 2025 00:43:24 +0100
Subject: [PATCH 12/16] fix: update variable names
---
.../Popups/InstallGamePopup.xaml | 2 +-
.../Popups/InstallGamePopup.xaml.cs | 40 +++++++++----------
2 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index 58f9669..bee8f83 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -78,7 +78,7 @@
-
+
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index a780834..51d5451 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -9,24 +9,24 @@ namespace BfmeFoundationProject.AllInOneLauncher.Popups;
public partial class InstallGamePopup : PopupBody
{
- private static readonly List _drives = DriveUtils.GetValidDrives();
- private string _defaultPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
+ private readonly List Drives = DriveUtils.GetValidDrives();
+ private readonly string DefaultPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
public InstallGamePopup()
{
InitializeComponent();
- if (_drives.Count <= 0)
+ if (Drives.Count <= 0)
{
SelectLocationError.Visibility = Visibility.Visible;
SelectLocationArea.Visibility = Visibility.Collapsed;
}
else
{
- locations.Children.Clear();
- _drives.ForEach(drive =>
+ Locations.Children.Clear();
+ Drives.ForEach(drive =>
{
- locations.Children.Add(new Selectable()
+ Locations.Children.Add(new Selectable()
{
Title = new LibraryDriveHeader()
{
@@ -42,34 +42,34 @@ public InstallGamePopup()
});
- SetSelectedPath(_defaultPath);
+ SetSelectedPath(DefaultPath);
}
}
private void SetSelectedPath(string path)
{
- string? _selectedPath = null;
- var _selectedFreeText = string.Empty;
+ string? selectedPath = null;
+ var selectedFreeText = string.Empty;
try
{
- _selectedPath = DriveUtils.GetValidPath(path);
- var drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
+ selectedPath = DriveUtils.GetValidPath(path);
+ var drive = DriveUtils.GetDriveForPath(Drives, selectedPath);
if (drive == null)
{
- _selectedPath = DriveUtils.GetValidPath(_defaultPath);
- drive = DriveUtils.GetDriveForPath(_drives, _selectedPath);
+ selectedPath = DriveUtils.GetValidPath(DefaultPath);
+ drive = DriveUtils.GetDriveForPath(Drives, selectedPath);
}
if (drive != null)
{
- _selectedFreeText = GetDriveFreeSpaceFormatted(drive);
+ selectedFreeText = GetDriveFreeSpaceFormatted(drive);
}
}
catch { /* ignore errors here */ }
- SelectedPathText.Text = _selectedPath;
- SelectedFreeSpaceText.Text = _selectedFreeText;
- ButtonAccept.IsEnabled = !string.IsNullOrWhiteSpace(_selectedPath);
+ SelectedPathText.Text = selectedPath;
+ SelectedFreeSpaceText.Text = selectedFreeText;
+ ButtonAccept.IsEnabled = !string.IsNullOrWhiteSpace(selectedPath);
}
private static string GetDriveFreeSpaceFormatted(DriveInfo drive)
@@ -83,8 +83,8 @@ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
{
var ownerWindow = Window.GetWindow(this);
var folderDialogTitle = (string)App.Current.FindResource("InstallGamePopupSelectFolder");
- var _selectedPath = SelectedPathText.Text;
- var selected = FolderPicker.ShowDialog(ownerWindow, folderDialogTitle, _selectedPath);
+ var selectedPath = SelectedPathText.Text;
+ var selected = FolderPicker.ShowDialog(ownerWindow, folderDialogTitle, selectedPath);
if (!string.IsNullOrWhiteSpace(selected))
SetSelectedPath(selected);
}
@@ -105,7 +105,7 @@ private void OnAdvancedSettingsSwitched(object sender, EventArgs e)
private void OnInstallClicked(object sender, RoutedEventArgs e)
{
var language = LanguageDropdown.SelectedValue;
- var path = (SelectLocationAdvancedToggle.IsToggled == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(locations)!.ToString()!;
+ var path = (SelectLocationAdvancedToggle.IsToggled == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(Locations)!.ToString()!;
Submit(language, path);
}
From 4c5d8da3c23ad4b0f5bf32fddbdac8b85ac408fe Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Thu, 30 Oct 2025 01:42:30 +0100
Subject: [PATCH 13/16] fix: update subelement style
---
.../Popups/InstallGamePopup.xaml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index bee8f83..7cc517b 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -49,7 +49,7 @@
-
+
English
French
@@ -64,16 +64,16 @@
-
-
+
+
-
+
-
+
From 36c3fe176d3f7857653d0f2447a535c136f1ffd1 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Thu, 30 Oct 2025 01:44:05 +0100
Subject: [PATCH 14/16] fix: set HiglightButton style for folderselection
button
---
.../Popups/InstallGamePopup.xaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index 7cc517b..57fe912 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -80,7 +80,7 @@
-
+
From b6fd1be20f17ffd3c63565ee752dd2fdc1968ad9 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Fri, 31 Oct 2025 00:36:35 +0100
Subject: [PATCH 15/16] fix: Update advanced folder selection ui
use visiblity hidden instead of collapse to avoid layout shift
reduce layout complexity by removing obsolete elements
---
.../Popups/InstallGamePopup.xaml | 27 ++++++++++++-------
.../Popups/InstallGamePopup.xaml.cs | 10 +++----
2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index 57fe912..d4eb02e 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -76,17 +76,24 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
index 51d5451..a00c3f3 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml.cs
@@ -23,10 +23,10 @@ public InstallGamePopup()
}
else
{
- Locations.Children.Clear();
+ SelectLocationSelectableList.Children.Clear();
Drives.ForEach(drive =>
{
- Locations.Children.Add(new Selectable()
+ SelectLocationSelectableList.Children.Add(new Selectable()
{
Title = new LibraryDriveHeader()
{
@@ -98,14 +98,14 @@ private void OnSelectFolderClicked(object sender, RoutedEventArgs e)
private void OnAdvancedSettingsSwitched(object sender, EventArgs e)
{
var isActive = SelectLocationAdvancedToggle.IsToggled;
- SelectLocationList.Visibility = isActive ? Visibility.Collapsed : Visibility.Visible;
- SelectFolderButton.Visibility = isActive ? Visibility.Visible : Visibility.Collapsed;
+ SelectLocationSelectableList.Visibility = isActive ? Visibility.Hidden : Visibility.Visible;
+ SelectLocationAdvancedArea.Visibility = isActive ? Visibility.Visible : Visibility.Hidden;
}
private void OnInstallClicked(object sender, RoutedEventArgs e)
{
var language = LanguageDropdown.SelectedValue;
- var path = (SelectLocationAdvancedToggle.IsToggled == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(Locations)!.ToString()!;
+ var path = (SelectLocationAdvancedToggle.IsToggled == true) ? SelectedPathText.Text : Selectable.GetSelectedTagInContainer(SelectLocationSelectableList)!.ToString()!;
Submit(language, path);
}
From 0490cce586219b056cfb4105c809f5fb92a47831 Mon Sep 17 00:00:00 2001
From: AlvinSchiller <103769832+AlvinSchiller@users.noreply.github.com>
Date: Sun, 28 Dec 2025 23:02:03 +0100
Subject: [PATCH 16/16] fix: Update advanced folder selection ui. refactor to
single button.
---
.../Popups/InstallGamePopup.xaml | 31 +++++++++----------
1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
index d4eb02e..634332c 100644
--- a/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
+++ b/src/BfmeFoundationProject_AllInOneLauncher/Popups/InstallGamePopup.xaml
@@ -77,23 +77,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+