Unhandled Exception: type 'Null' is not a subtype of type 'String' in type cast flutter - flutter

I'm trying to make a simple messaging application while using firebase and flutter, everything was working fine until I came to the message screen, but on this screen, I get the error that I will specify below. Do you know the solution for this?
Unhandled Exception: type 'Null' is not a subtype of type 'String' in type cast
I could not understand where I got the error, when I click on any user on the page where I listed the users, it gives this error directly.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_chat_bubble/bubble_type.dart';
import 'package:flutter_chat_bubble/chat_bubble.dart';
import 'package:flutter_chat_bubble/clippers/chat_bubble_clipper_6.dart';
import 'package:ourchat/pallete.dart';
import 'package:ourchat/shared/utils.dart';
class ChatDetailPage extends StatefulWidget {
final String user;
const ChatDetailPage({
Key? key,
required this.user,
}) : super(key: key);
#override
_ChatDetailPageState createState() => _ChatDetailPageState();
}
class _ChatDetailPageState extends State<ChatDetailPage> {
TextEditingController messageController = TextEditingController();
final currentUserId = FirebaseAuth.instance.currentUser?.uid;
CollectionReference chats = FirebaseFirestore.instance.collection('chats');
var chatDocId;
var userData = {};
bool isLoading = false;
#override
void initState() {
super.initState();
getData();
checkUser();
}
void checkUser() async {
await chats
.where('users', isEqualTo: {userData['uid']: null, currentUserId: null})
.limit(1)
.get()
.then(
(QuerySnapshot querySnapshot) async {
if (querySnapshot.docs.isNotEmpty) {
setState(() {
chatDocId = querySnapshot.docs.single.id;
});
print(chatDocId);
} else {
await chats.add({
'users': {currentUserId: null, widget.user: null},
'names': {
currentUserId: FirebaseAuth.instance.currentUser?.displayName,
userData['uid']: userData['username']
}
}).then((value) => {chatDocId = value});
}
},
)
.catchError((error) {});
}
getData() async {
setState(() {
isLoading = true;
});
try {
var userSnap = await FirebaseFirestore.instance
.collection('users')
.doc(widget.user)
.get();
userData = userSnap.data()!;
print(userData);
setState(() {});
} catch (e) {
showSnackBar(
context,
e.toString(),
);
}
setState(() {
isLoading = false;
});
}
void sendMessage(String msg) {
if (msg == '') return;
chats.doc(chatDocId).collection('messages').add({
'createdOn': FieldValue.serverTimestamp(),
'uid': currentUserId,
'friendName': userData['username'],
'msg': msg
}).then((value) {
messageController.text = '';
});
}
bool isSender(String friend) {
return friend == currentUserId;
}
Alignment getAlignment(friend) {
if (friend == currentUserId) {
return Alignment.topRight;
}
return Alignment.topLeft;
}
#override
Widget build(BuildContext context) {
return isLoading
? const Center(
child: CircularProgressIndicator(),
)
: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('users')
.doc(chatDocId)
.collection('messages')
.orderBy('createdOn', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text("Bir şeyler yanlış gitti..."),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(
color: kBlue,
),
);
}
if (snapshot.hasData) {
var data;
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
elevation: 0,
automaticallyImplyLeading: false,
backgroundColor: Colors.black,
flexibleSpace: SafeArea(
child: Container(
padding: EdgeInsets.only(right: 16),
child: Row(
children: <Widget>[
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: ImageIcon(
AssetImage("assets/icons/backicon.png"),
color: Colors.white,
),
),
SizedBox(
width: 2,
),
CircleAvatar(
backgroundImage:
NetworkImage(userData['photoUrl'].toString()),
maxRadius: 20,
),
SizedBox(
width: 12,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
userData['username'].toString(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white),
),
SizedBox(
height: 6,
),
Text(
userData['bio'].toString(),
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 13,
),
),
],
),
),
Icon(
Icons.settings,
color: Colors.white,
),
],
),
),
),
),
body: Stack(
children: <Widget>[
ListView(
reverse: true,
children: snapshot.data!.docs.map(
(DocumentSnapshot documentSnapshot) {
data = documentSnapshot.data()!;
print(documentSnapshot.toString());
print(data['msg']);
return Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: ChatBubble(
clipper: ChatBubbleClipper6(
nipSize: 0,
radius: 0,
type: isSender(data['uid'].toString())
? BubbleType.sendBubble
: BubbleType.receiverBubble,
),
alignment: getAlignment(data['uid'].toString()),
margin: EdgeInsets.only(top: 20),
backGroundColor:
isSender(data['uid'].toString())
? Color(0xFF08C187)
: Color(0xffE7E7ED),
child: Container(
constraints: BoxConstraints(
maxWidth:
MediaQuery.of(context).size.width * 0.7,
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Text(data['msg'],
style: TextStyle(
color: isSender(data['uid']
.toString())
? Colors.white
: Colors.black),
maxLines: 100,
overflow: TextOverflow.ellipsis)
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Text(
data['createdOn'] == null
? DateTime.now().toString()
: data['createdOn']
.toDate()
.toString(),
style: TextStyle(
fontSize: 10,
color: isSender(
data['uid'].toString())
? Colors.white
: Colors.black),
)
],
)
],
),
),
),
);
},
).toList(),
),
Align(
alignment: Alignment.bottomLeft,
child: Container(
padding:
EdgeInsets.only(left: 10, bottom: 10, top: 10),
height: 60,
width: double.infinity,
color: Colors.black,
child: Row(
children: <Widget>[
GestureDetector(
onTap: () {},
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
color: kBlue,
borderRadius: BorderRadius.circular(30),
),
child: Icon(
Icons.add,
color: Colors.white,
size: 26,
),
),
),
SizedBox(
width: 15,
),
Expanded(
child: TextField(
controller: messageController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Lütfen mesaj yazınız.",
labelStyle:
TextStyle(color: Colors.white),
hintStyle: TextStyle(color: Colors.white),
border: InputBorder.none),
),
),
SizedBox(
width: 15,
),
GestureDetector(
onTap: () {
sendMessage(messageController.text);
},
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
color: kBlue,
borderRadius: BorderRadius.circular(30),
),
child: Icon(
Icons.send,
color: Colors.white,
size: 20,
),
),
),
],
),
),
),
],
),
);
}
return null!;
},
);
}
}

Related

Flutter - ScrollController was used after being disposed

class HomeScreen extends StatefulWidget {
final userName;
HomeScreen(this.userName);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
Future<ClientDashboardModel?>? _meterReadingResponse;
BatchSummaryModel? _batchResponse;
AMRDashboardModel? _amrDashboardResponse;
String _userName = '';
int? qcAssignedReads = 0;
int? qcMrCompleted = 0;
int? qcCompletedReads = 0;
int? qcPendingReads = 0;
int? qcApprovedReads = 0;
int? qcRejectedReads = 0;
bool isFirstTimeCalled = false;
Timer? _timer;
int _currentIndex = 0;
final pages = [
const MDMScreen(),
const AMRDashboard(whichScreen: 0),
const AMRDashboard(whichScreen: 1),
const AMRDashboard(whichScreen: 2)
];
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
setUpTimedFetch();
super.initState();
if (widget.userName != null) _userName = (widget.userName!);
}
#override
void dispose() {
isFirstTimeCalled = false;
_timer?.cancel();
super.dispose();
}
void setUpTimedFetch() {
if (!isFirstTimeCalled) {
_meterReadingResponse = _getDashboardData();
}
isFirstTimeCalled = true;
}
Future<ClientDashboardModel?> _getDashboardData() async {
ClientDashboardModel? meterReadingResponse;
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
var responseData = await Dashboard().getClientDashboard(token);
if (responseData.statusCode == 200) {
String data = responseData.body;
var decodedData = jsonDecode(data);
meterReadingResponse = null;
meterReadingResponse = ClientDashboardModel.fromJson(decodedData);
return meterReadingResponse;
}
return null;
}
void logout() async {
SharedPreferences.getInstance().then((value) {
value.remove('token');
value.remove('userName');
});
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) {
return const LoginScreen();
}));
}
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text(Strings.kLogoutLabel),
content: const Text(Strings.kConfirmLogout),
actions: <Widget>[
TextButton(
child: const Text(Strings.kCancelLabel),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text(Strings.kOKLabel),
onPressed: () {
Navigator.of(context).pop();
logout();
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
backgroundColor: const Color(0XFF116AFF),
unselectedItemColor: Colors.white,
selectedLabelStyle: const TextStyle(color: Colors.white),
showUnselectedLabels: false,
onTap: (value) {
setState(() => _currentIndex = value);
},
items: [
BottomNavigationBarItem(
label: 'MDM',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 0 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.electric_meter_outlined),
),
),
),
BottomNavigationBarItem(
label: 'Site Survey',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 1 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.location_city_outlined),
),
),
),
BottomNavigationBarItem(
label: 'Meter Replace',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 2 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.library_books_outlined),
),
),
),
BottomNavigationBarItem(
label: 'TroubleShoot',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 3 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.info_outline),
),
),
),
],
),
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text(Strings.kMRDLabel),
actions: [
IconButton(
onPressed: () {
_showMyDialog();
},
icon: const Icon(Icons.power_settings_new))
],
),
body: childView());
}
Widget childView() {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
Strings.kWelcome2Label,
style: TextStyle(
color: Colors.amber.shade700,
fontSize: 16.0,
fontWeight: FontWeight.w600),
),
Text(
_userName.toTitleCase(),
style: const TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.w400),
)
],
),
const Spacer(),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(color: Colors.grey.shade200),
child: SvgPicture.asset(
'images/profile.svg',
height: 54.0,
width: 54.0,
),
),
),
],
),
const SizedBox(
height: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [pages[_currentIndex]],
),
],
),
));
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:manager/components/dotted_line.dart';
import 'package:manager/model/lookup_cycle.dart';
import 'package:manager/model/mr_report_model.dart';
import 'package:manager/services/dashboard_service.dart';
import 'package:manager/utils/debouncer.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:manager/utils/string_captialize.dart';
class MRPerformance extends StatefulWidget {
const MRPerformance({super.key});
#override
State<MRPerformance> createState() => _MRPerformanceState();
}
bool isFilter = false;
bool isPerformingRequest = false;
int pageNumber = 0;
String _chosenValue = '';
List<MRReportResult> users = [];
Future<List<String>?>? dropDownValue;
ScrollController _scrollController = ScrollController();
final _debouncer = Debouncer(milliseconds: 500);
class _MRPerformanceState extends State<MRPerformance> {
#override
void initState() {
super.initState();
_getMoreData(_chosenValue);
dropDownValue = getAllCategory();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
_getMoreData(_chosenValue);
}
});
}
Future<List<String>?>? getAllCategory() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
var cycleResponse = await Dashboard().getAllCycle(token);
try {
if (cycleResponse.statusCode == 200) {
List<String> items = [];
var jsonData = json.decode(cycleResponse.body) as List;
List<LookUpCycle> lookupCycle = jsonData
.map<LookUpCycle>((json) => LookUpCycle.fromJson(json))
.toList();
items.add('Select');
for (var element in lookupCycle) {
if (element.name != null) {
items.add(element.name!);
}
}
return items;
}
} catch (ex) {
throw (ex.toString());
}
return null;
}
#override
void dispose() {
super.dispose();
_scrollController.dispose();
}
void _getMoreData(String searchCycle) async {
List<MRReportResult>? resultResponse = [];
if (!isPerformingRequest) {
setState(() {
isPerformingRequest = true;
});
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
debugPrint(token);
var responseData =
await Dashboard().getMRReport(token, pageNumber, 10, searchCycle);
if (responseData.statusCode == 200) {
String data = responseData.body;
var decodedData = jsonDecode(data);
MRReportModel newEntries = MRReportModel.fromJson(decodedData);
if (newEntries.result == null) {
if (newEntries.result!.isEmpty) {
double edge = 50.0;
double offsetFromBottom =
_scrollController.position.maxScrollExtent -
_scrollController.position.pixels;
if (offsetFromBottom < edge) {
_scrollController.animateTo(
_scrollController.offset - (edge - offsetFromBottom),
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut);
}
}
}
setState(() {
users.addAll(newEntries.result!);
isPerformingRequest = false;
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: const Text('MR Performance')),
body: filterView());
}
void setFilterState() {
setState(() {
if (isFilter == true) {
isFilter = false;
} else {
isFilter = true;
}
});
}
Widget _buildProgressIndicator() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Opacity(
opacity: isPerformingRequest ? 1.0 : 0.0,
child: const CircularProgressIndicator(),
),
),
);
}
Widget filterView() {
return Column(
children: [
Row(
children: [
Visibility(
visible: isFilter ? true : false,
child: Flexible(
child: Card(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
elevation: 2,
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
textInputAction: TextInputAction.search,
decoration: const InputDecoration(
border: InputBorder.none,
prefixIcon: InkWell(
child: Icon(Icons.search),
),
contentPadding: EdgeInsets.all(8.0),
hintText: 'Search ',
),
onChanged: (string) {
_debouncer.run(() {});
},
),
),
],
),
],
),
),
),
),
Visibility(
visible: isFilter ? false : true,
child: Flexible(
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.only(
left: 10,
),
child: FutureBuilder<List<String>?>(
future: dropDownValue,
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Something wrong');
} else if (snapshot.hasData) {
var data = snapshot.data!;
return DropdownButtonHideUnderline(
child: DropdownButton<String>(
icon: const Icon(
Icons.expand_more_outlined,
size: 35,
color: Color(0XFF116AFF),
),
borderRadius: BorderRadius.circular(10),
isExpanded: true,
// value: _chosenValue.isNotEmpty ? _chosenValue : null,
elevation: 16,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400),
items: data.map((String value) {
return DropdownMenuItem(
value: value, child: Text(value));
}).toList(),
hint: Padding(
padding: const EdgeInsets.all(15),
child: Text(
_chosenValue.isEmpty
? 'Cycle'
: _chosenValue,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w400),
),
),
onChanged: (String? value) {
setState(() {
if (value != null) {
pageNumber = 0;
users.clear();
if (value == 'Select') {
_chosenValue = '';
} else {
_chosenValue = value;
}
_getMoreData(_chosenValue);
}
});
},
),
);
}
}
return const CircularProgressIndicator();
},
)),
),
),
),
InkWell(
onTap: () => {setFilterState()},
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: isFilter
? const Icon(Icons.filter_alt, color: Color(0XFF116AFF))
: const Icon(
Icons.search,
color: Color(0XFF116AFF),
),
),
),
),
],
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: users.length + 1,
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
if (index == users.length) {
return _buildProgressIndicator();
} else {
return cardView(users, index);
}
}),
),
],
);
}
Widget cardView(List<MRReportResult>? users, int index) {
return Card(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
margin: const EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.orange,
),
borderRadius: const BorderRadius.all(Radius.circular(20))),
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(10),
child: Row(
children: [
Text(
'${users?[index].mRNumber}: ',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
Text(
'${users?[index].meterReaderName}'.toTitleCase(),
style: const TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.w400),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Row(
children: [
const Text(
'Supervisor: ',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 10,
fontWeight: FontWeight.w600),
),
Expanded(
child: Text(
'${users?[index].supervisor}'.toTitleCase(),
overflow: TextOverflow.fade,
style: const TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.w400),
),
),
],
),
),
const SizedBox(height: 10),
const MySeparator(),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Column(
children: [
Text(
'${users?[index].unreadPercenatge}%',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'Unread',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].readPercenatge}%',
style: const TextStyle(
color: Colors.green,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'Read',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].plusorMinusTwoReadPercentage}%',
style: const TextStyle(
color: Colors.green,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'+/- 2',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].above32ReadPercentage}%',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'>32',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
],
),
),
],
),
),
);
}
}
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Builder:
A ScrollController was used after being disposed.
Once you have called dispose() on a ScrollController, it can no longer be used.
The relevant error-causing widget was
MaterialApp
lib/main.dart:13
When the exception was thrown, this was the stack
You have declared _getMoreData two times in init(), so remove it before _scrollController as shown below
void initState() {
super.initState();
_getMoreData(_chosenValue);-------------> remove this from here
dropDownValue = getAllCategory();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
_getMoreData(_chosenValue);
}
});
}
OR
Declare ScrollController _scrollController = ScrollController(); in state class _MRPerformanceState as below code:
class _MRPerformanceState extends State<MRPerformance> {
ScrollController _scrollController = ScrollController();

only when use iphone simulator

I have this error:
The following FileSystemException was thrown resolving an image codec:
Cannot open file, path = '/Users/todo/Library/Developer/CoreSimulator/Devices/82205CEC-3D83-4A29-BF17-01C5B0515F71/data/Containers/Data/Application/035B9913-BEC5-46BA-84A5-8C1FE3C4E671/tmp/image_picker_B8D488A3-2790-4D53-A5D8-52E57E2C4108-76094-000003172DF085D2.jpg' (OS Error: No such file or directory, errno = 2)
When the exception was thrown, this was the stack
only when use iphone simulator while android emulator no problem
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../app/utility.dart';
import '../db/aql_db.dart';
import '../globals.dart';
import '../menu_page.dart';
import '../model/aql_model.dart';
import '../widget/input_text.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
var _current = resultsFld[0];
class AqlPg extends StatefulWidget {
const AqlPg({Key? key}) : super(key: key);
#override
State<AqlPg> createState() => _AqlPgState();
}
class _AqlPgState extends State<AqlPg> {
final List<TextEditingController> _criticalController = [];
final List<TextEditingController> _majorController = [];
final List<TextEditingController> _minorController = [];
final List<TextEditingController> _imgCommintControllers = [];
final _irController = TextEditingController();
bool clickedCentreFAB =
false; //boolean used to handle container animation which expands from the FAB
int selectedIndex =
0; //to handle which item is currently selected in the bottom app bar
//call this method on click of each bottom app bar item to update the screen
void updateTabSelection(int index, String buttonText) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
//
_irController.text = aqltbl.ir ?? '';
String _current = aqltbl.result ?? resultsFld[0];
//
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
//---- stack for FloatingActionButton
Stack(
children: <Widget>[
//this is the code for the widget container that comes from behind the floating action button (FAB)
Align(
alignment: FractionalOffset.bottomCenter,
child: AnimatedContainer(
child: const Text(
'Hello',
style: TextStyle(fontSize: 18, color: whiteColor),
),
duration: const Duration(milliseconds: 250),
//if clickedCentreFAB == true, the first parameter is used. If it's false, the second.
height: clickedCentreFAB
? MediaQuery.of(context).size.height
: 10.0,
width: clickedCentreFAB
? MediaQuery.of(context).size.height
: 10.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
clickedCentreFAB ? 0.0 : 300.0),
color: Colors.blue),
),
),
],
),
// --- Top Page Title
const SizedBox(
height: 50,
),
const Center(
child: Text(
'Aql page',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: medBlueColor),
),
),
Text(
'Shipment no:$shipmentId',
style: const TextStyle(color: medBlueColor),
),
//--- input container
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
height: 270,
width: 300,
margin: const EdgeInsets.only(top: 5),
child: ListView.builder(
itemCount: (aqltbl.aql ?? []).length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
//here
var _aqlList = aqltbl.aql![index];
//
if (aqltbl.aql!.length > _criticalController.length) {
_criticalController.add(TextEditingController());
_majorController.add(TextEditingController());
_minorController.add(TextEditingController());
}
//
_criticalController[index].text =
_aqlList.critical ?? '';
_majorController[index].text = _aqlList.major ?? '';
_minorController[index].text = _aqlList.minor ?? '';
//
return Column(
children: [
Container(
height: 260,
width: 200,
margin: const EdgeInsets.only(left: 10),
padding: const EdgeInsets.all(10),
// ignore: prefer_const_constructors
decoration: BoxDecoration(
color: lightBlue,
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Text(
(_aqlList.name ?? '').toString(),
style: const TextStyle(
color: medBlueColor,
fontSize: 13,
),
),
// ignore: prefer_const_constructors
MyInputField(
title: 'critical',
hint: 'write critical ',
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _criticalController[index],
onSubmit: (value) {
setState(() {
aqltbl.aql![index].critical = value;
_save();
});
},
),
MyInputField(
title: 'majority',
hint: 'write majority ',
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _majorController[index],
onSubmit: (value) {
setState(() {
aqltbl.aql![index].major = value;
_save();
});
},
),
MyInputField(
title: 'minority',
hint: 'write minority ',
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _minorController[index],
onSubmit: (value) {
setState(() {
aqltbl.aql![index].minor = value;
_save();
});
},
),
],
),
),
],
);
}),
),
Container(
height: 270,
width: 300,
margin: const EdgeInsets.only(right: 10, left: 20),
padding: const EdgeInsets.only(
left: 10, bottom: 3, right: 10, top: 5),
decoration: const BoxDecoration(
color: lightBlue,
),
child: Column(
children: [
const Text(
'Summery results',
style: TextStyle(color: medBlueColor),
),
Container(
margin: const EdgeInsets.only(top: 10, bottom: 5),
alignment: Alignment.centerLeft,
child: const Text(
'Results',
style: TextStyle(color: medBlueColor),
),
),
Container(
padding: const EdgeInsets.only(right: 5, left: 5),
decoration: BoxDecoration(
color: whiteColor,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: borderColor,
)),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
focusColor: whiteColor,
value: aqltbl.result,
hint: const Text('select result'),
isExpanded: true,
iconSize: 36,
icon: const Icon(Icons.arrow_drop_down),
items: resultsFld.map((res) {
return DropdownMenuItem<String>(
value: res,
child: Text(
res,
style: const TextStyle(
fontFamily: 'tajawal',
fontSize: 15,
color: medBlueColor),
),
);
}).toList(),
onChanged: (val) {
setState(() {
aqltbl.result = val;
});
_save();
},
),
),
),
// aqltbl.result = selRes;
MyInputField(
width: 300,
title: 'information remarks (ir)',
hint: '',
maxLines: 3,
borderColor: borderColor,
textColor: textColor,
hintColor: hintColor,
controller: _irController,
onSubmit: (value) {
aqltbl.ir = value;
_save();
},
),
],
),
),
],
),
),
//Images Container
Container(
height: 400,
padding: const EdgeInsets.all(0),
margin: const EdgeInsets.only(bottom: 10, left: 10),
decoration: const BoxDecoration(color: lightGrey),
child: (aqltbl.images ?? []).isEmpty
? Column(
children: [
Image.asset(
'images/empty-photo.jpg',
height: 300,
),
Container(
margin: const EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('Click'),
Text(
'Camera button',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(' to add new photo'),
],
)),
],
)
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: (aqltbl.images ?? []).length,
itemBuilder: (context, imgIndex) {
String? _image =
(aqltbl.images ?? [])[imgIndex].name.toString();
inspect('aql image file');
File(_image).exists() == true
? inspect('image exist')
: inspect('not exist: ' + _image);
inspect('_image: ' + _image);
if (aqltbl.images!.length >
_imgCommintControllers.length) {
_imgCommintControllers.add(TextEditingController());
}
_imgCommintControllers[imgIndex].text =
aqltbl.images![imgIndex].imgComment!;
inspect(_imgCommintControllers.length);
return Container(
margin: const EdgeInsets.only(left: 5),
height: 300,
child: Column(
children: [
Stack(
children: [
Image.file(
File(_image),
height: 300,
),
Container(
decoration: const BoxDecoration(
color: medBlueColor,
),
child: IconButton(
onPressed: () {
inspect('clear');
String imgName =
aqltbl.images![imgIndex].name ??
'';
aqltbl.images!.removeAt(imgIndex);
// aqltbl.images!.removeWhere(
// (item) => item.name == imgName);
_imgCommintControllers
.removeAt(imgIndex);
setState(() {});
},
color: whiteColor,
icon: const Icon(Icons.clear)),
)
],
),
MyInputField(
title: 'Write remarks about image',
hint: '',
controller: _imgCommintControllers[imgIndex],
onSubmit: (value) {
aqltbl.images![imgIndex].imgComment = value;
aqltbl.images![imgIndex].name = _image;
_save();
},
),
],
));
}),
),
],
),
),
// --- FloatingActionButton
floatingActionButtonLocation: FloatingActionButtonLocation
.centerDocked, //specify the location of the FAB
floatingActionButton: FloatingActionButton(
backgroundColor: medBlueColor,
onPressed: () {
inspect(aqltbl);
setState(() {
clickedCentreFAB =
!clickedCentreFAB; //to update the animated container
});
},
tooltip: "Centre FAB",
child: Container(
margin: const EdgeInsets.all(15.0),
child: const Icon(Icons.send),
),
elevation: 4.0,
),
// --- bottom action bar
bottomNavigationBar: BottomAppBar(
child: Container(
margin: const EdgeInsets.only(left: 12.0, right: 12.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
//to leave space in between the bottom app bar items and below the FAB
IconButton(
//update the bottom app bar view each time an item is clicked
onPressed: () {
// updateTabSelection(0, "Home");
Get.to(const MainMenu());
},
iconSize: 27.0,
icon: Image.asset(
'images/logo.png',
color: medBlueColor,
),
),
const SizedBox(
width: 50.0,
),
IconButton(
onPressed: () async {
// updateTabSelection(2, "Incoming");
await _takeImage('gallery');
},
iconSize: 27.0,
icon: const Icon(
Icons.image_outlined,
color: medBlueColor,
),
),
IconButton(
onPressed: () async {
// updateTabSelection(1, "Outgoing");
await _takeImage('camera');
},
iconSize: 27.0,
icon: const Icon(
Icons.camera_alt,
color: medBlueColor,
),
),
],
),
),
//to add a space between the FAB and BottomAppBar
shape: const CircularNotchedRectangle(),
//color of the BottomAppBar
color: Colors.white,
),
);
}
_save() {
inspect('submit');
saveAql(shipmentId, aqltbl);
box.write('aql'+shipmentId.toString(), aqltbl);
}
_takeImage(method) async {
String _imgPath = await imageFromDevice(method);
if (_imgPath != empty) {
ImagesModel imgMdl = ImagesModel();
imgMdl.name = _imgPath;
imgMdl.imgComment = '';
if (aqltbl.images != null) {
// _saveLocaly(close: 0);
setState(() {
aqltbl.images!.add(imgMdl);
_save();
});
}
}
}
Future _sendAqlToServer() async {
try {
var response = await http.post(urlSendProductPhoto, body: {
'aql': json.encode(aqltbl).toString(),
'id': shipmentId.toString(),
});
if (response.statusCode == 200) {
Get.snackbar('Success', 'Image successfully uploaded');
return response.body;
} else {
Get.snackbar('Fail', 'Image not uploaded');
inspect('Request failed with status: ${response.statusCode}.');
return 'empty';
}
} catch (socketException) {
Get.snackbar('warning', 'Image not uploaded');
return 'empty';
}
}
}
Try following the path that it is saying it cannot find in your computer, I had a similar issue, I tried opening an Iphone 12 instead of an Iphone 13 and it worked out the issue, my problem was I inadvertently deleted a few files I shouldn't have.

ListView.builder returns Null check operator used on a null value

I'm developing a job search app that scrapes data from Indeed using Python which is being sent back to my Flutter UI as JSON data. The JSON data is being received successfully, however, Im getting an error of Null check operator used on a null value. The error appears to be stemming from the _jobSearch widget.
The relevant error-causing widget was ListView lib/ui/home_page.dart:256
Exception caught by scheduler library
Null check operator used on a null value
Here is the code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_job_portal/theme/colors.dart';
import 'package:flutter_job_portal/theme/images.dart';
import 'package:flutter_job_portal/ui/bottom_menu_bar.dart';
import 'package:flutter_job_portal/ui/job_detail_page.dart';
String job = ""; //user's response will be assigned to this variable
String final_response = "";
final _formkey = GlobalKey<FormState>(); //key created to interact with the form
//function to validate and save user form
Future<void> _savingData() async {
final validation = _formkey.currentState.validate();
if (!validation) {
return;
}
_formkey.currentState.save();
}
Future<List<Job>> _getJobs() async {
final url = 'http://127.0.0.1:5000/job';
final response1 = await http.post(Uri.parse(url), body: json.encode({'job': job}));
final response2 = await http.get(Uri.parse(url));
final decoded = json.decode(response2.body);
List<Job> jobs = [];
for (var i in decoded) {
Job job = Job(i['Title'], i['Company'], i['Location'], i['Salary']);
jobs.add(job);
}
return jobs;
}
class Job {
final String title;
final String company;
final String location;
final String salary;
Job(this.title, this.company, this.location, this.salary);
}
class HomePage extends StatelessWidget {
const HomePage({Key key}) : super(key: key);
Widget _appBar(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Row(
children: [
CircleAvatar(
backgroundImage: AssetImage(Images.user1),
),
Spacer(),
IconButton(
icon: Icon(Icons.notifications_none_rounded),
onPressed: () {},
)
],
),
);
}
Widget _header(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 12),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Hello, Alex!",
style: TextStyle(
fontSize: 15,
color: KColors.subtitle,
fontWeight: FontWeight.w500,
)),
SizedBox(
height: 6,
),
Text("Swipe to find your future",
style: TextStyle(
fontSize: 20,
color: KColors.title,
fontWeight: FontWeight.bold)),
SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: Container(
height: 45,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: KColors.lightGrey,
borderRadius: BorderRadius.circular(10)),
child: Form(
key: _formkey,
child: TextFormField(
decoration: InputDecoration(
hintText: 'Search job title or keywords',
),
onSaved: (value) {
job =
value; //getting data from the user form and assigning it to job
},
),
),
),
),
SizedBox(
width: 16,
),
Container(
decoration: BoxDecoration(
color: KColors.primary,
borderRadius: BorderRadius.circular(10),
),
height: 40,
child: IconButton(
color: KColors.primary,
icon: Icon(Icons.search, color: Colors.white),
onPressed: () async {
_savingData();
_getJobs();
},
),
)
],
)
],
),
);
}
Widget _recommendedSection(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
margin: EdgeInsets.symmetric(vertical: 12),
height: 200,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Recommended",
style: TextStyle(fontWeight: FontWeight.bold, color: KColors.title),
),
SizedBox(height: 10),
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
_recommendedJob(context,
company: "Google",
img: Images.google,
title: "UX Designer",
sub: "\$45,000 Remote",
isActive: true),
_recommendedJob(context,
company: "DropBox",
img: Images.dropbox,
title: "Research Assist",
sub: "\$45,000 Remote",
isActive: false)
],
),
),
],
),
);
}
Widget _recommendedJob(
BuildContext context, {
String img,
String company,
String title,
String sub,
bool isActive = false,
}) {
return Padding(
padding: const EdgeInsets.only(right: 10),
child: GestureDetector(
onTap: () {
Navigator.push(context, JobDetailPage.getJobDetail());
},
child: AspectRatio(
aspectRatio: 1.3,
child: Container(
decoration: BoxDecoration(
color: isActive ? KColors.primary : Colors.white,
borderRadius: BorderRadius.circular(7),
),
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 40,
width: 40,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: isActive ? Colors.white : KColors.lightGrey,
borderRadius: BorderRadius.circular(7),
),
child: Image.asset(img),
),
SizedBox(height: 16),
Text(
company,
style: TextStyle(
fontSize: 12,
color: isActive ? Colors.white38 : KColors.subtitle,
),
),
SizedBox(height: 6),
Text(
title,
style: TextStyle(
fontSize: 14,
color: isActive ? Colors.white : KColors.title,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 6),
Text(
sub,
style: TextStyle(
fontSize: 12,
color: isActive ? Colors.white38 : KColors.subtitle,
),
),
],
),
),
),
),
);
}
Widget _jobSearch(BuildContext context) {
return new Container(
child: FutureBuilder(
future: _getJobs(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text('Loading...'),
));
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].location),
);
},
);
}
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: KColors.background,
bottomNavigationBar: BottomMenuBar(),
body: SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_appBar(context),
_header(context),
_recommendedSection(context),
_jobSearch(context)
],
),
),
),
),
);
}
}

Why is Flutter BloC UI not updating after app restart despite state change in observer?

I concede that there are many questions similar to mine, but I have not found a satisfactory answer from those questions. So I decided to make my own question specifying my problem. I have 3 BloCs in my program each with different purposes. They all share similar problems, as such I will ask on one of those BloCs with the hope that one solution will fix all of the BloCs.
The problem is this, if I just started the application and have logged in, the BloC will update the UI. If I have logged in, exited the app, and restarted it, the Bloc will not update the UI. The Bloc in question is called DetailpersonilBloc with 1 event called Detail and 2 states called DetailpersonilInitial and Loaded. At the event of Detail, the state Loaded should be emitted.
I called Detail at LoginPage and at GajiPage at initState. This works when I just opened the app, but does not work when I restart the app. I also have equatable thinking that it will help me but apparently it changes nothing.
Note: The "..." at the GajiPage is just some code that I believe is not necessary for reproduction.
DetailpersonilBloc
part 'detailpersonil_event.dart';
part 'detailpersonil_state.dart';
class DetailpersonilBloc
extends Bloc<DetailpersonilEvent, DetailpersonilState> {
DetailpersonilBloc() : super(const DetailpersonilInitial()) {
on<Detail>((event, emit) async {
SharedPreferences pref = await SharedPreferences.getInstance();
String name = pref.getString('nama');
String nrp = pref.getString('NRP');
String pangkat = pref.getString('pangkat');
String jabatan = pref.getString('jabatan');
String satker = pref.getString('satker');
String polda = pref.getString('polda');
String npwp = pref.getString('NPWP');
String rekening = pref.getString('rekening');
String bank = pref.getString('bank');
emit(Loaded(
name,
nrp,
pangkat,
jabatan,
satker,
polda,
npwp,
rekening,
bank,
));
});
}
}
DetailpersonilEvent
part of 'detailpersonil_bloc.dart';
#immutable
abstract class DetailpersonilEvent extends Equatable {}
class Detail extends DetailpersonilEvent {
#override
List<Object> get props => [];
}
DetailpersonilState
part of 'detailpersonil_bloc.dart';
#immutable
abstract class DetailpersonilState extends Equatable {
final String nama;
final String nrp;
final String pangkat;
final String jabatan;
final String satker;
final String polda;
final String npwp;
final String rekening;
final String bank;
const DetailpersonilState(
{this.nama,
this.nrp,
this.pangkat,
this.jabatan,
this.satker,
this.polda,
this.npwp,
this.rekening,
this.bank});
}
class DetailpersonilInitial extends DetailpersonilState {
const DetailpersonilInitial()
: super(
nama: 'Nama',
nrp: 'NRP',
pangkat: 'Pangkat',
jabatan: 'Jabatan',
satker: 'Satker',
polda: 'Polda',
npwp: 'NPWP',
rekening: 'No Rekening',
bank: 'Nama Bank',
);
#override
List<Object> get props =>
[nama, nrp, pangkat, jabatan, satker, polda, npwp, rekening, bank];
}
class Loaded extends DetailpersonilState {
const Loaded(
String nama,
String nrp,
String pangkat,
String jabatan,
String satker,
String polda,
String npwp,
String rekening,
String bank,
) : super(
nama: nama,
nrp: nrp,
pangkat: pangkat,
jabatan: jabatan,
satker: satker,
polda: polda,
npwp: npwp,
rekening: rekening,
bank: bank);
#override
List<Object> get props =>
[nama, nrp, pangkat, jabatan, satker, polda, npwp, rekening, bank];
}
LoginPage
class LoginPage extends StatefulWidget {
const LoginPage({Key key}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
double width = 0;
double height = 0;
TextEditingController nrpController = TextEditingController();
TextEditingController sandiController = TextEditingController();
final formKey = GlobalKey<FormState>();
DetailpersonilBloc detailPersonilBloc;
GajiBloc gajiBloc;
TunkinBloc tunkinBloc;
bool passwordVisible = false;
#override
void initState() {
super.initState();
checkToken();
}
void checkToken() async {
SharedPreferences pref = await SharedPreferences.getInstance();
if (pref.getString('token') != null) {
detailPersonilBloc = DetailpersonilBloc();
gajiBloc = GajiBloc();
tunkinBloc = TunkinBloc();
detailPersonilBloc.add(Detail());
gajiBloc.add(Gaji());
tunkinBloc.add(Tunkin());
Navigator.push(
context, MaterialPageRoute(builder: (context) => const MainPage()));
}
}
onLogin(DetailpersonilBloc detailPersonilBloc) async {
if (formKey.currentState.validate()) {
var token = await APIService.generateToken(
nrpController.text, sandiController.text);
if (token != null) {
SharedPreferences pref = await SharedPreferences.getInstance();
await pref.setString('token', token.token);
var detail = await APIService.getDetailPersonil(token.token);
await pref.setString('nama', detail.nMPEG);
await pref.setString('NRP', detail.nRP);
await pref.setString('pangkat', detail.nMGOL1);
await pref.setString('jabatan', detail.sEBUTJAB);
await pref.setString('satker', detail.nMSATKER);
await pref.setString('polda', detail.nMUAPPAW);
await pref.setString('NPWP', detail.nPWP);
await pref.setString('rekening', detail.rEKENING);
await pref.setString('bank', detail.nMBANK);
nrpController.clear();
sandiController.clear();
detailPersonilBloc.add(Detail());
Navigator.push(
context, MaterialPageRoute(builder: (context) => const MainPage()));
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Error'),
content: Text('Login Gagal'),
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Tutup'),
),
],
);
},
);
}
}
}
#override
Widget build(BuildContext context) {
var detailPersonilBloc = BlocProvider.of<DetailpersonilBloc>(context);
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Scaffold(
body: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: const [
Opacity(
opacity: 0.5,
child: Image(
image: AssetImage('images/bg-map-min.png'),
),
),
],
),
SingleChildScrollView(
padding: EdgeInsets.only(top: 100),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 100,
width: width,
child: const Image(
image: AssetImage('images/login-logo.png'),
alignment: Alignment.center,
),
),
Container(
padding: const EdgeInsets.all(15),
child: const Text(
'GAJI DAN TUNKIN',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
Form(
key: formKey,
child: Column(
children: [
Container(
margin: const EdgeInsets.all(20 - 2.6),
child: Card(
elevation: 10,
child: Container(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Container(
alignment: Alignment.topLeft,
padding: const EdgeInsets.only(bottom: 20),
child: const Text(
'LOGIN',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
Container(
padding: const EdgeInsets.only(bottom: 25),
child: TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Masukkan NRP/NIP';
}
return null;
},
controller: nrpController,
decoration: InputDecoration(
labelText: 'NRP/NIP',
hintText: 'Masukkan NRP/NIP',
prefixIcon: Icon(Icons.person,
color: Colors.blue.shade700),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
),
TextFormField(
obscureText: !passwordVisible,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Masukkan Kata Sandi';
}
return null;
},
controller: sandiController,
decoration: InputDecoration(
labelText: 'Kata Sandi',
hintText: 'Masukkan Kata Sandi',
prefixIcon: Icon(Icons.lock,
color: Colors.blue.shade700),
suffixIcon: IconButton(
onPressed: () {
setState(() {
passwordVisible = !passwordVisible;
});
},
icon: Icon(
passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Colors.blue.shade700,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
)
],
),
),
),
),
ElevatedButton(
onPressed: () async {
await onLogin(detailPersonilBloc);
},
child: const Text('LOGIN'),
style: ElevatedButton.styleFrom(
primary: Colors.blue.shade700,
minimumSize: const Size(200, 40),
),
)
],
),
),
],
),
),
],
),
);
}
}
GajiPage
class GajiPage extends StatefulWidget {
const GajiPage({Key key}) : super(key: key);
#override
_GajiPageState createState() => _GajiPageState();
}
class _GajiPageState extends State<GajiPage> {
double width = 0;
double height = 0;
var currentYear = DateTime.now().year;
var currentMonth = DateTime.now().month;
DetailpersonilBloc detailPersonilBloc;
GajiBloc gajiBloc;
#override
void initState() {
setState(() {
detailPersonilBloc = DetailpersonilBloc();
detailPersonilBloc.add(Detail());
setMonth();
setYear();
gajiBloc = GajiBloc();
gajiBloc.add(Gaji());
});
super.initState();
}
#override
Widget build(BuildContext context) {
var detailPersonilBloc = BlocProvider.of<DetailpersonilBloc>(context);
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Image(
image: const AssetImage('images/header-logo.png'),
width: width / 2,
),
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromARGB(255, 170, 177, 175),
Color.fromARGB(255, 197, 217, 212)
],
),
),
),
),
body: Stack(
children: [
BlocBuilder<GajiBloc, GajiState>(
builder: (context, state) {
return state is GajiLoaded
? ListView(
children: [
Container(
height: 100,
),
Card(
color: const Color.fromARGB(255, 74, 50, 152),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: const Text(
'Gaji Bersih',
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
),
Container(
margin: const EdgeInsets.all(10),
child: Text(
NumberFormat.currency(
locale: 'en',
symbol: 'RP ',
decimalDigits: 0)
.format(state.bersih),
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 40,
color: Colors.white,
),
),
),
],
),
),
Card(
child: Column(
children: [
Container(
color: const Color.fromARGB(255, 238, 238, 238),
width: width,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Container(
margin: const EdgeInsets.fromLTRB(
10, 10, 0, 10),
width: (width / 2) - 25,
child: const Text(
'Detail Gaji',
textAlign: TextAlign.start,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
),
Container(
margin: const EdgeInsets.fromLTRB(
5, 10, 20, 10),
width: (width / 2) - 18,
child: Text(
'${state.bulan} - ${state.tahun}',
textAlign: TextAlign.end,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
)
],
),
),
...
],
),
),
Container(
height: 50,
),
],
)
: Center(
child: Text(
'Tidak ada data. Data gaji bulan ${state.bulan} belum diproses'),
);
},
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Center(
child: BlocBuilder<DetailpersonilBloc, DetailpersonilState>(
builder: (context, state) {
return Card(
child: Row(
children: [
Container(
margin: const EdgeInsets.all(10),
child: const CircleAvatar(
backgroundImage: AssetImage('images/Profpic.PNG'),
radius: 30,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 250,
padding: const EdgeInsets.all(5),
child: Text(
state.nama,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
)),
Container(
padding: const EdgeInsets.all(5),
child: Text(
state.nrp,
style: const TextStyle(fontSize: 15),
)),
],
),
GestureDetector(
onTap: () {
detailPersonilBloc.add(Detail());
showModalBottomSheet(
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (context) => detailsBottomSheet(),
);
},
child: const Text(
'DETAILS',
style: TextStyle(color: Colors.blue),
),
)
],
),
);
},
),
),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, StateSetter setState) {
return filterBottomSheet();
},
);
},
);
},
child: Container(
height: 50,
width: width,
decoration: const BoxDecoration(
color: Color.fromARGB(255, 244, 244, 244),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.only(right: 3),
child: const Icon(
Icons.tune,
color: Color.fromARGB(255, 45, 165, 217),
),
),
const Text(
'Filter',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
color: Color.fromARGB(255, 45, 165, 217),
),
),
],
),
),
)
],
)
],
),
);
}
}
Note 2: The "..." is a bunch of code not needed for reproduction.
The answer is surprisingly simple as I would learn from my internship. The reason the Bloc is not updating is because I was not using the context of the application. So when I generated a new Bloc inside my pages, it was "empty". So the solution is to use context.read().add(BlocEvent()) or create a new bloc with BlocProvider.of(context) then add the event. Basically the bloc has to be provided with the original context of the application.

Tab Bar in Flutter

I want to implement Tab Bar in my application having length 2 named "Need Help" and "Help Requests". In "Need Help" tab, I want my first container (i.e. Upload data to Firestore Database) and in "Help Requests" tab, I want my second container (i.e. Retrieve data from Firestore Database). I am new to flutter and will be very much grateful to you if you can help me.
Source code:
import 'package:chat_app/group_chats/group_info.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../constants.dart';
import '../global_data.dart';
class FinancialRoom extends StatelessWidget {
final String groupChatId, groupName;
FinancialRoom({required this.groupName, required this.groupChatId, Key? key})
: super(key: key);
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final FirebaseAuth _auth = FirebaseAuth.instance;
final _formKey = GlobalKey<FormState>();
TextEditingController amountValue = TextEditingController();
void onSend() async {
Map<String, dynamic> data = {
"amount": amountValue.text,
"sendBy": _auth.currentUser!.displayName,
"type": "text",
"time": FieldValue.serverTimestamp(),
};
amountValue.clear();
await _firestore
.collection('groups')
.doc(groupChatId)
.collection('chats')
.add(data);
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: Text(groupName),
actions: [
IconButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => GroupInfo(
groupName: groupName,
groupId: groupChatId,
),
),
),
icon: Icon(Icons.more_vert)),
],
),
body: SafeArea(
child: ListView(padding: EdgeInsets.all(20.0), children: [
Container(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 10.0,
),
TextFormField(
controller: amountValue,
decoration: InputDecoration(
hintText: 'Enter the amount you want',
labelText: 'Enter the amount you want',
prefixIcon: Icon(Icons.account_balance_wallet_outlined),
enabledBorder: kEnabledBorder,
focusedBorder: kFocusedBorder,
errorBorder: kErrorBorder,
focusedErrorBorder: kErrorBorder,
),
onTap: () {
},
// The validator receives the text that the user has entered.
validator: (value) {
if (value!.isEmpty) {
return 'Please enter the amount you want';
}
return null;
},
),
SizedBox(
height: kInputSpacing,
),
SizedBox(
width: double.infinity,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
color: Colors.blue,
textColor: Colors.white,
padding: EdgeInsets.only(top: 16.0, bottom: 16.0),
onPressed: onSend,
child: Text(
'SEND',
style: kButtonTextStyle,
),
),
),
],
),
),
Container(
height: size.height / 1.27,
width: size.width,
child: StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('groups')
.doc(groupChatId)
.collection('chats')
.orderBy('time')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
Map<String, dynamic> data =
snapshot.data!.docs[index].data()
as Map<String, dynamic>;
return messageTile(size, data);
},
);
} else {
return Container();
}
},
),
),
]),
),
);
}
Widget messageTile(Size size, Map<String, dynamic> data) {
return Builder(builder: (_) {
if (data['type'] == "text") {
return Container(
width: size.width,
alignment: data['sendBy'] == _auth.currentUser!.displayName
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 14),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.blue,
),
child: Column(
children: [
Text(
data['sendBy'],
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
SizedBox(
height: size.height / 200,
),
Text(
data['amount'],
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
)),
);
} else if (data['type'] == "img") {
return Container(
width: size.width,
alignment: data['sendBy'] == _auth.currentUser!.displayName
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
height: size.height / 2,
child: Image.network(
data['amount'],
),
),
);
} else if (data['type'] == "notify") {
return Container(
width: size.width,
alignment: Alignment.center,
child: Container(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black38,
),
child: Text(
data['message'],
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
);
} else {
return SizedBox();
}
});
}
}
It's very straightforward to implement a simple TabBar in your app. All you need is a TabController and two widgets called TabBar and TabBarView. Here is a simple example:
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
]),
),
body: TabBarView(children: [
// Tab 1
Container(color: Colors.red),
// Tab 2
Container(color: Colors.blue),
]),
),
);
Now all you need to do is to replace children inside TabBarView with whatever you want to display.