diff options
Diffstat (limited to 'lib/screens/level_selection.dart')
-rw-r--r-- | lib/screens/level_selection.dart | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/lib/screens/level_selection.dart b/lib/screens/level_selection.dart new file mode 100644 index 0000000..0987063 --- /dev/null +++ b/lib/screens/level_selection.dart @@ -0,0 +1,161 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:sense_the_rhythm/utils/esense_input.dart'; +import 'package:sense_the_rhythm/utils/simfile.dart'; +import 'package:sense_the_rhythm/widgets/connection_status_button.dart'; +import 'package:sense_the_rhythm/widgets/level_list_entry.dart'; + +class LevelSelection extends StatefulWidget { + const LevelSelection({super.key}); + + @override + State<LevelSelection> createState() => _LevelSelectionState(); +} + +class _LevelSelectionState extends State<LevelSelection> { + String? _stepmaniaCoursesPath; + List<Simfile> _stepmaniaCoursesFolders = []; + List<Simfile> _stepmaniaCoursesFoldersFiltered = []; + + @override + void initState() { + super.initState(); + _loadFolderPath(); + } + + /// gets folder path from persistent storage and updates state with loaded simfiles + Future<void> _loadFolderPath() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + final String? stepmaniaCoursesPathSetting = + prefs.getString('stepmania_courses'); + + if (stepmaniaCoursesPathSetting == null) return; + List<Simfile> stepmaniaCoursesFoldersFuture = + await _listFilesAndFolders(stepmaniaCoursesPathSetting); + + setState(() { + _stepmaniaCoursesPath = stepmaniaCoursesPathSetting; + _stepmaniaCoursesFolders = stepmaniaCoursesFoldersFuture; + _stepmaniaCoursesFoldersFiltered = stepmaniaCoursesFoldersFuture; + }); + } + + /// open folder selection dialog and save selected folder in persistent storage + Future<void> _selectFolder() async { + await Permission.manageExternalStorage.request(); + String? selectedFolder = await FilePicker.platform.getDirectoryPath(); + + if (selectedFolder != null) { + // Save the selected folder path + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('stepmania_courses', selectedFolder); + + _loadFolderPath(); + } + } + + /// load all simfiles from a [directoryPath] + Future<List<Simfile>> _listFilesAndFolders(String directoryPath) async { + final directory = Directory(directoryPath); + try { + // List all files and folders in the directory + List<Simfile> simfiles = directory + .listSync(recursive: true) + .where((entity) => entity.path.endsWith('.sm')) + .map((entity) => Simfile(entity.path)) + .toList(); + + List<bool> successfullLoads = + await Future.wait(simfiles.map((simfile) => simfile.load())); + List<Simfile> simfilesFiltered = []; + for (int i = 0; i < simfiles.length; i++) { + if (successfullLoads[i]) { + simfilesFiltered.add(simfiles[i]); + } + } + + simfilesFiltered + .sort((a, b) => a.tags['TITLE']!.compareTo(b.tags['TITLE']!)); + + return simfilesFiltered; + } catch (e) { + print("Error reading directory: $e"); + return []; + } + } + + /// filter stepmaniaCoursesFolders based on [input] + void _filterLevels(String input) { + setState(() { + _stepmaniaCoursesFoldersFiltered = _stepmaniaCoursesFolders + .where((simfile) => simfile.tags["TITLE"]! + .toLowerCase() + .contains(input.toLowerCase())) + .toList(); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Sense the Rhythm'), + actions: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: ValueListenableBuilder( + valueListenable: ESenseInput.instance.deviceStatus, + builder: + (BuildContext context, String deviceStatus, Widget? child) { + return ConnectionStatusButton(deviceStatus); + }, + ), + ) + ], + ), + body: Builder(builder: (context) { + if (_stepmaniaCoursesPath == null) { + return Text('Add a Directory with Stepmania Songs on \'+\''); + } else if (_stepmaniaCoursesFolders.isEmpty) { + return Text( + 'Folder empty. Add Stepmania Songs to Folder or select a different folder on \'+\''); + } else { + return Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 0.0), + child: TextField( + onChanged: _filterLevels, + decoration: InputDecoration( + // icon: Icon(Icons.search), + hintText: 'Search'), + ), + ), + Expanded( + child: ListView.separated( + itemCount: _stepmaniaCoursesFoldersFiltered.length, + separatorBuilder: (BuildContext context, int index) => + const Divider(), + itemBuilder: (context, index) { + Simfile simfile = _stepmaniaCoursesFoldersFiltered[index]; + return LevelListEntry(simfile: simfile); + }, + ), + ), + ], + ); + } + }), + floatingActionButton: FloatingActionButton( + onPressed: () { + _selectFolder(); + }, + child: Icon(Icons.add)), + ); + } +} |