summaryrefslogtreecommitdiff
path: root/lib/screens/level_selection.dart
diff options
context:
space:
mode:
Diffstat (limited to 'lib/screens/level_selection.dart')
-rw-r--r--lib/screens/level_selection.dart161
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)),
+ );
+ }
+}