Flutter: pass data from one screen to another based on a list that I fetch from API - flutter

I am building a Job Find app on flutter and I am facing some State Management problems. I have a screen where I show all of my job listings (job_list_screen.dart) and if the user press on a job the app loads this specific job with all the details(job_details_screen.dart).
enter image description here
enter image description here
As you can see, I have an apply button(the blue button) on both screens. When I press apply on the job_details_screen I send a put request on my database and it works fine. But, when I go back to my job_list_screen the button doesn't change even thought I wrapped it with a Consumer.
enter image description here
enter image description here
Here is all the code I wrote with the providers, the **screens **and the **widgets **I use.
The jobs provider:
First of all, this is how I fetch jobs from the API and I insert all my data in a List model:
`
/*
|--------------------------------------------------------------------------
| Fetch Jobs from database
|--------------------------------------------------------------------------
|
| 1. set the url for this function
| 2. GET the response from the server only if you are authenticated
| 3. Decode the
response.body: {
'listings': {
'data': (*Inside here, there are all the job list*)
}
}
| 4. For every job inside the data response
| add a new Job item in the List<Job>
| with the named variables from the current data.reposnse.job
*/
Future<List<Job>?> fetchJobs() async {
final key = await storage.read(key: 'auth');
final baseUrl = AppUrl.baseUrl;
try {
// 1.
var url = Uri.parse('$baseUrl/listings');
// 2.
var response = await http.get(
url,
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $key',
},
);
// print(key);
if (response.statusCode == 200 || response.statusCode == 201) {
// 3.
var jsonResponse = jsonDecode(response.body)['listings']['data'];
_jobs = [];
// 4.
for (var j in jsonResponse) {
Job job = Job(
id: j['id'],
title: j['title'],
employmentType: j['employmentType'],
major: j['major'],
city: j['city'],
companyName: j['companyName'],
experience: j['experience'],
date: j['date'],
views: j['views'],
description: j['description'],
benefits: j['benefits'],
requirements: j['requirements'],
hasApplied: j['hasApplied'],
hasViewed: j['hasViewed'],
);
_jobs.add(job);
notifyListeners();
}
notifyListeners();
return _jobs;
} else {
throw Exception('Problem loading jobs');
}
} catch (e) {
print(e);
}
}
`
This is the function that I call when the user presses the apply button:
`
/*
|--------------------------------------------------------------------------
| Apply for a job
|--------------------------------------------------------------------------
*/
Future<void> applyJob(String id) async {
final key = await storage.read(key: 'auth');
final baseUrl = AppUrl.baseUrl;
try {
var url = Uri.parse('$baseUrl/listings/$id/apply');
var response = await http.put(
url,
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $key',
},
);
if (response.statusCode == 200 || response.statusCode == 201) {
print(jsonDecode(response.body));
_hasApplied = jsonDecode(response.body)['hasApplied'];
notifyListeners();
} else {
print(jsonDecode(response.body));
notifyListeners();
}
} catch (e) {
print(e);
}
notifyListeners();
}
`
The job_card widget:
`
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:final_try/screens/job_details_screen.dart';
import '../models/job.dart';
import '../providers/jobs.dart';
import '../styles/colors.dart';
class JobCardBig extends StatefulWidget {
static const routeName = '/job-card-big';
#override
State<JobCardBig> createState() => _JobCardBigState();
}
class _JobCardBigState extends State<JobCardBig> {
#override
Widget build(BuildContext context) {
final job = Provider.of<Job>(context, listen: true);
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(bottom: 10),
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: lightgrey, width: 1),
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
BoxShadow(
color: lightgrey.withOpacity(.5),
spreadRadius: 1,
blurRadius: 2,
offset: Offset(0, 1), // changes position of shadow
),
],
color: white,
),
child: Column(children: [
Container(
child: Row(
children: [
Container(
height: 50,
width: 50,
alignment: Alignment.center,
decoration:
BoxDecoration(shape: BoxShape.circle, color: lightgrey),
),
SizedBox(
width: 10,
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
height: 70,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
job.title.toString(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
job.companyName.toString(),
style: TextStyle(
fontSize: 14,
color: lightgrey,
),
),
],
),
),
),
Container(
height: 70,
width: 50,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.remove_red_eye,
size: 14,
color: darkgrey,
),
SizedBox(
width: 5,
),
Text(
job.views == null
? job.views = '0'
: job.views.toString(),
style: TextStyle(
fontSize: 14,
color: darkgrey,
),
),
],
),
],
),
),
],
),
),
],
)),
SizedBox(
height: 5,
),
Divider(
thickness: 1,
),
SizedBox(
height: 5,
),
Container(
height: 80,
alignment: Alignment.bottomLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'Είδος Απασχόλησης:',
),
SizedBox(
width: 5,
),
Text(
Provider.of<Jobs>(context, listen: false)
.jobTypeFormat(job.employmentType.toString()),
style: TextStyle(color: lightgrey),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Προϋπηρεσία:'),
SizedBox(
width: 5,
),
Flexible(
child: job.experience == null
? Text(
'Δεν απαιτείται',
style: TextStyle(color: lightgrey),
)
: job.experience! > 1
? Text(
'${job.experience.toString()} χρόνια',
style: TextStyle(color: lightgrey),
)
: Text(
'${job.experience.toString()} χρόνο',
style: TextStyle(color: lightgrey),
),
),
],
),
Row(
children: [
Text('Τοποθεσία:'),
SizedBox(
width: 5,
),
Text(
job.city.toString(),
style: TextStyle(color: lightgrey),
),
],
),
Row(
children: [
Text('Δημοσιεύθηκε:'),
SizedBox(
width: 5,
),
Text(
Provider.of<Jobs>(context, listen: false)
.dateFormat(job.date),
// job.date.toString(),
style: TextStyle(color: lightgrey),
),
],
),
],
),
),
Container(
margin: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
border: Border.all(color: darkgrey, width: 1),
borderRadius: BorderRadius.circular(5.0),
color: darkgrey,
),
child: Text(
'Περισσότερα',
style: TextStyle(color: white),
),
),
onTap: () {
Navigator.of(context)
.pushNamed(JobDetailsScreen.routeName, arguments: job.id)
.then((_) {
// Provider.of<Jobs>(context, listen: false).fetchJobs();
});
},
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
color: job.hasApplied == 1
? Color.fromARGB(255, 196, 76, 68)
: buttonColor,
),
child: Consumer<Job>(
builder: (context, job, child) {
return Text(
job.hasApplied == 1 ? 'Δεν ενδιαφέρομαι' : 'Αίτηση',
style: TextStyle(
color: white,
),
);
},
),
),
],
),
),
]),
);
}
}
`
The job_list_screen:
Here I load all my job_card widgets with ListView.builder
`
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import '../styles/colors.dart';
import '../providers/jobs.dart';
import '../widgets/header_screen.dart';
import '../widgets/job_card_big.dart';
class JobListScreen extends StatefulWidget {
static const routeName = '/job-list-screen';
const JobListScreen({super.key});
#override
State<JobListScreen> createState() => _JobListScreenState();
}
class _JobListScreenState extends State<JobListScreen> {
final controller = ScrollController();
bool _firstLoading = true;
var _isLoading = false;
int page = 1;
final _formKey = GlobalKey<FormState>();
String? _searchText;
bool _isFiltered = false;
#override
void initState() {
controller.addListener(() {
if (controller.position.maxScrollExtent == controller.offset) {
fetch();
}
});
super.initState();
}
Future fetch() async {
if (!_isFiltered) {
setState(() {
_isLoading = true;
page++;
Provider.of<Jobs>(context, listen: false)
.fetchMore(page)
.then((_) => _isLoading = false);
});
}
}
#override
void didChangeDependencies() {
if (_firstLoading) {
Provider.of<Jobs>(context, listen: true).fetchJobs().then((_) {
setState(() {
_firstLoading = false;
});
});
}
super.didChangeDependencies();
}
void searchJob() {
if(_searchText == null || _searchText == ''){
setState(() {
_isFiltered = false;
});
}
else setState(() {
Provider.of<Jobs>(context, listen: false).filterJobs(_searchText!);
_isFiltered = true;
});
}
#override
Widget build(BuildContext context) {
final jobsData = Provider.of<Jobs>(context, listen: true);
var jobsList = jobsData.jobs;
var filteredList = jobsData.filteredJobs;
// var jobsListFiltered = jobsData.filteredJobs;
return Scaffold(
body: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.only(
top: 20,
right: 20,
left: 20,
),
child: Column(
children: [
HeaderScreen(title: 'Αγγελίες'),
Container(
child: Form(
key: _formKey,
child: Row(
children: [
Expanded(
child: Container(
child: TextFormField(
decoration: InputDecoration(
hintText: 'Enter some text',
),
onSaved: (value) {
_searchText = value;
},
),
),
),
Container(
margin: EdgeInsets.only(top: 10, bottom: 5),
height: 40,
width: 40,
child: ElevatedButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all<Color>(white),
backgroundColor: MaterialStateProperty.all<Color>(
primaryColor),
),
child: Container(
child: Icon(Icons.search),
),
onPressed: () {
_formKey.currentState?.save();
searchJob();
},
),
),
],
),
),
),
SizedBox(
height: 10,
),
Divider(
thickness: 1,
),
SizedBox(
height: 10,
),
Expanded(
child: !_isFiltered
? Container(
child: !_firstLoading
? ListView.builder(
controller: controller,
itemCount: jobsList.length,
itemBuilder: (ctx, i) =>
ChangeNotifierProvider.value(
value: jobsList[i],
child: Column(
children: [
JobCardBig(),
],
),
),
)
: Center(
child: CircularProgressIndicator(),
),
)
: Container(
child: !_firstLoading
? ListView.builder(
controller: controller,
itemCount: filteredList.length,
itemBuilder: (ctx, i) =>
ChangeNotifierProvider.value(
value: filteredList[i],
child: Column(
children: [
JobCardBig(),
],
),
),
)
: Center(
child: CircularProgressIndicator(),
),
),
),
],
),
),
Positioned(
child: _isLoading
? Container(
width: double.infinity,
height: MediaQuery.of(context).size.height,
color: Color.fromARGB(52, 0, 0, 0),
child: Center(
child: CircularProgressIndicator(),
),
)
: Container(),
),
],
),
);
}
}
`
I tried to load my fetchJobs() function when the user exits the job_details_screen but even though it works, it is not the right solution. The reason why I say that this is not the right way, is because of this possible scenario:
If the user scrolls down a lot, and the app load 60 jobs, then if he presses on job 60, and he exit the job_details_screen, the app will load the first 15 jobs and the user will have to scroll down again. And that's not the user experience I want to provide.
I am searching for a solution that will update only the apply button and it will not need to recreate the whole list. Plus, with this solution the user will go back to the same scroll point he was when he entered the job_details_screen.
I hope I explained my problem properly. This is the first time I upload a question here and I would also like to mention that this is my first project on flutter so don't judge my code too harshly.
Thanks in advance!!

Related

I have 7 rows when I out the page and go again to the same page it show 14 rows

I have problem, when I run the code it works but when I out from the page and go back it show x2 for the rows its looping without any loop I make in my database 7 rows when I out and return to the same page it shows 14 rows but I have onlu 7 rows.
This is my code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class my_ads extends StatefulWidget {
const my_ads({Key? key}) : super(key: key);
#override
State<my_ads> createState() => _my_adsState();
}
List list = [];
int select_item = 0;
class _my_adsState extends State<my_ads> {
#override
Future MyAds() async {
final response =
await http.get(Uri.parse('https://***.***.***.**/getData.php'));
if (response.statusCode == 200) {
var red = jsonDecode(response.body);
setState(() {
list.addAll(red);
});
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load Ads');
}
}
#override
void initState() {
super.initState();
GetData();
}
GetData() async {
await MyAds();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
margin: const EdgeInsets.only(left: 70, right: 60, top: 50),
height: 54.0,
width: 224.0,
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: const Color(0xffF4AC47), width: 5),
color: const Color(0xff42A9D2),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(40),
bottomRight: Radius.circular(40))),
child: const Center(
child: Text(
"MyAds",
style: TextStyle(
fontSize: 25,
color: Color(0xff072A52),
fontFamily: 'Cairo'),
textAlign: TextAlign.center,
),
//end logo
)),
),
const SizedBox(
height: 35,
),
Expanded(
child: ListView.builder(
itemCount: list.length,
itemBuilder: ((cts, i) {
return Column(
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 10),
height: 180.0,
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color(0xff42A9D2), width: 5),
borderRadius: BorderRadius.circular(8)),
child: Row(
children: [
const Expanded(
flex: 3,
child: Image(
image: AssetImage("assets/book.jpg"),
),
),
Expanded(
flex: 6,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${list[i]["book_name"]}",
style: TextStyle(
fontSize: 20, color: Colors.black87),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text("${list[i]["collage"]}"),
const Icon(Icons.perm_identity_rounded)
],
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text("${list[i]["loc"]}"),
const Icon(Icons.store)
],
),
],
),
)
],
),
),
),
const SizedBox(height: 16),
],
);
}),
),
),
],
),
);
}
}
I tried to add this method to my PHP code $mysqli_connect-> close();
But its not working
This is my PHP code:
<?php
include("config.php");
$sql = "SELECT book_name,loc,com,spe,collage FROM ads";
$res = $connect->query($sql);
while($row = $res -> fetch_assoc()) {
$data[]=$row;
}
echo json_encode($data);
$mysqli_connect-> close();
?>
You declared list outside. It will maintain its state even when you change screens.
Either you declared it inside the state widget or replace :
list.addAll(red);
by :
list = red;

Unhandled Exception: type 'Null' is not a subtype of type 'String' in type cast 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!;
},
);
}
}

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.

The State of Selected value keeps being reverted back to it's original value

I want the value of selected to be of the changed one, but everytime I navigate to a different page then come back it keeps returning selected = true
. I tried putting the late bool selected; then initializing in the initState() but it still doesn't work.
bool selected = true;
#override
Widget build(BuildContext context) {
var why = DateTime.parse(
"${DateTime.now().toString().substring(0, 10)} ${widget.time}");
return Container(
padding: EdgeInsets.all(10),
height: 100,
decoration: BoxDecoration(
color: Color(0xFFF9F9FB),
borderRadius: BorderRadius.circular(30),
),
child: Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 15,
),
Center(
child: Text(
"${widget.time}",
style: TextStyle(fontWeight: FontWeight.bold),
),
)
],
),
SizedBox(
width: 50,
),
Container(
height: 100,
width: 1,
color: Colors.grey.withOpacity(0.5),
),
SizedBox(
width: 10,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("${widget.module}"),
Row(
children: [
Icon(
Icons.location_on,
color: Colors.grey,
size: 20,
),
SizedBox(
width: 3,
),
Text(
"${widget.loc}",
style: TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
],
),
Row(
children: [
Icon(
Icons.person,
color: Colors.grey,
),
SizedBox(
width: 1,
),
Text(
"${widget.lecturer}",
style: TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
],
)
],
),
),
IconButton(
icon: Icon(selected
? Icons.notifications_none
: Icons.notifications_active),
onPressed: () async {
// print(why);
print(widget.time);
print(widget.module);
print(widget.id);
setState(() {
selected = !selected;
});
if (selected == false) {
displayNotification("${widget.module}", why, widget.id);
} else if (selected == true) {
localNotification.cancel(widget.id);
}
},
),
],
),
);
}
Future<void> displayNotification(
String lesson, DateTime lessonTime, int id) async {
FlutterLocalNotificationsPlugin().zonedSchedule(
id,
lesson,
"${lesson} ",
tz.TZDateTime.from(lessonTime, tz.local),
NotificationDetails(
android: AndroidNotificationDetails(
"channel id", "channel name", "channel Description"),
),
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
androidAllowWhileIdle: true);
}
}
void initializeSetting() async {
var initializeAndroid = AndroidInitializationSettings("#mipmap/ic_launcher");
var initializeSetting = InitializationSettings(android: initializeAndroid);
await localNotification.initialize(initializeSetting);
}
A quick fix :-
Just place your selected variable outside any class like this.
import ...//all the import statements
bool selected = true;
//Rest other code

setState() or markNeedsBuild() called during build. when call native ad

import 'package:facebook_audience_network/ad/ad_native.dart';
import 'package:facebook_audience_network/facebook_audience_network.dart';
import 'package:flutter/material.dart';
import 'package:share/share.dart';
import 'package:social_share/social_share.dart';
import 'package:clipboard_manager/clipboard_manager.dart';
// ignore: camel_case_types
class listview extends StatefulWidget {
const listview({
Key key,
#required this.records,
}) : super(key: key);
final List records;
#override
_listviewState createState() => _listviewState();
}
// ignore: camel_case_types
class _listviewState extends State<listview> {
#override
void initState() {
super.initState();
FacebookAudienceNetwork.init(
testingId: "35e92a63-8102-46a4-b0f5-4fd269e6a13c",
);
// _loadInterstitialAd();
// _loadRewardedVideoAd();
}
// ignore: unused_field
Widget _currentAd = SizedBox(
width: 0.0,
height: 0.0,
);
Widget createNativeAd() {
_showNativeAd() {
_currentAd = FacebookNativeAd(
adType: NativeAdType.NATIVE_AD,
backgroundColor: Colors.blue,
buttonBorderColor: Colors.white,
buttonColor: Colors.deepPurple,
buttonTitleColor: Colors.white,
descriptionColor: Colors.white,
width: double.infinity,
height: 300,
titleColor: Colors.white,
listener: (result, value) {
print("Native Ad: $result --> $value");
},
);
}
return Container(
width: double.infinity,
height: 300,
child: _showNativeAd(),
);
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: this.widget.records.length,
itemBuilder: (BuildContext context, int index) {
var card = Container(
child: Card(
margin: EdgeInsets.only(bottom: 10),
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(1.0),
),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
print(this.widget.records);
},
child: Image.asset(
"assets/icons/avatar.png",
height: 45,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
(this
.widget
.records[index]['fields']['Publisher Name']
.toString()),
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
(this
.widget
.records[index]['fields']['Date']
.toString()),
style: TextStyle(
fontSize: 12,
),
),
],
),
)
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.90,
// height: MediaQuery.of(context).size.height * 0.20,
decoration: BoxDecoration(
border: Border.all(
color: Colors.purple,
width: 3.0,
),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(18.0),
child: Text(
(this
.widget
.records[index]['fields']['Shayari']
.toString()),
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
GestureDetector(
onTap: () {
ClipboardManager.copyToClipBoard(this
.widget
.records[index]['fields']['Shayari']
.toString())
.then((result) {
final snackBar = SnackBar(
content: Text('Copied to Clipboard'),
);
Scaffold.of(context).showSnackBar(snackBar);
});
print(this
.widget
.records[index]['fields']['Shayari']
.toString());
},
child: Image.asset(
"assets/icons/copy.png",
height: 25,
),
),
GestureDetector(
onTap: () async {
SocialShare.checkInstalledAppsForShare().then(
(data) {
print(data.toString());
},
);
},
child: Image.asset(
"assets/icons/whatsapp.png",
height: 35,
),
),
GestureDetector(
onTap: () async {
Share.share("Please Share https://google.com");
},
child: Image.asset(
"assets/icons/share.png",
height: 25,
),
),
],
),
SizedBox(
height: 5,
),
],
),
),
);
return Column(
children: [
card,
index != 0 && index % 5 == 0
? /* Its Show When Value True*/ createNativeAd()
: /* Its Show When Value false*/ Container()
],
);
},
);
}
}
I Am Having This Error setState() or markNeedsBuild() called during build.
I Try To Call Facebook Native Ads Between My Dynamic List View But Showing this error when I call native ad createNativeAd This is My Widget Where I set Native ad
This is code where I call ad
** return Column(
children: [
card,
index != 0 && index % 5 == 0
? /* Its Show When Value True*/ createNativeAd()
: /* Its Show When Value false*/ Container()
],
);
},
);**