new drawer to different image locations
This commit is contained in:
parent
fc0ab443e9
commit
195898009c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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!;
|
|
||||||
|
|
||||||
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 = 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: [
|
children: [
|
||||||
const Icon(Icons.folder_open, size: 142),
|
DrawerHeader(
|
||||||
Text(elem.name)
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
child: const Text('Gallery'),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Local'),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
page = Page.local;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Remote'),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
page = Page.remote;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
|
||||||
: null);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return const Text("Error loading files");
|
|
||||||
}
|
|
||||||
|
|
||||||
return const CircularProgressIndicator(
|
|
||||||
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
117
lib/image_grid.dart
Normal 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,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user