I'm new here, I joined the server because I have an error that I can't decipher.
here is the error, when i click on the user i would like to chat with i should get to the chat page. But I have an error that displays "type 'NULL' is not a subtype of type 'bool'
Could you help me ?
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'MaShup',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: backgroundColor,
appBarTheme: const AppBarTheme(
color: appBarColor,
),
),
onGenerateRoute: (settings) => generateRoute(settings),
home: ref.watch(userDataAuthProvider).when(
data: (user) {
if (user == null) {
return const LandingScreen();
}
return const MobileLayoutScreen();
},
error: (err, trace) {
return ErrorScreen(
error: err.toString(),
);
},
loading: () => const Loader(),
),
);
}
}
Error 1 [![enter image description here][1]][1] Error 2
[![enter image description here][2]][2]
screen of emulator
[![enter image description here][3]][3]
I redid the chat page as well as the chat controller and the chat repository, but that doesn't change anything...
I searched on stackoverflow and found different things but nothing conclusive... can you help me?
Landing_screen
class LandingScreen extends StatelessWidget {
const LandingScreen({Key? key}) : super(key: key);
void navigateToLoginScreen(BuildContext context) {
Navigator.pushNamed(context, LoginScreen.routeName);
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 50),
Text(
'Welcome to MaShup',
style: TextStyle(
fontSize: 33,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: size.height / 9),
const Image(
image: AssetImage('assets/bg.png'),
height: 340,
width: 340,
color: tabColor,
),
SizedBox(height: size.height / 9),
const Padding(
padding: EdgeInsets.all(15.0),
child: Text(
'Read our Privacy Policy. Tap "Agree and continue" to accept the Terms of Service.',
style: TextStyle(color: greyColor),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 10),
SizedBox(
width: size.width * 0.75,
child: CustomButton(
text: 'AGREE AND CONTINUE',
onPressed: () => navigateToLoginScreen(context),
),
)
],
),
),
);
}
}
Mobile_layout_screen
class MobileLayoutScreen extends ConsumerStatefulWidget {
const MobileLayoutScreen({Key? key}) : super(key: key);
@override
ConsumerState<MobileLayoutScreen> createState() => _MobileLayoutScreenState();
}
class _MobileLayoutScreenState extends ConsumerState<MobileLayoutScreen>
with WidgetsBindingObserver, TickerProviderStateMixin {
late TabController tabBarController;
@override
void initState() {
super.initState();
tabBarController = TabController(length: 3, vsync: this);
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.resumed:
ref.read(authControllerProvider).setUserState(true);
break;
case AppLifecycleState.inactive:
case AppLifecycleState.detached:
case AppLifecycleState.paused:
ref.read(authControllerProvider).setUserState(false);
break;
}
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: appBarColor,
centerTitle: false,
title: const Text(
'MaShup',
style: TextStyle(
fontSize: 20,
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
actions: [
IconButton(
icon: const Icon(Icons.search, color: Colors.grey),
onPressed: () {},
),
PopupMenuButton(
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
itemBuilder: (context) => [
PopupMenuItem(
child: const Text(
'Create Group',
),
onTap: () => Future(
() => Navigator.pushNamed(
context, CreateGroupScreen.routeName),
),
)
],
),
],
bottom: TabBar(
controller: tabBarController,
indicatorColor: tabColor,
indicatorWeight: 4,
labelColor: tabColor,
unselectedLabelColor: Colors.grey,
labelStyle: const TextStyle(
fontWeight: FontWeight.bold,
),
tabs: const [
Tab(
text: 'CHATS',
),
Tab(
text: 'STATUS',
),
Tab(
text: 'CALLS',
),
],
),
),
body: TabBarView(
controller: tabBarController,
children: const [
ContactsList(),
//StatusContactsScreen(),
Text('Calls')
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
if (tabBarController.index == 0) {
Navigator.pushNamed(context, SelectContactsScreen.routeName);
} else {
File? pickedImage = await pickImageFromGallery(context);
if (pickedImage != null) {
/*Navigator.pushNamed(
context,
ConfirmStatusScreen.routeName,
arguments: pickedImage,
);*/
}
}
},
backgroundColor: tabColor,
child: const Icon(
Icons.comment,
color: Colors.white,
),
),
),
);
}
}
Contact_list
class ContactsList extends ConsumerWidget {
const ContactsList({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.only(top: 10.0),
child: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<List<Group>>(
stream: ref.watch(chatControllerProvider).chatGroups(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Loader();
}
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
var groupData = snapshot.data![index];
return Column(
children: [
InkWell(
onTap: () {
Navigator.pushNamed(
context,
MobileChatScreen.routeName,
arguments: {
'name': groupData.name,
'uid': groupData.groupId,
'isGroupChat': true,
'profilePic': groupData.groupPic,
},
);
},
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: ListTile(
title: Text(
groupData.name,
style: const TextStyle(
fontSize: 18,
),
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: Text(
groupData.lastMessage,
style: const TextStyle(fontSize: 15),
),
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
groupData.groupPic,
),
radius: 30,
),
trailing: Text(
DateFormat.Hm().format(groupData.timeSent),
style: const TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
),
),
),
const Divider(color: dividerColor, indent: 85),
],
);
},
);
}),
StreamBuilder<List<ChatContact>>(
stream: ref.watch(chatControllerProvider).chatContacts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Loader();
}
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
var chatContactData = snapshot.data![index];
return Column(
children: [
InkWell(
onTap: () {
Navigator.pushNamed(
context,
MobileChatScreen.routeName,
arguments: {
'name': chatContactData.name,
'uid': chatContactData.contactId,
'isGroupChat': false,
'profilePic': chatContactData.profilePic,
},
);
},
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: ListTile(
title: Text(
chatContactData.name,
style: const TextStyle(
fontSize: 18,
),
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: Text(
chatContactData.lastMessage,
style: const TextStyle(fontSize: 15),
),
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
chatContactData.profilePic,
),
radius: 30,
),
trailing: Text(
DateFormat.Hm()
.format(chatContactData.timeSent),
style: const TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
),
),
),
const Divider(color: dividerColor, indent: 85),
],
);
},
);
}),
],
),
),
);
}
}
select_contact_screen
final selectContactsRepositoryProvider = Provider(
(ref) => SelectContactRepository(
firestore: FirebaseFirestore.instance,
),
);
class SelectContactRepository {
final FirebaseFirestore firestore;
SelectContactRepository({
required this.firestore,
});
Future<List<Contact>> getContacts() async {
List<Contact> contacts = [];
try {
if (await FlutterContacts.requestPermission()) {
contacts = await FlutterContacts.getContacts(withProperties: true);
}
} catch (e) {
debugPrint(e.toString());
}
return contacts;
}
void selectContact(Contact selectedContact, BuildContext context) async {
try {
var userCollection = await firestore.collection('users').get();
bool isFound = false;
for (var document in userCollection.docs) {
var userData = UserModel.fromMap(document.data());
String selectedPhoneNum = selectedContact.phones[0].number.replaceAll(
' ',
'',
);
if (selectedPhoneNum == userData.phoneNumber) {
isFound = true;
Navigator.pushNamed(
context,
MobileChatScreen.routeName,
arguments: {
'name': userData.name,
'uid': userData.uid,
},
);
}
}
if (!isFound) {
showSnackBar(
context: context,
content: 'This number does not exist on this app.',
);
}
} catch (e) {
showSnackBar(context: context, content: e.toString());
}
}
}
I added select contact screen because it is from there that it shows me an error.
router.dart
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case LoginScreen.routeName:
return MaterialPageRoute(
builder: (context) => const LoginScreen(),
);
case OTPScreen.routeName:
final verificationId = settings.arguments as String;
return MaterialPageRoute(
builder: (context) => OTPScreen(
verificationId: verificationId,
),
);
case UserInformationScreen.routeName:
return MaterialPageRoute(
builder: (context) => const UserInformationScreen(),
);
case SelectContactsScreen.routeName:
return MaterialPageRoute(
builder: (context) => const SelectContactsScreen(),
);
case MobileChatScreen.routeName:
final arguments = settings.arguments as Map<String, dynamic>;
final name = arguments['name'];
final uid = arguments['uid'];
final isGroupChat = arguments['isGroupChat'];
final profilePic = arguments['profilePic'];
return MaterialPageRoute(
builder: (context) => MobileChatScreen(
name: name,
uid: uid,
isGroupChat: isGroupChat,
profilePic: profilePic,
),
);
case ConfirmStatusScreen.routeName:
final file = settings.arguments as File;
return MaterialPageRoute(
builder: (context) => ConfirmStatusScreen(
file: file,
),
);
case StatusScreen.routeName:
final status = settings.arguments as Status;
return MaterialPageRoute(
builder: (context) => StatusScreen(
status: status,
),
);
case CreateGroupScreen.routeName:
return MaterialPageRoute(
builder: (context) => const CreateGroupScreen(),
);
default:
return MaterialPageRoute(
builder: (context) => const Scaffold(
body: ErrorScreen(error: 'This page doesn\'t exist'),
),
);
}
select_contact_group
final selectedGroupContacts = StateProvider<List<Contact>>((ref) => []);
class SelectContactsGroup extends ConsumerStatefulWidget {
const SelectContactsGroup({Key? key}) : super(key: key);
@override
ConsumerState<ConsumerStatefulWidget> createState() =>
_SelectContactsGroupState();
}
class _SelectContactsGroupState extends ConsumerState<SelectContactsGroup> {
List<int> selectedContactsIndex = [];
void selectContact(int index, Contact contact) {
if (selectedContactsIndex.contains(index)) {
selectedContactsIndex.removeAt(index);
} else {
selectedContactsIndex.add(index);
}
setState(() {});
ref
.read(selectedGroupContacts.state)
.update((state) => [...state, contact]);
}
@override
Widget build(BuildContext context) {
return ref.watch(getContactsProvider).when(
data: (contactList) => Expanded(
child: ListView.builder(
itemCount: contactList.length,
itemBuilder: (context, index) {
final contact = contactList[index];
return InkWell(
onTap: () => selectContact(index, contact),
child: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text(
contact.displayName,
style: const TextStyle(
fontSize: 18,
),
),
leading: selectedContactsIndex.contains(index)
? IconButton(
onPressed: () {},
icon: const Icon(Icons.done),
)
: null,
),
),
);
}),
),
error: (err, trace) => ErrorScreen(
error: err.toString(),
),
loading: () => const Loader(),
);
}
}
CodePudding user response:
For the 1st error message, you need to have the same number of children on TabBar and TabBarView. Add another widget.
body: TabBarView(
controller: tabBarController,
children: const [
ContactsList(),
StatusContactsScreen(), //just unncomment it
Text('Calls')
],
),
For the second error, it can be inside ContactsList
I am not sure