sending progress to ui with very epic animated upload progress

This commit is contained in:
RafayAhmad7548 2025-08-02 08:39:31 +05:00
parent b3b2fc8895
commit ce6374d302
3 changed files with 70 additions and 13 deletions

View file

@ -11,6 +11,7 @@ class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.teal,

View file

@ -21,6 +21,8 @@ class _SftpExplorerState extends State<SftpExplorer> {
bool _isLoading = true;
late List<SftpName> _dirContents;
double? _progress;
@override
void initState() {
super.initState();
@ -45,7 +47,29 @@ class _SftpExplorerState extends State<SftpExplorer> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 75,
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),
body: _isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder(
@ -234,7 +258,18 @@ class _SftpExplorerState extends State<SftpExplorer> {
final files = await openFiles();
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();
},
child: Icon(Icons.upload),

View file

@ -24,7 +24,7 @@ class SftpWorker {
final ReceivePort _responses;
final SendPort _commands;
final Map<int, Completer<Object>> _activeRequests = {};
final Map<int, dynamic> _activeRequests = {};
int _idCounter = 0;
SftpWorker._(this._responses, this._commands) {
@ -98,24 +98,31 @@ class SftpWorker {
'$path${basename(filePath)}',
mode: SftpFileOpenMode.create | SftpFileOpenMode.write | SftpFileOpenMode.exclusive
);
bool timeout = true;
await remoteFile.write(
file.openRead().cast(),
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) {
sendPort.send((id, RemoteError(e.message, '')));
}
sendPort.send((id, 1.0));
}
sendPort.send((id, 0));
}
});
}
void _sftpResponseHandler(dynamic message) {
final (int id, Object response) = message;
if (_activeRequests[id] is Completer) {
final completer = _activeRequests.remove(id)!;
if (response is RemoteError) {
@ -125,6 +132,20 @@ class SftpWorker {
completer.complete(response);
}
}
else if (_activeRequests[id] is StreamController) {
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);
}
}
}
}
Future<List<SftpName>> listdir(String path) async {
@ -136,12 +157,12 @@ class SftpWorker {
}
Future<void> uploadFiles(String path, List<String> filePaths) async {
final completer = Completer<Object>.sync();
Stream<double> uploadFiles(String path, List<String> filePaths) {
final controller = StreamController<double>();
final id = _idCounter++;
_activeRequests[id] = completer;
_activeRequests[id] = controller;
_commands.send((id, UploadFiles(path, filePaths)));
await completer.future;
return controller.stream;
}