sending progress to ui with very epic animated upload progress
This commit is contained in:
parent
b3b2fc8895
commit
ce6374d302
3 changed files with 70 additions and 13 deletions
|
@ -11,6 +11,7 @@ class MainApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
colorSchemeSeed: Colors.teal,
|
colorSchemeSeed: Colors.teal,
|
||||||
|
|
|
@ -20,6 +20,8 @@ class _SftpExplorerState extends State<SftpExplorer> {
|
||||||
|
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
late List<SftpName> _dirContents;
|
late List<SftpName> _dirContents;
|
||||||
|
|
||||||
|
double? _progress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -45,7 +47,29 @@ class _SftpExplorerState extends State<SftpExplorer> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
toolbarHeight: 75,
|
||||||
title: Text('Explorer'),
|
title: Text('Explorer'),
|
||||||
|
elevation: 2,
|
||||||
|
actionsPadding: EdgeInsets.only(right: 20),
|
||||||
|
actions: [
|
||||||
|
if (_progress != null)
|
||||||
|
Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
TweenAnimationBuilder<double>(
|
||||||
|
tween: Tween(begin: 0, end: _progress),
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
builder: (context, value, _) => CircularProgressIndicator(strokeWidth: 3, value: value,)
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.upload)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: _buildFABs(context),
|
floatingActionButton: _buildFABs(context),
|
||||||
body: _isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder(
|
body: _isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder(
|
||||||
|
@ -234,7 +258,18 @@ class _SftpExplorerState extends State<SftpExplorer> {
|
||||||
final files = await openFiles();
|
final files = await openFiles();
|
||||||
filePaths = files.map((file) => file.path).toList();
|
filePaths = files.map((file) => file.path).toList();
|
||||||
}
|
}
|
||||||
await widget.sftpWorker.uploadFiles(widget.path, filePaths);
|
try {
|
||||||
|
await for (final progress in widget.sftpWorker.uploadFiles(widget.path, filePaths)) {
|
||||||
|
print(progress);
|
||||||
|
setState(() => _progress = progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setState(() => _progress = null);
|
||||||
_listDir();
|
_listDir();
|
||||||
},
|
},
|
||||||
child: Icon(Icons.upload),
|
child: Icon(Icons.upload),
|
||||||
|
|
|
@ -24,7 +24,7 @@ class SftpWorker {
|
||||||
|
|
||||||
final ReceivePort _responses;
|
final ReceivePort _responses;
|
||||||
final SendPort _commands;
|
final SendPort _commands;
|
||||||
final Map<int, Completer<Object>> _activeRequests = {};
|
final Map<int, dynamic> _activeRequests = {};
|
||||||
int _idCounter = 0;
|
int _idCounter = 0;
|
||||||
|
|
||||||
SftpWorker._(this._responses, this._commands) {
|
SftpWorker._(this._responses, this._commands) {
|
||||||
|
@ -98,31 +98,52 @@ class SftpWorker {
|
||||||
'$path${basename(filePath)}',
|
'$path${basename(filePath)}',
|
||||||
mode: SftpFileOpenMode.create | SftpFileOpenMode.write | SftpFileOpenMode.exclusive
|
mode: SftpFileOpenMode.create | SftpFileOpenMode.write | SftpFileOpenMode.exclusive
|
||||||
);
|
);
|
||||||
|
bool timeout = true;
|
||||||
await remoteFile.write(
|
await remoteFile.write(
|
||||||
file.openRead().cast(),
|
file.openRead().cast(),
|
||||||
onProgress: (progress) {
|
onProgress: (progress) {
|
||||||
print(progress/fileSize);
|
if (timeout) {
|
||||||
|
timeout = false;
|
||||||
|
sendPort.send((id, progress/fileSize));
|
||||||
|
Future.delayed(Duration(seconds: 2), () => timeout = true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
on SftpStatusError catch (e) {
|
on SftpStatusError catch (e) {
|
||||||
sendPort.send((id, RemoteError(e.message, '')));
|
sendPort.send((id, RemoteError(e.message, '')));
|
||||||
}
|
}
|
||||||
|
sendPort.send((id, 1.0));
|
||||||
}
|
}
|
||||||
sendPort.send((id, 0));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sftpResponseHandler(dynamic message) {
|
void _sftpResponseHandler(dynamic message) {
|
||||||
final (int id, Object response) = message;
|
final (int id, Object response) = message;
|
||||||
final completer = _activeRequests.remove(id)!;
|
|
||||||
|
|
||||||
if (response is RemoteError) {
|
if (_activeRequests[id] is Completer) {
|
||||||
completer.completeError(response);
|
final completer = _activeRequests.remove(id)!;
|
||||||
|
|
||||||
|
if (response is RemoteError) {
|
||||||
|
completer.completeError(response);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
completer.complete(response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (_activeRequests[id] is StreamController) {
|
||||||
completer.complete(response);
|
final controller = _activeRequests[id] as StreamController;
|
||||||
|
if (response is RemoteError) {
|
||||||
|
controller.addError(response);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.add(response);
|
||||||
|
if (response == 1) {
|
||||||
|
controller.close();
|
||||||
|
_activeRequests.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,12 +157,12 @@ class SftpWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> uploadFiles(String path, List<String> filePaths) async {
|
Stream<double> uploadFiles(String path, List<String> filePaths) {
|
||||||
final completer = Completer<Object>.sync();
|
final controller = StreamController<double>();
|
||||||
final id = _idCounter++;
|
final id = _idCounter++;
|
||||||
_activeRequests[id] = completer;
|
_activeRequests[id] = controller;
|
||||||
_commands.send((id, UploadFiles(path, filePaths)));
|
_commands.send((id, UploadFiles(path, filePaths)));
|
||||||
await completer.future;
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue