diff --git a/lib/views/pages/manage.dart b/lib/views/pages/manage.dart index a79a50f..bfd6804 100644 --- a/lib/views/pages/manage.dart +++ b/lib/views/pages/manage.dart @@ -21,16 +21,15 @@ class _DistributionManagePageState extends State { child: Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( + leading: BackButton( + onPressed: () => setState(() { + current = null; + }), + ), forceMaterialTransparency: true, backgroundColor: Colors.transparent, title: Text(current!), ), - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.arrow_back), - onPressed: () => setState(() { - current = null; - }), - ), body: DistroManagePage(distro: current!), ), ); diff --git a/lib/views/pages/manage_distro.dart b/lib/views/pages/manage_distro.dart index 0a7c9fa..40fc564 100644 --- a/lib/views/pages/manage_distro.dart +++ b/lib/views/pages/manage_distro.dart @@ -5,6 +5,8 @@ import 'package:arche/arche.dart'; import 'package:arche/extensions/iter.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:path/path.dart'; import 'package:wslconfigurer/i18n/i18n.dart'; import 'package:wslconfigurer/views/widgets/basic.dart'; import 'package:wslconfigurer/views/widgets/extension.dart'; @@ -119,6 +121,12 @@ class _DistroManagePageState extends State ), ), ), + Card.filled( + child: Padding( + padding: const EdgeInsets.all(8), + child: WSLExplorerWidget(distro: widget.distro), + ), + ), ].enumerate( (index, widget) => AnimationConfiguration.staggeredList( position: index, @@ -134,3 +142,103 @@ class _DistroManagePageState extends State ); } } + +class WSLExplorerWidget extends StatefulWidget { + final String distro; + const WSLExplorerWidget({super.key, required this.distro}); + + @override + State createState() => _WSLExplorerWidgetState(); +} + +class _WSLExplorerWidgetState extends State + with RefreshMountedStateMixin { + late WSLExplorer explorer; + List current = []; + @override + void initState() { + super.initState(); + + explorer = WSLExplorer(widget.distro); + listExplorer(); + } + + void listExplorer() { + current.clear(); + + explorer.list().listen((data) => refreshMountedFn(() => current.add(data)), + onDone: () => refreshMountedFn( + () => current.sort((a, b) => a.path.compareTo(b.path)))); + } + + @override + Widget build(BuildContext context) { + return Column( + key: ValueKey(explorer.current), + children: [ + ...explorer.isRoot + ? [] + : [ + ListTile( + title: const Text(".."), + onTap: () { + explorer.parent(); + listExplorer(); + }, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8)))) + ], + ...current.map((entity) { + var entityBaseName = basename(entity.path); + var friendlyName = + entity.path.replaceFirst(explorer.root, "").replaceAll("\\", "/"); + return FutureBuilder( + future: entity.stat(), + builder: (context, snapshot) { + var data = snapshot.data; + if (data == null) { + return ListTile( + leading: const Icon(Icons.question_mark), + title: Text(entityBaseName), + subtitle: Text(friendlyName), + ); + } + + IconData icon; + Function()? onTap; + + switch (data.type) { + case FileSystemEntityType.file: + icon = FontAwesomeIcons.file; + break; + case FileSystemEntityType.directory: + icon = Icons.folder; + onTap = () async { + await explorer.move(entity.path); + listExplorer(); + }; + break; + case FileSystemEntityType.link: + icon = Icons.link; + break; + case FileSystemEntityType.notFound: + icon = Icons.security; + default: + icon = Icons.question_mark; + } + + return ListTile( + leading: Icon(icon), + title: Text(entityBaseName), + subtitle: Text(friendlyName), + onTap: onTap, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8))), + ); + }, + ); + }), + ], + ); + } +} diff --git a/lib/windows/wsl.dart b/lib/windows/wsl.dart index 2b4b505..bc36dbf 100644 --- a/lib/windows/wsl.dart +++ b/lib/windows/wsl.dart @@ -83,3 +83,33 @@ class WindowsSubSystemLinux { ); } } + +class WSLExplorer { + final String distro; + late final String root; + late Directory current; + + WSLExplorer(this.distro) { + root = "//wsl.localhost/$distro"; + current = Directory("$root/home"); + } + + Stream list() { + return current.list(); + } + + bool get isRoot => current.path == root; + + Future move(String path) async { + var target = Directory(path); + if (await target.exists()) { + current = target; + return true; + } + return false; + } + + void parent() { + current = current.parent; + } +} diff --git a/pubspec.lock b/pubspec.lock index 9a0d92d..07cd71b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -273,7 +273,7 @@ packages: source: hosted version: "2.1.0" path: - dependency: transitive + dependency: "direct main" description: name: path sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" diff --git a/pubspec.yaml b/pubspec.yaml index 7d38695..e0118a0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,7 @@ dependencies: flutter_markdown: ^0.7.3 flutter_staggered_animations: ^1.1.1 system_info2: ^4.0.0 + path: ^1.9.0 dev_dependencies: flutter_test: