Created
September 24, 2025 14:18
-
-
Save rena2019/dc7122a1021ac44570e9f4d90858bf14 to your computer and use it in GitHub Desktop.
Overlay Popup 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'; | |
| //Overlay Popup with Stream | |
| void main() => runApp(MyApp()); | |
| class MyApp extends StatelessWidget { | |
| @override | |
| Widget build(BuildContext context) => MaterialApp(home: HomePage()); | |
| } | |
| /* --- Beispiel-Datenmodell & Kommunikation --- */ | |
| class MyStreamData { | |
| final double progress; // 0.0 - 1.0 | |
| final String? message; | |
| MyStreamData(this.progress, {this.message}); | |
| } | |
| class MyCommunication { | |
| // Simulierter Stream, in realem Code würdest du hier echte Daten liefern | |
| final StreamController<MyStreamData> _ctrl = StreamController.broadcast(); | |
| Stream<MyStreamData> get incomingStream => _ctrl.stream; | |
| // Für Demo: starte simulation | |
| void startSimulation() async { | |
| for (int i = 0; i <= 10; i++) { | |
| await Future.delayed(Duration(milliseconds: 400)); | |
| _ctrl.add(MyStreamData(i / 10, message: 'Step $i/10')); | |
| } | |
| await Future.delayed(Duration(milliseconds: 500)); | |
| _ctrl.add(MyStreamData(1.0, message: 'Fertig')); | |
| } | |
| void dispose() => _ctrl.close(); | |
| } | |
| /* --- PopupMessage Widget-Klasse (zustandsbehaftet) --- */ | |
| class PopupMessage extends StatefulWidget { | |
| final Stream<MyStreamData> progressStream; | |
| final VoidCallback onClose; | |
| final String title; | |
| PopupMessage({ | |
| required this.progressStream, | |
| required this.onClose, | |
| this.title = 'Ladevorgang', | |
| Key? key, | |
| }) : super(key: key); | |
| @override | |
| _PopupMessageState createState() => _PopupMessageState(); | |
| } | |
| class _PopupMessageState extends State<PopupMessage> { | |
| late StreamSubscription<MyStreamData> _sub; | |
| double _progress = 0.0; | |
| String? _message; | |
| @override | |
| void initState() { | |
| super.initState(); | |
| _sub = widget.progressStream.listen((data) { | |
| setState(() { | |
| _progress = data.progress.clamp(0.0, 1.0); | |
| _message = data.message; | |
| }); | |
| // Optional: automatisch schließen, wenn fertig | |
| if (_progress >= 1.0) { | |
| Future.delayed(Duration(milliseconds: 300), () { | |
| widget.onClose(); | |
| }); | |
| } | |
| }, onError: (err) { | |
| // Fehlerbehandlung hier | |
| }); | |
| } | |
| @override | |
| void dispose() { | |
| _sub.cancel(); | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Material( | |
| color: Colors.black54, // halbtransparenter Modal-Hintergrund | |
| child: Center( | |
| child: Container( | |
| width: 320, | |
| padding: EdgeInsets.all(16), | |
| decoration: BoxDecoration( | |
| color: Colors.white, | |
| borderRadius: BorderRadius.circular(12), | |
| ), | |
| child: Column( | |
| mainAxisSize: MainAxisSize.min, //vertical center | |
| children: [ | |
| Text(widget.title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), | |
| SizedBox(height: 12), | |
| LinearProgressIndicator(value: _progress), | |
| SizedBox(height: 12), | |
| Text(_message ?? '${(_progress * 100).round()}%'), | |
| SizedBox(height: 16), | |
| Row( | |
| mainAxisAlignment: MainAxisAlignment.end, | |
| children: [ | |
| TextButton(onPressed: widget.onClose, child: Text('Abbrechen')), | |
| ], | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| /* --- HomePage: zeigt wie OverlayEntry genutzt wird --- */ | |
| class HomePage extends StatefulWidget { | |
| @override | |
| _HomePageState createState() => _HomePageState(); | |
| } | |
| class _HomePageState extends State<HomePage> { | |
| final MyCommunication comm = MyCommunication(); | |
| OverlayEntry? _overlayEntry; | |
| void _showPopup() { | |
| if (_overlayEntry != null) return; // bereits sichtbar | |
| _overlayEntry = OverlayEntry( | |
| builder: (context) { | |
| return PopupMessage( | |
| progressStream: comm.incomingStream, | |
| onClose: _removePopup, | |
| title: 'Upload', | |
| ); | |
| }, | |
| ); | |
| Overlay.of(context)!.insert(_overlayEntry!); | |
| // Demo: starte Simulationsdaten | |
| comm.startSimulation(); | |
| } | |
| void _removePopup() { | |
| _overlayEntry?.remove(); | |
| _overlayEntry = null; | |
| } | |
| @override | |
| void dispose() { | |
| comm.dispose(); | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Scaffold( | |
| appBar: AppBar(title: Text('Overlay Popup mit Stream')), | |
| body: Center( | |
| child: ElevatedButton( | |
| onPressed: _showPopup, | |
| child: Text('Zeige PopupMessage'), | |
| ), | |
| ), | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment