70b4fc3fe0
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
141 lines
3.5 KiB
Dart
141 lines
3.5 KiB
Dart
library;
|
|
|
|
import 'dart:collection';
|
|
|
|
import 'package:file_selector/file_selector.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:wolf_3d_flutter/wolf_3d_flutter.dart';
|
|
|
|
/// Minimal app shell that binds a prepared [Wolf3dFlutterEngine] instance to
|
|
/// host screens.
|
|
class Wolf3dApp extends StatefulWidget {
|
|
/// Shared initialized facade that owns game data, input, and audio services.
|
|
final Wolf3dFlutterEngine engine;
|
|
|
|
const Wolf3dApp({
|
|
super.key,
|
|
required this.engine,
|
|
});
|
|
|
|
@override
|
|
State<Wolf3dApp> createState() => _Wolf3dAppState();
|
|
}
|
|
|
|
class _Wolf3dAppState extends State<Wolf3dApp> {
|
|
bool _isLoadingGameData = false;
|
|
String? _pickerError;
|
|
|
|
Future<void> _pickGameDataDirectory() async {
|
|
setState(() {
|
|
_isLoadingGameData = true;
|
|
_pickerError = null;
|
|
});
|
|
|
|
try {
|
|
final String? directoryPath = await getDirectoryPath(
|
|
confirmButtonText: 'Use this folder',
|
|
);
|
|
|
|
if (directoryPath == null || directoryPath.trim().isEmpty) {
|
|
return;
|
|
}
|
|
|
|
await widget.engine.init(directory: directoryPath.trim());
|
|
} catch (error) {
|
|
setState(() {
|
|
_pickerError = 'Unable to load selected directory: $error';
|
|
});
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() {
|
|
_isLoadingGameData = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _pickGameDataFiles() async {
|
|
setState(() {
|
|
_isLoadingGameData = true;
|
|
_pickerError = null;
|
|
});
|
|
|
|
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) {
|
|
setState(() {
|
|
_pickerError = 'Selected files do not expose local filesystem paths.';
|
|
});
|
|
return;
|
|
}
|
|
|
|
final List<String> orderedDirectories = directories.toList(
|
|
growable: false,
|
|
);
|
|
await widget.engine.init(
|
|
directory: orderedDirectories.first,
|
|
additionalDirectories: orderedDirectories.skip(1),
|
|
);
|
|
} catch (error) {
|
|
setState(() {
|
|
_pickerError = 'Unable to load selected files: $error';
|
|
});
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() {
|
|
_isLoadingGameData = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return widget.engine.availableGames.isEmpty
|
|
? NoGameDataScreen(
|
|
configuredDataDirectory: widget.engine.configuredDataDirectory,
|
|
onPickGameDataDirectory: _pickGameDataDirectory,
|
|
onPickGameDataFiles: _pickGameDataFiles,
|
|
isLoadingGameData: _isLoadingGameData,
|
|
pickerError: _pickerError,
|
|
)
|
|
: GameScreen(wolf3d: widget.engine);
|
|
}
|
|
}
|