musicus_mobile/lib/selectors/files.dart
Elias Projahn e9f0bd03e7 Use the storage access framework
Everything related to file system access has been rewritten to make use
of the storage access framework. This means that the
WRITE_EXTERNAL_STORAGE is no longer needed. Because of that, the
dependency on permission_handler could be dropped and all code related
to permission handling has been removed. To be able to open a whole
document tree, the minSdkVersion was bumped to 21. Finally the file
selector was rewritten using custom platform dependent code.
2020-04-11 21:59:23 +02:00

158 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../backend.dart';
class Document {
final String id;
final String name;
final String parent;
final bool isDirectory;
Document.fromMap(Map<dynamic, dynamic> map)
: id = map['id'],
name = map['name'],
parent = map['parent'],
isDirectory = map['isDirectory'];
}
class FilesSelector extends StatefulWidget {
@override
_FilesSelectorState createState() => _FilesSelectorState();
}
class _FilesSelectorState extends State<FilesSelector> {
static const platform = MethodChannel('de.johrpan.musicus/platform');
BackendState backend;
List<Document> history = [];
List<Document> children = [];
Set<String> selectedIds = {};
@override
void didChangeDependencies() {
super.didChangeDependencies();
backend = Backend.of(context);
loadChildren();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(
appBar: AppBar(
title: Text('Choose files'),
leading: IconButton(
icon: const Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
},
),
actions: <Widget>[
FlatButton(
child: Text('DONE'),
onPressed: () {
Navigator.pop(context, selectedIds);
},
),
],
),
body: Column(
children: <Widget>[
Material(
elevation: 2.0,
child: ListTile(
leading: IconButton(
icon: const Icon(Icons.arrow_upward),
onPressed: history.isNotEmpty ? up : null,
),
title: Text(
history.isNotEmpty ? history.last.name : 'Music library'),
),
),
Expanded(
child: ListView.builder(
itemCount: children.length,
itemBuilder: (context, index) {
final document = children[index];
if (document.isDirectory) {
return ListTile(
leading: const Icon(Icons.folder),
title: Text(document.name),
onTap: () {
setState(() {
history.add(document);
});
loadChildren();
},
);
} else {
return CheckboxListTile(
controlAffinity: ListTileControlAffinity.trailing,
secondary: const Icon(Icons.insert_drive_file),
title: Text(document.name),
value: selectedIds.contains(document.id),
onChanged: (selected) {
setState(() {
if (selected) {
selectedIds.add(document.id);
} else {
selectedIds.remove(document.id);
}
});
},
);
}
},
),
),
],
),
),
onWillPop: () => Future.value(up()),
);
}
Future<void> loadChildren() async {
setState(() {
children = [];
});
final childrenMaps = await platform.invokeListMethod<Map<dynamic, dynamic>>(
'getChildren',
{
'treeUri': backend.musicLibraryUri,
'parentId': history.isNotEmpty ? history.last.id : null,
},
);
final newChildren = childrenMaps.map((m) => Document.fromMap(m)).toList();
newChildren.sort((d1, d2) {
if (d1.isDirectory != d2.isDirectory) {
return d1.isDirectory ? -1 : 1;
} else {
return d1.name.compareTo(d2.name);
}
});
setState(() {
children = newChildren;
});
}
bool up() {
if (history.isNotEmpty) {
setState(() {
history.removeLast();
});
loadChildren();
return false;
} else {
return true;
}
}
}