import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_broadcast_receiver/flutter_broadcast_receiver.dart'; import 'package:isar/isar.dart'; import 'package:path_provider/path_provider.dart'; import 'package:stadtbote/model/message.dart'; import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/tools/colored_safe_area.dart'; import 'package:stadtbote/model/status.dart'; import 'package:stadtbote/tools/connection_status.dart'; import 'tools/mqtt_core.dart'; import 'content_views/main_page.dart'; import 'content_views/utils/content_view_widget.dart'; import 'content_views/utils/widget_stack.dart'; import 'model/job.dart'; import 'tools/constants.dart'; import 'tools/util.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); final dir = await getApplicationDocumentsDirectory(); MyApp.isarInstance = await Isar.open([ StatusSchema, JobSchema, TaskInfoSchema, MessageSchema, ], directory: dir.path); runZonedGuarded(() { }, (error, stackTrace) { _traceUncaughtExceptions(error, stackTrace); }); MqttCore.setup(); runApp(const MyApp()); } void _traceUncaughtExceptions(Object error, StackTrace stackTrace) { Util.logException('Ein Fehler ist aufgetreten: $error'); Util.logException('Stack-Trace: $stackTrace'); } class MyApp extends StatelessWidget { const MyApp({super.key}); static late Isar isarInstance; @override Widget build(BuildContext context) { return MaterialApp( title: 'Stadtbote', theme: ThemeData( primarySwatch: Colors.blue, ), home: const Main(), ); } } class Main extends StatefulWidget { const Main({super.key}); @override State
createState() => _MainState(); } class _MainState extends State
{ late ContentViewWidget _currentContent; late WidgetStack contentStack = WidgetStack(); late Widget _currentTitleWidget; late Widget _leftIconButton; late Widget _rightIconButton; late bool _leftButtonVisible = false; late bool _rightButtonVisible = false; late Function _rightButtonOnPressed; late Function _leftButtonOnPressed; bool _initCompleted = false; final ValueNotifier _connectionLostValueNotifier = ValueNotifier(true); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { _initMessages(); _currentContent = MainPage(); var headerInfo = await _currentContent.getHeaderInfo(context); _currentTitleWidget = headerInfo.titleWidget; _leftButtonVisible = false; _leftIconButton = const Icon(Icons.arrow_back, size: 20.0, color: Colors.white); _leftButtonOnPressed = () { _popContentView(); }; _rightButtonVisible = headerInfo.rightButtonVisible; _rightButtonOnPressed = headerInfo.rightButtonOnPressed; if (headerInfo.rightButtonEnabled) { _rightIconButton = await headerInfo.rightButtonImage as Widget; } _initCompleted = true; setState(() {}); }); } @override void dispose() { super.dispose(); //_subscription.cancel(); } @override Widget build(BuildContext context) { if (!_initCompleted) { return Util.getWaitWidget(context); } return ColoredSafeArea( key: GlobalKey(), child: WillPopScope( onWillPop: () async { if (contentStack.isNotEmpty) { _popContentView(); return false; } else { return true; } }, child: Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(100), child: ColoredSafeArea( key: const Key("appBar"), child: SizedBox( height: 100, child: Padding( padding: const EdgeInsets.all(8), child: Stack( alignment: Alignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Visibility( visible: _leftButtonVisible, child: Container( width: 60, height: 60, decoration: const BoxDecoration( shape: BoxShape.circle, color: Colors.white, ), child: FittedBox( child: GestureDetector( onTap: () async { _leftButtonOnPressed(); }, child: CircleAvatar( radius: 15, backgroundColor: Constants.colorPrimary, child: Padding(padding: const EdgeInsets.all(1.0), child: _leftIconButton), ), ), ), ), ), Visibility( visible: _rightButtonVisible, child: Container( width: 60, height: 60, decoration: const BoxDecoration( shape: BoxShape.circle, color: Colors.red, ), child: FittedBox( child: GestureDetector( onTap: () async { _rightButtonOnPressed(); }, child: CircleAvatar( backgroundColor: Constants.colorPrimary, radius: 15, child: Padding(padding: const EdgeInsets.all(1.0), child: _rightIconButton), ), ), ), ), ), ], ), SizedBox( height: 100, width: 300, child: Center( heightFactor: 1, child: _currentTitleWidget), ), ], ), ), )), ), body: Column( children: [ ValueListenableBuilder( valueListenable: _connectionLostValueNotifier, builder: (context, value, child) { return Visibility( visible: value, child: Container( width: MediaQuery.of(context).size.width, height: 30, color: Colors.red, child: const Center( child: Text("*** OFFLINE ***", style: TextStyle( color: Colors.white, fontSize: 15.0, ),), ), ), ); }, ), Expanded(child: _currentContent), ], ),// This trailing comma makes auto-formatting nicer for build methods. ), ), ); } void _initMessages() { BroadcastReceiver().subscribe(Constants.messageTopicPushContentView, (ContentViewWidget widget) { _pushContentView(widget); }); BroadcastReceiver().subscribe(Constants.messageTopicPopContentView, (ContentViewWidget widget) { _popContentView(); }); BroadcastReceiver().subscribe(Constants.messageTopicReplaceContentView, (ContentViewWidget widget) { _replaceContentView(widget); }); BroadcastReceiver().subscribe(Constants.messageTopicHideRightButton, (hideButton) { _hideRightButton(hideButton); }); BroadcastReceiver().subscribe(Constants.messageTopicConnectionStatusChanged, (ConnectionStatus connectionStatus) { _connectionStatusChanged(connectionStatus); }); } void _replaceContentView(ContentViewWidget widget) async { Future.delayed(const Duration(seconds: 0), () async { contentStack.clear(); setState(() { _currentContent = widget; }); var headerInfo = await _currentContent.getHeaderInfo(context); _currentTitleWidget = headerInfo.titleWidget; _rightButtonVisible = headerInfo.rightButtonVisible; _rightButtonOnPressed = headerInfo.rightButtonOnPressed; if (headerInfo.rightButtonEnabled) { _rightIconButton = await headerInfo.rightButtonImage as Widget; } _leftButtonVisible = false; setState(() {}); }); } void _popContentView() { Future.delayed(const Duration(seconds: 0), () async { var previousContentView = contentStack.pop(); _currentContent = previousContentView; var headerInfo = await _currentContent.getHeaderInfo(context); _currentTitleWidget = headerInfo.titleWidget; _rightButtonVisible = headerInfo.rightButtonVisible; _rightButtonOnPressed = headerInfo.rightButtonOnPressed; if (headerInfo.rightButtonEnabled) { _rightIconButton = await headerInfo.rightButtonImage as Widget; } if (contentStack.isEmpty) { _leftButtonVisible = false; } setState(() {}); }); } void _pushContentView(ContentViewWidget widget) { Future.delayed(const Duration(seconds: 0), () async { contentStack.push(_currentContent); _currentContent = widget; var headerInfo = await _currentContent.getHeaderInfo(context); _currentTitleWidget = headerInfo.titleWidget; _rightButtonVisible = headerInfo.rightButtonVisible; _rightButtonOnPressed = headerInfo.rightButtonOnPressed; if (headerInfo.rightButtonEnabled) { _rightIconButton = await headerInfo.rightButtonImage as Widget; } _leftButtonVisible = true; setState(() {}); }); } void _hideRightButton(bool hideButton) { setState(() { _rightButtonVisible = !hideButton; }); } void _connectionStatusChanged(ConnectionStatus connectionStatus) { _connectionLostValueNotifier.value = connectionStatus.status == ConnectionStatusEnum.notConnected; } }