Created
September 24, 2025 14:20
-
-
Save rena2019/b9d3d78f2b849cbfcf1d7d4e9b486fa9 to your computer and use it in GitHub Desktop.
Progress Popup Widget with Stream
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:async'; | |
| import 'package:flutter/material.dart'; | |
| //Progress Popup Widget with Stream | |
| /// Beispiel-Datenmodell, das vom Stream gesendet wird. | |
| class MyStreamData { | |
| final double progress; // 0.0 .. 1.0 | |
| final String? message; | |
| final bool done; | |
| MyStreamData({required this.progress, this.message, this.done = false}); | |
| } | |
| /// Kommunikation-Klasse, die einen Stream erzeugt. | |
| /// In der Praxis kommt der Stream z.B. von WebSocket, Isolate, HTTP-Upload-Progress etc. | |
| class MyCommunication { | |
| final StreamController<MyStreamData> _controller = StreamController.broadcast(); | |
| Stream<MyStreamData> get incomingStream => _controller.stream; | |
| /// Beispiel: startet eine simulierte Progress-Übertragung | |
| void startSimulatedTransfer({Duration step = const Duration(milliseconds: 300)}) { | |
| double p = 0.0; | |
| Timer.periodic(step, (t) { | |
| p += 0.05; | |
| if (p >= 1.0) { | |
| _controller.add(MyStreamData(progress: 1.0, message: 'Fertig', done: true)); | |
| t.cancel(); | |
| return; | |
| } | |
| _controller.add(MyStreamData(progress: p, message: 'Lade ${ (p*100).round() }%')); | |
| }); | |
| } | |
| void dispose() { | |
| _controller.close(); | |
| } | |
| } | |
| /// PopupMessage Widget zeigt eine simple Card mit ProgressBar und Text. | |
| /// Es verwaltet eine StreamSubscription<MyStreamData> und aktualisiert State. | |
| class PopupMessage extends StatefulWidget { | |
| final Stream<MyStreamData> stream; | |
| final VoidCallback? onDone; | |
| const PopupMessage({Key? key, required this.stream, this.onDone}) : super(key: key); | |
| @override | |
| State<PopupMessage> createState() => _PopupMessageState(); | |
| } | |
| class _PopupMessageState extends State<PopupMessage> { | |
| late StreamSubscription<MyStreamData> _sub; | |
| double _progress = 0.0; | |
| String _text = 'Warte...'; | |
| bool _visible = true; | |
| @override | |
| void initState() { | |
| super.initState(); | |
| _sub = widget.stream.listen((data) { | |
| // Aktualisiere UI bei neuen Daten | |
| setState(() { | |
| _progress = data.progress.clamp(0.0, 1.0); | |
| if (data.message != null) _text = data.message!; | |
| if (data.done) { | |
| _visible = false; | |
| } | |
| }); | |
| // optional: Callback informieren | |
| if (data.done) widget.onDone?.call(); | |
| }, onError: (e) { | |
| setState(() { | |
| _text = 'Fehler: $e'; | |
| _visible = false; | |
| }); | |
| }, onDone: () { | |
| setState(() { | |
| _visible = false; | |
| }); | |
| }); | |
| } | |
| @override | |
| void dispose() { | |
| _sub.cancel(); | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| if (!_visible) return const SizedBox.shrink(); | |
| return Center( | |
| child: Material( | |
| color: Colors.transparent, | |
| child: Card( | |
| elevation: 8, | |
| child: SizedBox( | |
| width: 300, | |
| child: Padding( | |
| padding: const EdgeInsets.all(16.0), | |
| child: Column( | |
| mainAxisSize: MainAxisSize.min, | |
| children: [ | |
| Text(_text), | |
| const SizedBox(height: 12), | |
| LinearProgressIndicator(value: _progress), | |
| const SizedBox(height: 12), | |
| Row( | |
| mainAxisAlignment: MainAxisAlignment.end, | |
| children: [ | |
| Text('${(_progress * 100).round()}%'), | |
| ], | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| /// Minimaler demo App, die PopupMessage in einem Stack zeigt. | |
| class DemoApp extends StatefulWidget { | |
| @override | |
| State<DemoApp> createState() => _DemoAppState(); | |
| } | |
| class _DemoAppState extends State<DemoApp> { | |
| final MyCommunication comm = MyCommunication(); | |
| bool _showPopup = false; | |
| @override | |
| void dispose() { | |
| comm.dispose(); | |
| super.dispose(); | |
| } | |
| void _start() { | |
| setState(() => _showPopup = true); | |
| comm.startSimulatedTransfer(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| home: Scaffold( | |
| appBar: AppBar(title: const Text('Popup Progress Demo')), | |
| body: Stack( | |
| children: [ | |
| Center( | |
| child: ElevatedButton( | |
| onPressed: _start, | |
| child: const Text('Starte Transfer'), | |
| ), | |
| ), | |
| if (_showPopup) | |
| PopupMessage( | |
| stream: comm.incomingStream, | |
| onDone: () { | |
| // Popup nach kurzer Verzögerung schließen | |
| Future.delayed(const Duration(milliseconds: 400), () { | |
| setState(() => _showPopup = false); | |
| }); | |
| }, | |
| ), | |
| ], | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| void main() => runApp(DemoApp()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment