Skip to content

Instantly share code, notes, and snippets.

@rena2019
Created September 4, 2025 17:11
Show Gist options
  • Save rena2019/9fe349e6eae13dca3e6570a7216b2704 to your computer and use it in GitHub Desktop.
Save rena2019/9fe349e6eae13dca3e6570a7216b2704 to your computer and use it in GitHub Desktop.
Flutter Stream example
import 'dart:async';
import 'package:flutter/material.dart';
//wrapper class for progress + data
class DataWithProgress<T> {
final T? data;
final int progress; // 0..100
final Object? error;
final bool done;
DataWithProgress({this.data, required this.progress, this.error, this.done = false});
}
// Producer (async* Beispiel)
Stream<DataWithProgress<int>> produce() async* {
int total = 5;
for (int i = 1; i <= total; i++) {
await Future.delayed(Duration(seconds: 1));
int progress = ((i / total) * 100).round();
yield DataWithProgress(data: i, progress: progress);
}
// optional: endgültiger Done-Event
yield DataWithProgress(progress: 100, done: true);
}
void main() async {
final controller = StreamController<DataWithProgress>();
// Listener
print("1. Listener ---");
controller.stream.listen((value) {
print('Received progress: ${value.progress}%, data: ${value.data}');
}, onDone: () => print('Stream closed (onDone)'),);
// Adding data
controller.sink.add(DataWithProgress(progress: 1));
await Future.delayed(Duration(seconds: 1));
controller.sink.add(DataWithProgress(progress: 33, data: 1));
await Future.delayed(Duration(seconds: 2));
controller.sink.add(DataWithProgress(progress: 66, data: 2));
await Future.delayed(Duration(seconds: 1));
controller.sink.add(DataWithProgress(progress: 99, data: 3));
controller.sink.add(DataWithProgress(progress: 100, done: true));
// Closing the stream
controller.close();
//consume stream with async* function
print("2. consume stream with async* function ---");
await for (final event in produce()) {
if (event.data != null) print('Data: ${event.data} — ${event.progress}%');
if (event.done) print('Producer signaled done');
}
print('Stream finished');
//UI
print("3. UI ---");
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: ProgressDemoPage());
}
}
class ProgressDemoPage extends StatefulWidget {
const ProgressDemoPage({super.key});
@override
State<ProgressDemoPage> createState() => _ProgressDemoPageState();
}
class _ProgressDemoPageState extends State<ProgressDemoPage> {
late Stream<DataWithProgress<int>> _stream;
@override
void initState() {
super.initState();
_stream = produce();
}
void _restart() {
setState(() {
_stream = produce();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Progress Stream Demo')),
body: Center(
child: StreamBuilder<DataWithProgress<int>>(
stream: _stream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 12),
Text('Warte auf erste Updates...'),
],
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
final e = snapshot.data!;
final displayData = e.data != null ? 'Data: ${e.data}' : 'No data';
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(displayData, style: const TextStyle(fontSize: 24)),
const SizedBox(height: 12),
SizedBox(
width: 250,
child: LinearProgressIndicator(value: e.progress / 100),
),
const SizedBox(height: 8),
Text('${e.progress}%'),
if (e.done) const Padding(
padding: EdgeInsets.only(top: 8.0),
child: Text('Fertig', style: TextStyle(color: Colors.green)),
),
],
);
} else {
return const Text('No data available');
}
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: _restart,
child: const Icon(Icons.replay),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment