Every time I try to run my flutter app that has been previously working, I get No Firebase App '[Default]' error. I have this project connected to my GitHub and I downloaded a different version and it seemed to work fine, so I thought to revert my main repo to that commit, and then the same thing happened again. I did a git compare and found no differences in the files, which made it hard to find out what was happening.
Error caught in the debug console
════════ Exception caught by widgets library ═══════════════════════════════════
The following FirebaseException was thrown building FutureBuilder<FirebaseApp>(dirty, state: _FutureBuilderState<FirebaseApp>#d30ed):
[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
The relevant error-causing widget was
FutureBuilder<FirebaseApp>
package:mynotes/main.dart:105
When the exception was thrown, this was the stack
#0 MethodChannelFirebase.app
package:firebase_core_platform_interface/…/method_channel/method_channel_firebase.dart:193
#1 Firebase.app
package:firebase_core/src/firebase.dart:53
#2 FirebaseAuth.instance
package:firebase_auth/src/firebase_auth.dart:38
#3 Setup.build.<anonymous closure>
package:mynotes/main.dart:110
#4 _FutureBuilderState.build
package:flutter/…/widgets/async.dart:615
#5 StatefulElement.build
package:flutter/…/widgets/framework.dart:4919
#6 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4806
#7 StatefulElement.performRebuild
package:flutter/…/widgets/framework.dart:4977
#8 Element.rebuild
package:flutter/…/widgets/framework.dart:4529
#9 BuildOwner.buildScope
package:flutter/…/widgets/framework.dart:2659
#10 WidgetsBinding.drawFrame
package:flutter/…/widgets/binding.dart:891
#11 RendererBinding._handlePersistentFrameCallback
package:flutter/…/rendering/binding.dart:370
#12 SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1146
#13 SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1083
#14 SchedulerBinding._handleDrawFrame
package:flutter/…/scheduler/binding.dart:997
#18 _invoke (dart:ui/hooks.dart:151:10)
#19 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)
#20 _drawFrame (dart:ui/hooks.dart:115:31)
(elided 3 frames from dart:async)
════════════════════════════════════════════════════════════════════════════════
Main.dart
import 'dart:io';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_phoenix/flutter_phoenix.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:mynotes/constants/routes.dart';
import 'package:mynotes/services/auth/auth_service.dart';
import 'package:mynotes/services/auth/auth_user.dart';
import 'package:mynotes/services/hive/boxes.dart';
import 'package:mynotes/services/hive/settings_service.dart';
import 'package:mynotes/themes/themes.dart';
import 'package:mynotes/views/forgot_password_view.dart';
import 'package:mynotes/views/login_view.dart';
import 'package:mynotes/views/notes/create_update_note_view.dart';
import 'package:mynotes/views/main_ui.dart';
import 'package:mynotes/views/register_view.dart';
import 'package:mynotes/views/settings_view.dart';
import 'package:mynotes/views/verify_email_view.dart';
import "dart:developer" as devtools show log;
const double sizedBoxWidth = 300;
const double sizedBoxHeight = 300;
late Color textColor;
// const Color themeColor = Color.fromRGBO(85, 111, 68, 1);
const Color bgColor = Color.fromRGBO(20, 20, 20, 1);
const Color themeColor = Color.fromARGB(255, 107, 65, 114);
//const Color bgColor = Color.fromARGB(255, 31, 31, 31);
late ThemeData currentTheme;
const Color defTextColor = Colors.white;
dynamic loadingCircle;
late Icon shareIcon;
//Creates an empty sized box for sapce
SizedBox createSpace(double height) {
return SizedBox(height: height);
}
SizedBox createSpaceWidth(double height, double width) {
return SizedBox(
height: height,
width: width,
);
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(UserSettingsAdapter());
await Hive.openBox<UserSettings>("user_settings");
//Allows for app restart for themes
runApp(Phoenix(child: const HomePage()));
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final box = Boxes.getUserSettings();
//Making sure a first time user has the theme setting
if (box.containsKey("defaultKey")) {
if (box.get("defaultKey", defaultValue: UserSettings("Purple"))!.theme ==
"Green") {
currentTheme = MyThemes.greenTheme;
textColor = Colors.white;
} else if (box.get("defaultKey")!.theme == "White") {
currentTheme = MyThemes.lightTheme;
textColor = Colors.black;
} else {
currentTheme = MyThemes.purpleTheme;
textColor = Colors.white;
}
} else {
box.put("defaultKey", UserSettings("Purple"));
currentTheme = MyThemes.purpleTheme;
textColor = Colors.white;
}
return MaterialApp(
title: 'Flutter Demo',
theme: currentTheme,
debugShowCheckedModeBanner: false,
home: const Setup(),
routes: {
loginRoute: (context) => const LoginView(),
registerRoute: (context) => const RegisterView(),
notesRoute: (context) => const MainUIView(),
verifyRoute: (context) => const VerifyEmailView(),
createOrUpdateNoteRoute: (context) => const CreateUpdateNoteView(),
forgotPasswordViewRoute: (context) => const ForgotPasswordView(),
settingsRoute: (context) => const SettingsView(),
homeRoute: (context) => const HomePage(),
},
);
}
}
class Setup extends StatelessWidget {
const Setup({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: Firebase.initializeApp(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
if (user.emailVerified) {
return const MainUIView();
} else {
devtools.log(user.toString());
return const VerifyEmailView();
}
} else {
return const LoginView();
}
default:
if (Platform.isIOS) {
loadingCircle = const CupertinoActivityIndicator();
shareIcon = const Icon(Icons.ios_share);
} else {
loadingCircle = const CircularProgressIndicator();
shareIcon = const Icon(Icons.share);
}
return Scaffold(
body: Center(
child: SizedBox(
width: sizedBoxWidth,
height: sizedBoxHeight,
child: Center(child: loadingCircle),
),
),
);
}
},
);
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
//initialize it here
await Firebase.initializeApp(),
await Hive.initFlutter();
Hive.registerAdapter(UserSettingsAdapter());
await Hive.openBox<UserSettings>("user_settings");
//Allows for app restart for themes
runApp(Phoenix(child: const HomePage()));
}
static Future<FirebaseApp?> initialize() async {
await Firebase.initializeApp(
options: kIsWeb
? const FirebaseOptions(
appId: appId,
authDomain: authDomain,
apiKey: apiKey,
databaseURL: databaseURL,
projectId: projectId,
storageBucket: storageBucket,
messagingSenderId: messagingSenderId,
measurementId: measurementId,
)
: null);
return Firebase.app();
}
call it.
main() async{
await ClassName.initialize();
}
I am using it like that and it works fine.
Deleted and re-downloaded my project from Github, which fixed the issue.
Related
I have a push notification manager class that is singleton where I listen for notifications from Firebase FCM and I handle them based on the logic and open specific screens.
I init with BuildContext that PushtNotificatonManager class inside HomePage that iS called from main.dart.
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
PushNotificationsManager().listen(context);
}
This is code from main.dart
Future<void> backgroundHandler(RemoteMessage message) async {
print('Handling a background message ${message.messageId}');
print('Content of message: ' + message.toString());
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
configureInjections();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(backgroundHandler);
runApp(SayApp());
}
This is part of the code from PushNotificationsManager class
#injectable
class PushNotificationsManager {
static final PushNotificationsManager _instance = PushNotificationsManager._internal();
factory PushNotificationsManager() {
return _instance;
}
PushNotificationsManager._internal();
Future<void> listen(BuildContext context) async {
if (Platform.isIOS) {
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
await _handleNotifications(context);
}
} else {
await _handleNotifications(context);
}
}
Future<void> _handleNotifications(BuildContext context) async {
// gives the message on which user taps and it opened the app from terminated state
FirebaseMessaging.instance.getInitialMessage().then((message) {
if (message != null) {
openNotification(message, context);
}
});
// foreground
FirebaseMessaging.onMessage.listen((message) {
if (message.notification != null) {
_showInAppNotification(message);
}
});
// When the app is in background but opened and user taps on the notification
FirebaseMessaging.onMessageOpenedApp.listen((message) {
openNotification(message, context);
});
}
Inside showInAppNotifications I am trying to display notifications as pop up and when the user clicks on it, I try to open a specific screen.
void _displayInAppNotifications(RemoteMessage message) {
FlutterRingtonePlayer.playNotification();
showOverlayNotification((context) {
return GestureDetector(
onTap: () {
openNotification(message, context);
OverlaySupportEntry.of(context)!.dismiss();
},
child: SafeArea(
child: Card(
child: ListTile(
leading: message.data[NotificationType.NOTIFICATION_TYPE] ==
NotificationType.PRIVATE_MESSAGE_1_ON_1
? Avatar(text: message.notification!.title!)
: SizedBox.fromSize(
size: const Size(40, 40),
child: ClipOval(
child: Container(
child: SvgPicture.asset(SvgIcons.sayAppWaveLogo),
))),
title:
Text(message.notification!.title!, overflow: TextOverflow.ellipsis, maxLines: 1),
subtitle: Text(
message.notification!.body!,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
trailing: IconButton(
icon: Icon(Icons.close),
onPressed: () {
OverlaySupportEntry.of(context)!.dismiss();
}),
),
),
),
);
}, duration: Duration(seconds: 4), position: NotificationPosition.top);
}
I have this method navigateToChannelDetailsPage that is called from the above method and here I am getting an exception.
Future<void> navigateToChannelDetailsPage(ChannelEntity channel, BuildContext context) async {
var cubit = BlocProvider.of<HomeCubit>(context);
var isUserChannelMember = await cubit.isCurrentUserChannelMember(channel);
if (!isUserChannelMember) return;
var isUserMutedPublic = await cubit.getIsUserMutedPublic(channel);
if (isUserMutedPublic) channel.isUserMutedPublic = isUserMutedPublic;
return PageNavigator.navigate(
context, ChannelDetailsPage(channel: channel, isFromAdminNotification: true))
.then((_) {
FocusManager.instance.primaryFocus?.unfocus();
cubit.updateChannelMemberChatDetailsDataOnChannelClosed(channel);
});
}
This is the exception:
E/flutter (25412): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (25412): At this point the state of the widget's element tree is no longer stable.
E/flutter (25412): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter (25412): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:4241:9)
E/flutter (25412): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:4255:6)
E/flutter (25412): #2 Element.getElementForInheritedWidgetOfExactType (package:flutter/src/widgets/framework.dart:4286:12)
E/flutter (25412): #3 Provider._inheritedElementOf (package:provider/src/provider.dart:339:38)
E/flutter (25412): #4 Provider.of (package:provider/src/provider.dart:293:30)
E/flutter (25412): #5 BlocProvider.of (package:flutter_bloc/src/bloc_provider.dart:100:23)
E/flutter (25412): #6 PushNotificationsManager.navigateToChannelDetailsPage (package:say_app/presentation/notification/push_notifications_manager.dart:204:30)
E/flutter (25412): #7 PushNotificationsManager.openNotification (package:say_app/presentation/notification/push_notifications_manager.dart:180:9)
E/flutter (25412): <asynchronous suspension>
Any ideas?
You get that error because, by the time you wait for some things to finish the execution, you do something else on the app (go back one or few screens let's say) so your widget/screen gets disposed of and is no longer in the widget tree when you call PageNavigator.navigate(context, ...).
So to prevent that from happening, you can use the mounted flag to check if your StatefulWidget is still active, like:
if(mounted) PageNavigator.navigate(context, ...)
But in that case, the page will not get pushed if the widget is disposed of. So if you still want to push the new screen, no matter what happens in the meantime (even if that widget gets disposed of), you can have your global navigatorKey which you assign to the MaterialApp key property and use the context from navigatorKey while navigating, since it should always be usable (i.e. the MaterialApp should always be present in the widget tree). Solution example:
import 'package:flutter/material.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
home: const HomePage(),
);
}
}
So now you navigate like:
PageNavigator.navigate(navigatorKey.currentContext!, ...) // your use case
Navigator.of(navigatorKey.currentContext!).push(...) // the usual way using global navigatorKey
I added a new field to the class CloudNote, now I am getting an error!
I am getting the error when the app is trying to display a list.
Here is all my code without adding the field :: https://github.com/casas1010/flutter_firebase_vendor_management
I know its a simple issue, but I have tried to troubleshoot this for like an hour and have not made any progress
CloudNote class::
import 'package:cloud_firestore/cloud_firestore.dart';
import '/services/cloud/cloud_storage_constants.dart';
import 'package:flutter/foundation.dart';
/*
https://youtu.be/VPvVD8t02U8?t=87934
*/
#immutable
class CloudNote {
final String documentId;
final String jobCreatorId;
final String jobDescription;
final String jobState; // I added this
const CloudNote({
required this.documentId,
required this.jobCreatorId,
required this.jobDescription,
required this.jobState, // I added this
});
// acts as constructor
CloudNote.fromSnapshot(QueryDocumentSnapshot<Map<String, dynamic>> snapshot)
: documentId = snapshot.id,
jobCreatorId = snapshot.data()[jobCreatorIdColumn],
jobState = snapshot.data()[jobStateColumn], // I added this
jobDescription = snapshot.data()[jobDescriptionColumn] as String;
}
notes view ::
import 'package:flutter/material.dart';
import '/constants/routes.dart';
import '/enums/menu_action.dart';
import '/services/auth/auth_service.dart';
import '/services/cloud/cloud_note.dart';
import '/services/cloud/firebase_cloud_storage.dart';
import '/utilities/dialogs/logout_dialog.dart';
import '/views/notes/notes_list_view.dart';
class NotesView extends StatefulWidget {
const NotesView({Key? key}) : super(key: key);
#override
_NotesViewState createState() => _NotesViewState();
}
class _NotesViewState extends State<NotesView> {
late final FirebaseCloudStorage _notesService;
String get userId => AuthService.firebase().currentUser!.id;
#override
void initState() {
_notesService = FirebaseCloudStorage();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Your jobs'),
actions: [
IconButton(
onPressed: () {
Navigator.of(context).pushNamed(createOrUpdateNoteRoute);
},
icon: const Icon(Icons.add),
),
PopupMenuButton<MenuAction>(
onSelected: (value) async {
switch (value) {
case MenuAction.logout:
final shouldLogout = await showLogOutDialog(context);
if (shouldLogout) {
await AuthService.firebase().logOut();
Navigator.of(context).pushNamedAndRemoveUntil(
loginRoute,
(_) => false,
);
}
}
},
itemBuilder: (context) {
return const [
PopupMenuItem<MenuAction>(
value: MenuAction.logout,
child: Text('Log out'),
),
];
},
)
],
),
body: StreamBuilder(
stream: _notesService.allNotes(jobCreatorId: userId),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
case ConnectionState.active:
if (snapshot.hasData) {
final allNotes = snapshot.data as Iterable<CloudNote>;
return NotesListView(
notes: allNotes,
onDeleteNote: (note) async {
await _notesService.deleteNote(documentId: note.documentId);
},
onTap: (note) {
Navigator.of(context).pushNamed(
createOrUpdateNoteRoute,
arguments: note,
);
},
);
} else {
return const CircularProgressIndicator();
}
default:
return const CircularProgressIndicator();
}
},
),
);
}
}
Error
The following _TypeError was thrown building NotesListView(dirty):
type 'Null' is not a subtype of type 'String'
The relevant error-causing widget was
NotesListView
lib/…/notes/notes_view.dart:72
When the exception was thrown, this was the stack
#0 new CloudNote.fromSnapshot
package:ijob_clone_app/…/cloud/cloud_note.dart:26
#1 FirebaseCloudStorage.allNotes.<anonymous closure>.<anonymous closure>
package:ijob_clone_app/…/cloud/firebase_cloud_storage.dart:39
#2 MappedListIterable.elementAt (dart:_internal/iterable.dart:413:31)
#3 ListIterator.moveNext (dart:_internal/iterable.dart:342:26)
#4 WhereIterator.moveNext (dart:_internal/iterable.dart:438:22)
#5 Iterable.length (dart:core/iterable.dart:497:15)
#6 NotesListView.build
package:ijob_clone_app/…/notes/notes_list_view.dart:26
#7 StatelessElement.build
package:flutter/…/widgets/framework.dart:4949
#8 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4878
#9 Element.rebuild
package:flutter/…/widgets/framework.dart:4604
#10 ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:4859
#11 ComponentElement.mount
package:flutter/…/widgets/framework.dart:4853
#12 Element.inflateWidget
package:flutter/…/widgets/framework.dart:3863
#13 Element.updateChild
package:flutter/…/widgets/framework.dart:3586
#14 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4904
#15 StatefulElement.performRebuild
package:flutter/…/widgets/framework.dart:5050
#16 Element.rebuild
package:flutter/…/widgets/framework.dart:4604
#17 BuildOwner.buildScope
package:flutter/…/widgets/framework.dart:2667
#18 WidgetsBinding.drawFrame
package:flutter/…/widgets/binding.dart:882
#19 RendererBinding._handlePersistentFrameCallback
package:flutter/…/rendering/binding.dart:378
#20 SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1175
#21 SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1104
#22 SchedulerBinding._handleDrawFrame
package:flutter/…/scheduler/binding.dart:1015
#23 _invoke (dart:ui/hooks.dart:148:13)
#24 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#25 _drawFrame (dart:ui/hooks.dart:115:31)
════════════════════════════════════════════════════════════════════════════════
NotesListView ::
import 'package:flutter/material.dart';
import '/services/cloud/cloud_note.dart';
import '/utilities/dialogs/delete_dialog.dart';
/*
source: https://www.youtube.com/watch?v=VPvVD8t02U8&t=59608s
class creation :: 22:02:54
*/
typedef NoteCallback = void Function(CloudNote note);
class NotesListView extends StatelessWidget {
final Iterable<CloudNote> notes; // list of notes
final NoteCallback onDeleteNote;
final NoteCallback onTap;
const NotesListView({
Key? key,
required this.notes,
required this.onDeleteNote,
required this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: notes.length,
itemBuilder: (context, index) {
final note =
notes.elementAt(index); // current note whose data we are returning
return ListTile(
onTap: () {
onTap(note);
},
title: Text(
note.jobDescription,
maxLines: 1,
softWrap: true,
overflow: TextOverflow.ellipsis,
),
trailing: IconButton(
onPressed: () async {
final shouldDelete = await showDeleteDialog(context);
if (shouldDelete) {
onDeleteNote(note);
}
},
icon: const Icon(Icons.delete),
),
);
},
);
}
}
This happens if you forget to update your Firestore entries. Atleast one of your CloudNote entries in Firestore does not have the field jobState. That's why Firestore returns a Null value. But it tries to map to String which leads to an exception.
Make sure to rerun the project.
or
flutter clean
and then
flutter run
i want to go back to my previous page, first i tried Navigator.pop(context); but it returns a black screen. Second try was with this code which i use it to another screen works fine there but here it return this error: Null check operator on a null value
Second try was with this code which i use it to another screen works fine there but here it return this error: Null check operator on a null value
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ShowSessionsPage(widget.appController)),
);
full code:
import 'ShowSessionsPage.dart';
import 'event.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import '../../Panels/SessionOrBookingPanel.dart';
import '../../Controllers/AppController.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Calendar extends StatelessWidget {
late AppController appController;
Calendar(appController){
this.appController = appController;
} // This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Calendar',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(appController),
);
}
}
class MyHomePage extends StatefulWidget {
late AppController appController;
MyHomePage(appController){
this.appController = appController;
}
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
late final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DateRangePickerController _datePickerController = DateRangePickerController();
#override
Widget build(BuildContext context) {
print(widget.appController.list);
return Scaffold(
appBar: AppBar(
leading: IconButton(
color: widget.appController.themeController.appBlackDeepColor,
tooltip: 'Back',
alignment: Alignment.centerLeft,
icon: (widget.appController.deviceIsAndroid) ? const Icon(Icons.arrow_back) : const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ShowSessionsPage(widget.appController)),
);
},
),
),
body: SfDateRangePicker(
view: DateRangePickerView.month,
monthViewSettings: DateRangePickerMonthViewSettings(firstDayOfWeek: 6,
specialDates:widget.appController.specialDates),
monthCellStyle: DateRangePickerMonthCellStyle(
specialDatesDecoration: BoxDecoration(
color: Colors.green,
border: Border.all(color: const Color(0xFF2B732F), width: 1),
shape: BoxShape.circle),
blackoutDateTextStyle: TextStyle(color: Colors.white, decoration: TextDecoration.lineThrough),
specialDatesTextStyle: const TextStyle(color: Colors.white),
),
selectionMode: DateRangePickerSelectionMode.multiple,
onSelectionChanged: _onSelectionChanged,
controller: _datePickerController,
onCancel: () {
_datePickerController.selectedRanges = null;
},
),
);
}
void _onSelectionChanged(
DateRangePickerSelectionChangedArgs dateRangePickerSelectionChangedArgs) {
print(dateRangePickerSelectionChangedArgs.value);
}
}
Error console:
======== Exception caught by widgets library =======================================================
The following _CastError was thrown building ShowSessionsPage(dirty, dependencies: [_LocalizationsScope-[GlobalKey#0c696]], state: _ShowSessionsPageState#fbc3f):
Null check operator used on a null value
The relevant error-causing widget was:
ShowSessionsPage ShowSessionsPage:file:///C:/Users/birbi/Desktop/electromobility_flutter_application/lib/Account/Sessions/Calendar.dart:72:63
When the exception was thrown, this was the stack:
#0 _ShowSessionsPageState.build (package:electromobility_flutter_application/Account/Sessions/ShowSessionsPage.dart:60:49)
#1 StatefulElement.build (package:flutter/src/widgets/framework.dart:4870:27)
#2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4754:15)
#3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4928:11)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#5 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)
#6 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#7 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)
#8 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
#9 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1081:9)
#10 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:995:5)
#14 _invoke (dart:ui/hooks.dart:151:10)
#15 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)
#16 _drawFrame (dart:ui/hooks.dart:115:31)
(elided 3 frames from dart:async)
====================================================================================================
showSessions code:
class ShowSessionsPage extends StatefulWidget {
late final AppController appController;
ShowSessionsPage(appController) {
this.appController = appController;
}
_ShowSessionsPageState createState() => _ShowSessionsPageState();
}
class _ShowSessionsPageState extends State<ShowSessionsPage>{
List<SessionOrBookingPanel> sessionPanels = [];
bool sessionsLoaded = false;
#override
void initState() {
super.initState();
loadSessions();
}
void loadSessions() async {
if (await widget.appController.fetchChargeTransactions())
setState(() {
sessionsLoaded = true;
});
}
void createSessionPanels(List<dynamic> sessions) {
int i = 0;
sessionPanels.clear();
if (sessions.length != 0){
while (i < sessions.length){
sessionPanels.add(new SessionOrBookingPanel(sessions[i], widget.appController, true, true));
i++;
}
}
}
Widget build(BuildContext context) {
createSessionPanels(widget.appController.sessions);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
leading: IconButton(
color: widget.appController.themeController.appBlackDeepColor,
tooltip: 'Back',
alignment: Alignment.centerLeft,
icon: (widget.appController.deviceIsAndroid) ? const Icon(Icons.arrow_back) : const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.pop(context);
},
),
title: Text(AppLocalizations.of(context)!.sessions,
style: TextStyle(color: widget.appController.themeController.appBlackDeepColor),),
elevation: 0.0,
),
body: sessionsLoaded ?
Column(
children: [ ElevatedButton(child: Text('Open Callendar'),
onPressed: () => {Navigator.push(
context,
MaterialPageRoute(builder: (context) => new Calendar(widget.appController)),
)}),
Expanded(
flex: 15,
child: Container(
margin: EdgeInsets.only(top: 10.0, bottom: 10.0),
child: ListView.separated(
padding: EdgeInsets.only(left: 10.0, right: 10.0),
scrollDirection: Axis.vertical,
itemBuilder: (_, index) => sessionPanels[index],
separatorBuilder: (context, index) => Divider(color: Colors.transparent,),
itemCount: sessionPanels.length),
),
),
],
)
:
Center(
child: CircularProgressIndicator(),
),
);
}
}
Add this to your MaterialApp. The error happens because of the null operator (!) in Text(AppLocalizations.of(context)!.sessions,. Because there is no AppLocalizations in the context it throws an error as it returns null.
MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
...
I am new in flutter .I am tried googling but I cant fix my problem. I used "MultiBlocProvider" for manage stats . I want change dark mode state like bellow.
ThemeCubit.dart
part 'theme_state.dart';
class ThemeCubit extends HydratedCubit<ThemeState> {
ThemeCubit() : super(ThemeState(AppThemes.lightTheme));
void getTheme(ThemeState state) {
emit(state);
}
#override
ThemeState? fromJson(Map<String, dynamic> json) {
return json['isDark'] as bool
? ThemeState(AppThemes.darkTheme)
: ThemeState(AppThemes.lightTheme);
}
#override
Map<String, bool>? toJson(ThemeState state) {
return {'isDark': state.themeData.brightness == Brightness.dark};
}
}
ThemeState.dart
part of 'theme_cubit.dart';
#immutable
class ThemeState extends Equatable {
final ThemeData themeData;
const ThemeState(this.themeData);
#override
List<Object?> get props => [themeData];
}
main.dart
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
lazy: true,
create: (context) => ThemeCubit(),
),
],
child:BlocBuilder<ThemeCubit, ThemeState>(
builder: (context,state) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Production Boilerplate',
theme: state.themeData, //ThemeMode.dark,
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
},
),
);
}
}
settingScreen.dart
Positioned(
top: 60 - widget.offset / 2,
left: 20,
child: Builder(builder: (context) {
return Switch(
value:newValue ,
onChanged: (value) {
BlocProvider.of<ThemeCubit>(context).getTheme(ThemeState(
newValue ? AppThemes.darkTheme : AppThemes.lightTheme));
});
})
),
This code works properly when used "BlocProvider" . But when I used "MultiBlocProvider", I get bellow error.
The following assertion was thrown attaching to the render tree:
'package:flutter/src/widgets/framework.dart': Failed assertion: line
4357 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
Either the assertion indicates an error in the framework itself, or we
should provide substantially more information in this error message to
help you determine and fix the underlying cause. In either case,
please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
When the exception was thrown, this was the stack:
#2 Element.rebuild. (package:flutter/src/widgets/framework.dart:4357:14)
#3 Element.rebuild (package:flutter/src/widgets/framework.dart:4360:6)
#4 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4643:5)
#5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4638:5)
#6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#7 Element.updateChild (package:flutter/src/widgets/framework.dart:3425:18)
#8 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#9 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#10 RenderObjectToWidgetAdapter.attachToRenderTree. (package:flutter/src/widgets/binding.dart:1112:18)
#11 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2573:19)
#12 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#13 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#14 WidgetsBinding.scheduleAttachRootWidget. (package:flutter/src/widgets/binding.dart:924:7) (elided 13 frames
from class _AssertionError, class _RawReceivePortImpl, class _Timer,
dart:async, and dart:async-patch)
How can I fix it?
I added bellow code to ThemeCubit.dart :
bool isDarkMode = false;
ThemeMode currentTheme(){
isDarkMode?_setTheme(ThemeMode.dark) : _setTheme(ThemeMode.light);
return isDarkMode?ThemeMode.dark : ThemeMode.light;
}
void updateTheme(bool isDarkMode) {
this.isDarkMode = isDarkMode;
}
and change main.dart :
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => ThemeCubit(),
),
],
child:ElderlyApp(),
);
}
class ElderlyApp extends StatefulWidget {
const ElderlyApp({Key? key,}) : super(key: key);
#override
_ElderlyAppState createState() => _ElderlyAppState();
}
class _ElderlyAppState extends State<ElderlyApp> with WidgetsBindingObserver {
#override
void initState() {
WidgetsBinding.instance!.addObserver(this);
super.initState();
}
#override
void didChangePlatformBrightness() {
context.read<ThemeCubit>().currentTheme();
super.didChangePlatformBrightness();
}
#override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Production Boilerplate',
theme: AppThemes.lightTheme,
darkTheme: AppThemes.darkTheme,
themeMode: context.select(
(ThemeCubit cubit) => cubit.currentTheme()), //ThemeMode.dark,
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
and change code in seetingScreen.dart
Positioned(
top: 60 - widget.offset / 2,
left: 20,
child: Builder(builder: (context) {
bool isDark = context.select((ThemeCubit themeCubit) =>
themeCubit.state.themeMode) ==ThemeMode.dark ? true: false;
return Switch(
value: context.read<ThemeCubit>().isDarkMode,
onChanged: (value) {
context.read<ThemeCubit>().updateTheme(value);
});
})),
I am trying to capture a PNG image of a Flutter Widget for use in a MapBox instance. The code requires that I detect when the Build process has completed, and the rendered area is ready to paint. Here is my Widget:
typedef void ImageCreatedCallback(UI.Image image);
class POIWidget extends StatefulWidget {
const POIWidget({Key key, this.poi, this.imageCreatedCallback})
: super(key: key);
final POI poi;
final ImageCreatedCallback imageCreatedCallback;
#override
_POIWidgetState createState() => _POIWidgetState();
}
class _POIWidgetState extends State<POIWidget> {
/**
* The only purpose of this widget is to provide an Image version of itself
* that can then be used in the MapBox map.
*/
GlobalKey globalKey = GlobalKey();
Future<void> _capturePng() async {
RenderRepaintBoundary boundary =
globalKey.currentContext.findRenderObject() as RenderRepaintBoundary;
if (boundary == null) {
// print("Waiting for boundary to be painted.");
await Future.delayed(const Duration(milliseconds: 100));
return _capturePng();
}
MediaQueryData queryData = MediaQuery.of(context);
double devicePixelRatio = queryData.devicePixelRatio;
UI.Image image = await boundary.toImage(pixelRatio: devicePixelRatio);
widget.imageCreatedCallback(image);
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback(
(_) async {
await Future.delayed(const Duration(milliseconds: 100))
.then((_) => _capturePng());
},
);
}
#override
Widget build(BuildContext context) {
return RepaintBoundary(
key: globalKey,
child: ClipOval(
child: Material(
color: widget.poi.iconBackgroundColor,
child: SizedBox(
width: widget.poi.iconSize.size * 2,
height: widget.poi.iconSize.size * 2,
child: widget.poi.iconName != null
? IconManager.instance.getIconFromName(
widget.poi.iconName,
size: widget.poi.iconSize.size,
color: widget.poi.iconColor,
)
: IconManager.instance.iconMapPin,
),
),
),
);
}
}
You'll notice that the _capturePNG method has this line:
RenderRepaintBoundary boundary =
globalKey.currentContext.findRenderObject() as RenderRepaintBoundary;
and then immediately afterwards I am testing to see if this is null. I think this is being ignored as it is not null but something else. It is, however, not what I need to create the image later on in the method.
I get this error message from this code:
[ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: Null check operator used on a null value
E/flutter (21697): #0 RenderRepaintBoundary.toImage (package:flutter/src/rendering/proxy_box.dart:3089)
E/flutter (21697): #1 _POIWidgetState._capturePng (package:screens/map/widgets/POIWidget.dart:38)
E/flutter (21697): #2 _POIWidgetState.initState.<anonymous closure>.<anonymous closure> (package:screens/map/widgets/POIWidget.dart:48)
E/flutter (21697): #3 _rootRunUnary (dart:async/zone.dart:1362)
E/flutter (21697): #4 _CustomZone.runUnary (dart:async/zone.dart:1265)
E/flutter (21697): <asynchronous suspension>
E/flutter (21697): #5 _POIWidgetState.initState.<anonymous closure> (package:screens/map/widgets/POIWidget.dart:47)
E/flutter (21697): <asynchronous suspension>
How can I be sure the widget is built and the RenderRepaintBoundary is ready to be captured?
instead of using RepaintBoundary with Future.delayed / WidgetsBinding.instance.addPostFrameCallback etc check how RepaintBoundary is implemented
after 5-10 minutes you could work out something like this:
class ImageGrab extends SingleChildRenderObjectWidget {
final Function(ByteData) onImageGrab;
ImageGrab({Key key, #required Widget child, #required this.onImageGrab}) : super(key: key, child: child);
#override
RenderImageGrab createRenderObject(BuildContext context) => RenderImageGrab(onImageGrab);
// TODO implement #override updateRenderObject ???
}
class RenderImageGrab extends RenderProxyBox {
final Function(ByteData) onImageGrab;
bool imageGrabbed;
RenderImageGrab(this.onImageGrab);
#override
bool get isRepaintBoundary => true;
#override
void paint(PaintingContext context, Offset offset) {
print('=========== paint $size ===========');
super.paint(context, offset);
imageGrabbed ??= grabImage();
}
bool grabImage() {
(layer as OffsetLayer)
.toImage(Offset.zero & size)
.then((image) => image.toByteData(format: ImageByteFormat.png))
.then(onImageGrab);
return true;
}
}
the sample usage is:
child: ImageGrab(
child: SomeWidgetToGrab(),
onImageGrab: (data) => print('png image length: ${data.lengthInBytes}'),
),
EDIT strange thing: i was testing this code with a relatively complex widget and it was working fine but with simple Container(color: Colors.red) it throws 'package:flutter/src/rendering/layer.dart': Failed assertion: line 497 pos 12: 'picture != null': is not true. exception, so the solution is to "futurize" grabImage method with:
bool grabImage() {
Future(_grabImage);
return true;
}
_grabImage() {
(layer as OffsetLayer)
.toImage(Offset.zero & size)
.then((image) => image.toByteData(format: ImageByteFormat.png))
.then(onImageGrab);
}
The issue is that the Widget needs to be visible and painted before you can grab an image, which is why the docs recommend you use a gesture event to initiate the image capture.
To solve my issue I used this library to detect visibility: https://pub.dev/packages/visibility_detector
Updated widget code:
import 'dart:async';
import 'dart:ui' as UI;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:visibility_detector/visibility_detector.dart';
import 'package:weald_ar_trails/model/POI.dart';
import 'package:weald_ar_trails/utils/managers/IconManager.dart';
typedef void ImageCreatedCallback(UI.Image image);
class POIWidget extends StatefulWidget {
const POIWidget({Key key, this.poi, this.imageCreatedCallback})
: super(key: key);
final POI poi;
final ImageCreatedCallback imageCreatedCallback;
#override
_POIWidgetState createState() => _POIWidgetState();
}
class _POIWidgetState extends State<POIWidget> {
/**
* The only purpose of this widget is to provide an Image version of itself
* that can then be used in the MapBox map.
*/
GlobalKey globalKey = GlobalKey();
Future<void> _capturePng() async {
await Future.delayed(const Duration(milliseconds: 100));
RenderRepaintBoundary boundary =
globalKey.currentContext.findRenderObject();
MediaQueryData queryData = MediaQuery.of(context);
double devicePixelRatio = queryData.devicePixelRatio;
UI.Image image = await boundary.toImage(pixelRatio: devicePixelRatio);
widget.imageCreatedCallback(image);
}
#override
Widget build(BuildContext context) {
return VisibilityDetector(
key: globalKey,
onVisibilityChanged: (visibilityInfo) {
var visiblePercentage = visibilityInfo.visibleFraction * 100;
debugPrint(
'Widget ${visibilityInfo.key} is ${visiblePercentage}% visible');
if (visiblePercentage == 100) {
_capturePng();
}
},
child: RepaintBoundary(
key: globalKey,
child: ClipOval(
child: Material(
color: widget.poi.iconBackgroundColor,
child: SizedBox(
width: widget.poi.iconSize.size * 2,
height: widget.poi.iconSize.size * 2,
child: widget.poi.iconName != null
? IconManager.instance.getIconFromName(
widget.poi.iconName,
size: widget.poi.iconSize.size,
color: widget.poi.iconColor,
)
: IconManager.instance.iconMapPin,
),
),
),
),
);
}
}
This works but I would recommend trying the answer above and extending SingleChildRenderObjectWidget as a more elegant solution that wouldn't rely on third-party packages.