Refactor menu structure and add Flutter-specific input and persistence layers
- Moved menu-related classes to a new structure under `src/menu/`. - Introduced `WolfMenuPresentation` to handle menu art and mappings. - Added `MenuManager` tests to ensure menu state reflects game status. - Implemented `FlutterRendererSettingsPersistence` and `FlutterSaveGamePersistence` for managing settings and save files on desktop platforms. - Created `Wolf3dFlutterInput` to handle keyboard and mouse input in a Flutter environment. - Updated README to reflect new package structure and usage instructions. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/// Flutter host adapter for persisting renderer settings to a local file.
|
||||
///
|
||||
/// Uses `dart:io` for desktop targets where a writable path is available.
|
||||
/// On web and other platforms that lack dart:io, persistence is silently
|
||||
/// skipped so the rest of the app continues to work normally.
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||
|
||||
/// Persists [WolfRendererSettings] as JSON to the app's support directory.
|
||||
///
|
||||
/// This implementation relies on `dart:io` and is therefore only active on
|
||||
/// non-web platforms. Pass an explicit [filePath] during testing.
|
||||
class FlutterRendererSettingsPersistence extends RendererSettingsPersistence
|
||||
with JsonRendererSettingsPersistence {
|
||||
FlutterRendererSettingsPersistence({String? filePath}) : _filePath = filePath;
|
||||
|
||||
final String? _filePath;
|
||||
String? _resolvedPath;
|
||||
|
||||
String get filePath {
|
||||
if (_resolvedPath != null) {
|
||||
return _resolvedPath!;
|
||||
}
|
||||
if (_filePath != null) {
|
||||
_resolvedPath = _filePath;
|
||||
return _resolvedPath!;
|
||||
}
|
||||
_resolvedPath = '$platformConfigDir/settings.json';
|
||||
return _resolvedPath!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> readRaw() async {
|
||||
if (kIsWeb) return null;
|
||||
try {
|
||||
final File f = File(filePath);
|
||||
if (!f.existsSync()) return null;
|
||||
return await f.readAsString();
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeRaw(String json) async {
|
||||
if (kIsWeb) return;
|
||||
try {
|
||||
await File(filePath).writeAsString(json, flush: true);
|
||||
} catch (_) {
|
||||
// Best-effort.
|
||||
}
|
||||
}
|
||||
|
||||
String get platformConfigDir {
|
||||
if (Platform.isLinux) {
|
||||
final String xdg = Platform.environment['XDG_CONFIG_HOME'] ?? '';
|
||||
final String home = Platform.environment['HOME'] ?? '.';
|
||||
return xdg.isNotEmpty ? '$xdg/wolf3d' : '$home/.config/wolf3d';
|
||||
}
|
||||
if (Platform.isMacOS) {
|
||||
final String home = Platform.environment['HOME'] ?? '.';
|
||||
return '$home/Library/Application Support/wolf3d';
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
final String appData = Platform.environment['APPDATA'] ?? '.';
|
||||
return '$appData/wolf3d';
|
||||
}
|
||||
final String home = Platform.environment['HOME'] ?? '.';
|
||||
return '$home/.config/wolf3d';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||
|
||||
/// Flutter desktop adapter for slot-based game save persistence.
|
||||
class FlutterSaveGamePersistence implements SaveGamePersistence {
|
||||
FlutterSaveGamePersistence({String? directoryPath})
|
||||
: _directoryPath = directoryPath;
|
||||
|
||||
final String? _directoryPath;
|
||||
String? _resolvedDirectoryPath;
|
||||
|
||||
Future<String> _resolveDirectoryPath() async {
|
||||
if (_resolvedDirectoryPath != null) {
|
||||
return _resolvedDirectoryPath!;
|
||||
}
|
||||
|
||||
if (_directoryPath != null) {
|
||||
_resolvedDirectoryPath = _directoryPath;
|
||||
return _resolvedDirectoryPath!;
|
||||
}
|
||||
|
||||
_resolvedDirectoryPath = '${_platformConfigDir()}/saves';
|
||||
return _resolvedDirectoryPath!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List?> load({
|
||||
required int slot,
|
||||
required GameVersion version,
|
||||
}) async {
|
||||
if (kIsWeb) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final String dirPath = await _resolveDirectoryPath();
|
||||
final File file = File(_slotPath(dirPath, slot, version));
|
||||
if (!file.existsSync()) {
|
||||
return null;
|
||||
}
|
||||
return await file.readAsBytes();
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> exists({
|
||||
required int slot,
|
||||
required GameVersion version,
|
||||
}) async {
|
||||
if (kIsWeb) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final String dirPath = await _resolveDirectoryPath();
|
||||
final File file = File(_slotPath(dirPath, slot, version));
|
||||
return file.existsSync() && file.lengthSync() > 0;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> save({
|
||||
required int slot,
|
||||
required GameVersion version,
|
||||
required Uint8List bytes,
|
||||
}) async {
|
||||
if (kIsWeb) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String dirPath = await _resolveDirectoryPath();
|
||||
final Directory dir = Directory(dirPath);
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create(recursive: true);
|
||||
}
|
||||
await File(
|
||||
_slotPath(dirPath, slot, version),
|
||||
).writeAsBytes(bytes, flush: true);
|
||||
}
|
||||
|
||||
String _slotPath(String dirPath, int slot, GameVersion version) {
|
||||
final String normalizedSlot = slot.clamp(0, 9).toString();
|
||||
return '$dirPath/SAVEGAM$normalizedSlot.${version.fileExtension}';
|
||||
}
|
||||
}
|
||||
|
||||
String _platformConfigDir() {
|
||||
if (Platform.isLinux) {
|
||||
final String xdg = Platform.environment['XDG_CONFIG_HOME'] ?? '';
|
||||
final String home = Platform.environment['HOME'] ?? '.';
|
||||
return xdg.isNotEmpty ? '$xdg/wolf3d' : '$home/.config/wolf3d';
|
||||
}
|
||||
if (Platform.isMacOS) {
|
||||
final String home = Platform.environment['HOME'] ?? '.';
|
||||
return '$home/Library/Application Support/wolf3d';
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
final String appData = Platform.environment['APPDATA'] ?? '.';
|
||||
return '$appData/wolf3d';
|
||||
}
|
||||
final String home = Platform.environment['HOME'] ?? '.';
|
||||
return '$home/.config/wolf3d';
|
||||
}
|
||||
Reference in New Issue
Block a user