new drawer to different image locations

This commit is contained in:
lukas-heiligenbrunner 2022-09-27 14:43:34 +02:00
parent fc0ab443e9
commit 195898009c
5 changed files with 179 additions and 97 deletions

View File

@ -14,12 +14,17 @@ class Folder {
Uri parent; Uri parent;
Folder(this.items, this.self, this.parent); Folder(this.items, this.self, this.parent);
@override
String toString() {
return 'Folder{items: $items, self: $self, parent: $parent}';
}
} }
abstract class DataProvider { abstract class DataProvider {
final List<String> validSuffix = [".jpg", ".jpeg", ".png"]; final List<String> validSuffix = [".jpg", ".jpeg", ".png"];
void connect(); Future<void> connect();
Future<Folder> listOfFiles({Uri? uri}); Future<Folder> listOfFiles({Uri? uri});
ImageProvider getImageProvider(Uri uri); ImageProvider getImageProvider(Uri uri);
} }

View File

@ -9,7 +9,7 @@ class LocalDataProvider extends DataProvider {
LocalDataProvider(this.initialPath); LocalDataProvider(this.initialPath);
@override @override
void connect() {} Future<void> connect() async {}
@override @override
Future<Folder> listOfFiles({Uri? uri}) async { Future<Folder> listOfFiles({Uri? uri}) async {

View File

@ -35,6 +35,7 @@ class SSHDataProvider extends DataProvider {
username: username, username: username,
onPasswordRequest: () => password, onPasswordRequest: () => password,
); );
await sshClient?.authenticated;
sftpClient = await sshClient?.sftp(); sftpClient = await sshClient?.sftp();
} }

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gallery/data_provider/data_provider.dart'; import 'package:gallery/data_provider/data_provider.dart';
import 'package:gallery/image_tile.dart'; import 'package:gallery/image_grid.dart';
import 'data_provider/local_data_provider.dart'; import 'data_provider/local_data_provider.dart';
import 'full_screen_image_view.dart'; import 'data_provider/ssh_data_provider.dart';
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title}); const MyHomePage({super.key, required this.title});
@ -14,113 +14,72 @@ class MyHomePage extends StatefulWidget {
State<MyHomePage> createState() => _MyHomePageState(); State<MyHomePage> createState() => _MyHomePageState();
} }
enum Page { local, remote }
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
Future<Folder>? folder; Page page = Page.local;
final DataProvider dprovider = LocalDataProvider("/home"); Widget _buildPage() {
DataProvider provider;
final ScrollController _controller = ScrollController(); switch (page) {
case Page.local:
_MyHomePageState() { provider = LocalDataProvider("/home");
folder = dprovider.listOfFiles(); break;
case Page.remote:
// todo do not generate a new provider on each tab switch
provider = SSHDataProvider(
initialPath: "/", host: "", password: "", port: 0, username: "");
break;
}
return ImageGrid(dProvider: provider);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(widget.title), title: Text(widget.title),
), ),
body: FutureBuilder( body: _buildPage(),
future: folder, drawer: Drawer(
builder: (context, snapshot) { child: ListView(
if (snapshot.hasData) { padding: EdgeInsets.zero,
final data = snapshot.data!; children: [
DrawerHeader(
return GridView.builder( decoration: BoxDecoration(
controller: _controller, color: Theme.of(context).primaryColor,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 0,
mainAxisSpacing: 0,
crossAxisCount: width ~/ 300,
), ),
itemCount: data.items.length + 1, child: const Text('Gallery'),
itemBuilder: (context, index) { ),
if (index == 0) { ListTile(
return ImageTile( title: const Text('Local'),
child: const Icon(Icons.arrow_back, size: 142), onTap: () {
onClick: () { setState(() {
setState(() { page = Page.local;
folder = dprovider.listOfFiles(uri: data.parent); });
});
},
);
}
final elem = data.items[index - 1];
return ImageTile(
dtaProvider: dprovider,
imageUri: elem.isFolder ? null : elem.uri,
onClick: () {
if (elem.isFolder) {
setState(() {
folder = dprovider.listOfFiles(uri: elem.uri);
});
_controller.jumpTo(.0);
} else {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
final d = data.items
.where((element) => !element.isFolder)
.toList(growable: false);
// check how many folders are before index and subtract it
final newidx = index -
data.items
.getRange(0, index)
.where((element) => element.isFolder)
.length;
return FullScreenImageView(
provider: dprovider,
items: d,
idx: newidx,
);
}),
);
}
},
child: elem.isFolder
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.folder_open, size: 142),
Text(elem.name)
],
)
: null);
}, },
); ),
} else if (snapshot.hasError) { ListTile(
return const Text("Error loading files"); title: const Text('Remote'),
} onTap: () {
setState(() {
return const CircularProgressIndicator( page = Page.remote;
strokeWidth: 3, });
); },
}, ),
), ],
floatingActionButton: FloatingActionButton( ),
onPressed: () {
_controller.animateTo(.0,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOutQuad);
},
tooltip: 'Increment',
child: const Icon(Icons.arrow_upward),
), ),
// floatingActionButton: FloatingActionButton(
// onPressed: () {
// // _controller.animateTo(.0,
// // duration: const Duration(milliseconds: 400),
// // curve: Curves.easeInOutQuad);
// },
// tooltip: 'Increment',
// child: const Icon(Icons.arrow_upward),
// ),
); );
} }
} }

117
lib/image_grid.dart Normal file
View File

@ -0,0 +1,117 @@
import 'package:flutter/material.dart';
import 'data_provider/data_provider.dart';
import 'full_screen_image_view.dart';
import 'image_tile.dart';
class ImageGrid extends StatefulWidget {
const ImageGrid({Key? key, required this.dProvider}) : super(key: key);
final DataProvider dProvider;
@override
State<ImageGrid> createState() => _ImageGridState();
}
class _ImageGridState extends State<ImageGrid> {
final ScrollController _controller = ScrollController();
late Future<Folder> folder = widget.dProvider.listOfFiles();
@override
void didUpdateWidget(ImageGrid oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.dProvider != widget.dProvider) {
folder = widget.dProvider.listOfFiles();
}
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return FutureBuilder(
future: (() async {
await widget.dProvider.connect();
return folder;
}).call(),
builder: (context, AsyncSnapshot<Folder> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData && snapshot.data != null) {
final Folder data = snapshot.data!;
return GridView.builder(
controller: _controller,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 0,
mainAxisSpacing: 0,
crossAxisCount: width ~/ 300,
),
itemCount: data.items.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return ImageTile(
child: const Icon(Icons.arrow_back, size: 142),
onClick: () {
setState(() {
folder = widget.dProvider.listOfFiles(uri: data.parent);
});
},
);
}
final elem = data.items[index - 1];
return ImageTile(
dtaProvider: widget.dProvider,
imageUri: elem.isFolder ? null : elem.uri,
onClick: () {
if (elem.isFolder) {
setState(() {
folder = widget.dProvider.listOfFiles(uri: elem.uri);
});
_controller.jumpTo(.0);
} else {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
final d = data.items
.where((element) => !element.isFolder)
.toList(growable: false);
// check how many folders are before index and subtract it
final newidx = index -
data.items
.getRange(0, index)
.where((element) => element.isFolder)
.length;
return FullScreenImageView(
provider: widget.dProvider,
items: d,
idx: newidx,
);
}),
);
}
},
child: elem.isFolder
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.folder_open, size: 142),
Text(elem.name)
],
)
: null);
},
);
} else if (snapshot.hasError) {
return const Text("Error loading files");
}
}
return const CircularProgressIndicator(
strokeWidth: 3,
);
},
);
}
}