feat: Add GameDataPickerManager for managing game data selection flows
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
|||||||
|
library;
|
||||||
|
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import 'package:file_selector/file_selector.dart';
|
||||||
|
import 'package:wolf_3d_flutter/wolf_3d_flutter.dart';
|
||||||
|
|
||||||
|
/// Coordinates game-data selection flows for the no-data setup screen.
|
||||||
|
class GameDataPickerManager {
|
||||||
|
GameDataPickerManager({required this.engine});
|
||||||
|
|
||||||
|
final Wolf3dFlutterEngine engine;
|
||||||
|
|
||||||
|
bool _isLoadingGameData = false;
|
||||||
|
String? _pickerError;
|
||||||
|
|
||||||
|
bool get isLoadingGameData => _isLoadingGameData;
|
||||||
|
String? get pickerError => _pickerError;
|
||||||
|
|
||||||
|
Future<void> pickGameDataDirectory({
|
||||||
|
required void Function() notifyChanged,
|
||||||
|
}) async {
|
||||||
|
_isLoadingGameData = true;
|
||||||
|
_pickerError = null;
|
||||||
|
notifyChanged();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String? directoryPath = await getDirectoryPath(
|
||||||
|
confirmButtonText: 'Use this folder',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (directoryPath == null || directoryPath.trim().isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await engine.init(directory: directoryPath.trim());
|
||||||
|
} catch (error) {
|
||||||
|
_pickerError = 'Unable to load selected directory: $error';
|
||||||
|
} finally {
|
||||||
|
_isLoadingGameData = false;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pickGameDataFiles({
|
||||||
|
required void Function() notifyChanged,
|
||||||
|
}) async {
|
||||||
|
_isLoadingGameData = true;
|
||||||
|
_pickerError = null;
|
||||||
|
notifyChanged();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final List<XFile> selectedFiles = await openFiles();
|
||||||
|
|
||||||
|
if (selectedFiles.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LinkedHashSet<String> directories = LinkedHashSet<String>();
|
||||||
|
for (final XFile file in selectedFiles) {
|
||||||
|
final String directory = _directoryFromFilePath(file.path);
|
||||||
|
if (directory.isNotEmpty) {
|
||||||
|
directories.add(directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directories.isEmpty) {
|
||||||
|
_pickerError = 'Selected files do not expose local filesystem paths.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> orderedDirectories = directories.toList(
|
||||||
|
growable: false,
|
||||||
|
);
|
||||||
|
await engine.init(
|
||||||
|
directory: orderedDirectories.first,
|
||||||
|
additionalDirectories: orderedDirectories.skip(1),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
_pickerError = 'Unable to load selected files: $error';
|
||||||
|
} finally {
|
||||||
|
_isLoadingGameData = false;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _directoryFromFilePath(String path) {
|
||||||
|
final String trimmedPath = path.trim();
|
||||||
|
if (trimmedPath.isEmpty) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
final int slashIndex = trimmedPath.lastIndexOf('/');
|
||||||
|
final int backslashIndex = trimmedPath.lastIndexOf(r'\');
|
||||||
|
final int separatorIndex = slashIndex > backslashIndex
|
||||||
|
? slashIndex
|
||||||
|
: backslashIndex;
|
||||||
|
|
||||||
|
if (separatorIndex < 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (separatorIndex == 0) {
|
||||||
|
return trimmedPath[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmedPath.substring(0, separatorIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
library;
|
library;
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
|
||||||
|
|
||||||
import 'package:file_selector/file_selector.dart';
|
|
||||||
import 'package:wolf_3d_flutter/wolf_3d_flutter.dart';
|
import 'package:wolf_3d_flutter/wolf_3d_flutter.dart';
|
||||||
|
|
||||||
/// Coordinates app-shell setup actions and shutdown behavior.
|
/// Coordinates app-shell setup actions and shutdown behavior.
|
||||||
@@ -11,13 +9,13 @@ class Wolf3dAppManager {
|
|||||||
Wolf3dAppManager({required this.engine});
|
Wolf3dAppManager({required this.engine});
|
||||||
|
|
||||||
final Wolf3dFlutterEngine engine;
|
final Wolf3dFlutterEngine engine;
|
||||||
|
late final GameDataPickerManager _pickerManager = GameDataPickerManager(
|
||||||
bool _isLoadingGameData = false;
|
engine: engine,
|
||||||
String? _pickerError;
|
);
|
||||||
Future<void>? _shutdownFuture;
|
Future<void>? _shutdownFuture;
|
||||||
|
|
||||||
bool get isLoadingGameData => _isLoadingGameData;
|
bool get isLoadingGameData => _pickerManager.isLoadingGameData;
|
||||||
String? get pickerError => _pickerError;
|
String? get pickerError => _pickerManager.pickerError;
|
||||||
|
|
||||||
Future<void> ensureAudioShutdown() {
|
Future<void> ensureAudioShutdown() {
|
||||||
final existing = _shutdownFuture;
|
final existing = _shutdownFuture;
|
||||||
@@ -33,91 +31,12 @@ class Wolf3dAppManager {
|
|||||||
Future<void> pickGameDataDirectory({
|
Future<void> pickGameDataDirectory({
|
||||||
required void Function() notifyChanged,
|
required void Function() notifyChanged,
|
||||||
}) async {
|
}) async {
|
||||||
_isLoadingGameData = true;
|
await _pickerManager.pickGameDataDirectory(notifyChanged: notifyChanged);
|
||||||
_pickerError = null;
|
|
||||||
notifyChanged();
|
|
||||||
|
|
||||||
try {
|
|
||||||
final String? directoryPath = await getDirectoryPath(
|
|
||||||
confirmButtonText: 'Use this folder',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (directoryPath == null || directoryPath.trim().isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await engine.init(directory: directoryPath.trim());
|
|
||||||
} catch (error) {
|
|
||||||
_pickerError = 'Unable to load selected directory: $error';
|
|
||||||
} finally {
|
|
||||||
_isLoadingGameData = false;
|
|
||||||
notifyChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pickGameDataFiles({
|
Future<void> pickGameDataFiles({
|
||||||
required void Function() notifyChanged,
|
required void Function() notifyChanged,
|
||||||
}) async {
|
}) async {
|
||||||
_isLoadingGameData = true;
|
await _pickerManager.pickGameDataFiles(notifyChanged: notifyChanged);
|
||||||
_pickerError = null;
|
|
||||||
notifyChanged();
|
|
||||||
|
|
||||||
try {
|
|
||||||
final List<XFile> selectedFiles = await openFiles();
|
|
||||||
|
|
||||||
if (selectedFiles.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final LinkedHashSet<String> directories = LinkedHashSet<String>();
|
|
||||||
for (final XFile file in selectedFiles) {
|
|
||||||
final String directory = _directoryFromFilePath(file.path);
|
|
||||||
if (directory.isNotEmpty) {
|
|
||||||
directories.add(directory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (directories.isEmpty) {
|
|
||||||
_pickerError =
|
|
||||||
'Selected files do not expose local filesystem paths.';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> orderedDirectories = directories.toList(
|
|
||||||
growable: false,
|
|
||||||
);
|
|
||||||
await engine.init(
|
|
||||||
directory: orderedDirectories.first,
|
|
||||||
additionalDirectories: orderedDirectories.skip(1),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
_pickerError = 'Unable to load selected files: $error';
|
|
||||||
} finally {
|
|
||||||
_isLoadingGameData = false;
|
|
||||||
notifyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _directoryFromFilePath(String path) {
|
|
||||||
final String trimmedPath = path.trim();
|
|
||||||
if (trimmedPath.isEmpty) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
final int slashIndex = trimmedPath.lastIndexOf('/');
|
|
||||||
final int backslashIndex = trimmedPath.lastIndexOf(r'\');
|
|
||||||
final int separatorIndex = slashIndex > backslashIndex
|
|
||||||
? slashIndex
|
|
||||||
: backslashIndex;
|
|
||||||
|
|
||||||
if (separatorIndex < 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (separatorIndex == 0) {
|
|
||||||
return trimmedPath[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return trimmedPath.substring(0, separatorIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export 'audio/wolf3d_platform_audio.dart' show Wolf3dPlatformAudio;
|
|||||||
export 'managers/game_app_lifecycle_manager.dart' show GameAppLifecycleManager;
|
export 'managers/game_app_lifecycle_manager.dart' show GameAppLifecycleManager;
|
||||||
export 'managers/game_data_directory_persistence.dart'
|
export 'managers/game_data_directory_persistence.dart'
|
||||||
show DefaultGameDataDirectoryPersistence;
|
show DefaultGameDataDirectoryPersistence;
|
||||||
|
export 'managers/game_data_picker_manager.dart' show GameDataPickerManager;
|
||||||
export 'managers/game_display_manager.dart' show GameDisplayManager;
|
export 'managers/game_display_manager.dart' show GameDisplayManager;
|
||||||
export 'managers/game_persistence_manager.dart' show GamePersistenceManager;
|
export 'managers/game_persistence_manager.dart' show GamePersistenceManager;
|
||||||
export 'managers/game_renderer_mode_manager.dart'
|
export 'managers/game_renderer_mode_manager.dart'
|
||||||
|
|||||||
Reference in New Issue
Block a user