Related
This is my code where I am showing list of pending invoices.But when i accept the it should reload the pending invoice widget after clicking on snack bar action button.When user clicks on accept button its showing snack bar and when pressed accept action button snack bar it navigate back to same widget where I needs to update that widget along with new list of pending invoices without the invoice which we have accepted
class PendingInvoiceWidget extends StatelessWidget {
final double maxWidth;
final double maxHeight;
final bool isOverdue;
final String amount;
final String savedAmount;
final String invoiceDate;
final String dueDate;
Invoice fullDetails;
int index;
bool userConsentGiven = false;
final String companyName;
PendingInvoiceWidget(
{required this.fullDetails,
required this.maxWidth,
required this.maxHeight,
required this.amount,
required this.savedAmount,
required this.index,
required this.invoiceDate,
required this.dueDate,
required this.companyName,
required this.isOverdue});
#override
Widget build(BuildContext context) {
TextEditingController acceptController = TextEditingController();
TextEditingController rejectController = TextEditingController();
List<Invoice> pendingInvoice =
Provider.of<TransactionManager>(context).pendingInvoice;
String? invoiceId = fullDetails.sId;
String invAmt = double.parse(amount).toStringAsFixed(2);
DateTime id = DateTime.parse(invoiceDate);
DateTime dd = DateTime.parse(dueDate);
DateTime currentDate = DateTime.now();
Duration dif = dd.difference(currentDate);
int daysLeft = dif.inDays;
String idueDate = DateFormat("dd-MMM-yyyy").format(dd);
String invDate = DateFormat("dd-MMM-yyyy").format(id);
double h1p = maxHeight * 0.01;
double h10p = maxHeight * 0.1;
double w10p = maxWidth * 0.1;
return ProgressHUD(child: Builder(builder: (context) {
final progress = ProgressHUD.of(context);
return ExpandableNotifier(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: w10p * .5, vertical: 10),
child: Expandable(
collapsed: ExpandableButton(
child: Card(
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colours.offWhite,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isOverdue
? Padding(
padding: EdgeInsets.symmetric(
vertical: h1p * 1),
child: Container(
// height: h1p * 4.5,
// width: w10p * 1.7,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(5),
color: Colours.failPrimary,
),
child: const Center(
child: Padding(
padding: EdgeInsets.all(4),
child: Text(
"Overdue",
style: TextStyles.overdue,
),
),
),
),
)
: Container(),
Row(
children: [
Text(
"${fullDetails.invoiceNumber}",
style: TextStyles.textStyle6,
),
SvgPicture.asset(
"assets/images/home_images/arrow-circle-right.svg"),
],
),
expanded: Column(
children: [
ExpandableButton(
child: Card(
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colours.offWhite,
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
isOverdue
? Text(
"$daysLeft days Overdue",
style: TextStyles.textStyle57,
)
: Text(
"$daysLeft days left",
style: TextStyles.textStyle57,
),
Text(
"₹ $invAmt",
style: TextStyles.textStyle58,
),
],
)
]),
),
),
),
Card(
elevation: .5,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 4,
),
const Text(
"Invoice Date",
style: TextStyles.textStyle62,
),
Text(
invDate,
style: TextStyles.textStyle63,
),
// Text(
// companyName,
// style: TextStyles.companyName,
// ),
],
),
SvgPicture.asset("assets/images/arrow.svg"),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const SizedBox(
height: 4,
),
const Text(
"Due Date",
style: TextStyles.textStyle62,
),
Text(
idueDate,
style: TextStyles.textStyle63,
),
// Text(
// companyName,
// style: TextStyles.companyName,
// ),
],
),
],
),
),
),
Card(
child: Container(
padding: const EdgeInsets.all(10),
decoration: const BoxDecoration(),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 4,
),
const Text(
"Invoice Amount",
style: TextStyles.textStyle62,
),
Text(
"₹ $invAmt",
style: TextStyles.textStyle65,
)
// Text("Asian Paints",style: TextStyles.textStyle34,),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const SizedBox(
height: 4,
),
isOverdue
? const Text(
"Payabe Amount",
style: TextStyles.textStyle62,
)
: const Text(
"Pay Now",
style: TextStyles.textStyle62,
),
Text(
"₹ $invAmt",
style: TextStyles.textStyle66,
),
],
),
],
),
SizedBox(
height: h1p * 1.5,
),
// Row(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// isOverdue?
// const Text(
// "Interest",
// style: TextStyles.textStyle62,
// ):
// const Text(
// "You Save",
// style: TextStyles.textStyle62,
// ),
// Text(
// "₹ $savedAmount",
// style:isOverdue?
// TextStyles.textStyle73:
// TextStyles.textStyle77,
// ),
// ],
// ),
// ],
// ),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: GestureDetector(
onTap: () {
progress!.show();
getIt<TransactionManager>()
.changeSelectedInvoice(fullDetails);
progress.dismiss();
Navigator.pushNamed(context, savemoreDetails);
},
child: Image.asset(
"assets/images/viewetails.png")),
),
Row(
children: [
Expanded(
child: InkWell(
onTap: () async {
showDialog(
context: context,
builder: (context) => Padding(
padding:
const EdgeInsets.symmetric(
// vertical: h10p * 5,
),
child: AlertDialog(
shape:
const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
10.0))),
title: Row(
children: const [
Center(
child: Text("Comment"),
),
],
),
const SizedBox(
width: 10,
),
Expanded(
child: InkWell(
onTap: () async {
showDialog(
context: context,
builder: (context) => Padding(
padding:
const EdgeInsets.symmetric(
// vertical: h10p * 4,
),
child: StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
shape:
const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
10.0))),
title: const Center(
child: Text("Consent"),
),
content: Column(
mainAxisSize:
MainAxisSize.min,
children: [
Text(
"I agree and approve Xuriti and NBFC Ditya Finance Private Limited to disburse funds to yhe seller $companyName for invoice number -${fullDetails.invoiceNumber} on my behalf"),
TextField(
controller:
acceptController,
decoration:
const InputDecoration(
hintText:
"Leave a comment *"),
onChanged: (_) {
print(acceptController
.text);
acceptController
.text.isEmpty
? Row(
children: const [
Text(
"Please write a reason",
style: TextStyle(
color:
Colors.red),
),
],
)
: Container();
},
),
SizedBox(
height: h1p * 4,
),
InkWell(
onTap: () async {
userConsentGiven =
true;
String timeStamp =
DateTime.now()
.toString();
if (acceptController
.text
.isNotEmpty) {
progress!.show();
String? message = await getIt<
TransactionManager>()
.changeInvoiceStatus(
invoiceId,
"Confirmed",
index,
fullDetails,
timeStamp,
userConsentGiven,
acceptController
.text,
"This invoice has been confirmed and Xuriti and its financing partner is authorised to disburse funds to the seller as per the invoice generated on my behalf");
progress.dismiss();
ScaffoldMessenger
.of(context)
.showSnackBar(
SnackBar(
behavior:
SnackBarBehavior
.floating,
content:
Text(
message!,
style:
const TextStyle(color: Colors.green),
)));
} else {
Fluttertoast.showToast(
msg:
"Please write a reason",
textColor:
Colors.red);
}
Navigator.pop(
context,
);
},
child: Container(
height: h1p * 8,
width: w10p * 7.5,
decoration: BoxDecoration(
borderRadius:
BorderRadius
.circular(
6),
color: Colours
.pumpkin),
child: const Center(
child: Text(
"Accept",
style: TextStyles
.subHeading,
)),
),
),
],
),
);
}),
));
},
child: Container(
height: h1p * 9,
decoration: BoxDecoration(
color: Colours.successPrimary,
borderRadius: BorderRadius.circular(5)),
child: const Center(
child: Text(
"Accept",
style: TextStyles.textStyle46,
),
),
),
),
),
],
)
],
),
),
),
],
)),
),
);
}));
}
}
Please try to use this code as SnackBar and decorate you want,
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
behavior: SnackBarBehavior.floating,
content: Text(
message!,
style: const TextStyle(color: Colors.green),
),
backgroundColor: Colors.black,
action: SnackBarAction(
label: "Reload",
onPressed: () {
setState(() {});
})));
I Hope these things are solve your issue,
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)
],
),
),
),
),
);
}
}
I have some Radios and i want to take some different String based on which Radio is selected.
These Radios are located in another file, and there are several files which i want to take data and bring to my main file and than to save these data into my cloud firebase.
I created another file to store all these Informations but i cant save these data into this class. Can u show me some ways how can i do that?
//this is my informations class
class Informations {
String nom;
String lieu;
String type;
String typDePlonge;
String topographie;
String temperatureEau;
String courant;
String visibilite;
String niveauRequis;
String autonomie;
String quandPlonger;
String requin;
String mammifere;
String reptile;
String crustace;
String raie;
String limace;
String cephalopode;
String corail;
String poissonPelagique;
String poissonDeRecif;
String poissonDeFond;
String vmAutres;
String niveauAcceptes;
String activitesProposes;
String photo;
Informations(
{this.type,
this.nom,
this.photo,
this.activitesProposes,
this.autonomie,
this.cephalopode,
this.corail,
this.courant,
this.crustace,
this.lieu,
this.limace,
this.mammifere,
this.niveauAcceptes,
this.niveauRequis,
this.poissonDeFond,
this.poissonDeRecif,
this.poissonPelagique,
this.quandPlonger,
this.raie,
this.reptile,
this.requin,
this.temperatureEau,
this.topographie,
this.typDePlonge,
this.visibilite,
this.vmAutres});
}
//this is where i have my data.
//For each radio selected i want to take that string which is near the radio,
//the string which is shown at the text widget.
class ActivitesProposes extends StatefulWidget {
const ActivitesProposes({Key key}) : super(key: key);
#override
_ActivitesProposesState createState() => _ActivitesProposesState();
}
class _ActivitesProposesState extends State<ActivitesProposes> {
bool isStrechedActivities = false;
int groupValueActivities = 0;
void handleGroupValueActivities(int value) {
setState(() {
groupValueActivities = value;
});
}
#override
Widget build(BuildContext context) {
return new Padding(
padding: EdgeInsets.fromLTRB(20, 10, 20, 0),
child: Container(
// height: double.infinity,
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
border: GradientBorder.uniform(
width: 3.0,
gradient: LinearGradient(colors: <Color>[
Color(0xff59a5da),
Color(0xff60af6c)
], stops: [
0.3,
0.5
])),
borderRadius: BorderRadius.circular(30.0),
),
child: Column(
children: [
Container(
height: 45,
width: double.infinity,
padding: EdgeInsets.only(right: 10),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[
Color(0xff59a5da),
Color(0xff60af6c),
]),
borderRadius: BorderRadius.all(
Radius.circular(25))),
constraints: BoxConstraints(
minHeight: 45,
minWidth: double.infinity,
),
alignment: Alignment.center,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10),
child: Text(
'Activités proposées',
style: new TextStyle(
fontSize: 20,
color: Colors.white,
decorationThickness: 3.0,
fontWeight: FontWeight.w900,
),
),
),
),
Padding(
padding: const EdgeInsets.all(0.0),
child: GestureDetector(
onTap: () {
setState(() {
isStrechedActivities =
!isStrechedActivities;
});
},
child: Icon(
isStrechedActivities
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Colors.white,
size: 40,
),
),
),
],
),
),
ExpandedSectionThreeRows(
expand: isStrechedActivities,
height: 100,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 18.0),
child: Container(
color: Colors.white70,
child: ListView(
padding: EdgeInsets.all(0),
shrinkWrap: true,
children: [
//controller: scrollController2,
Row(
children: [
Radio(
value: 0,
groupValue:
groupValueActivities,
onChanged:
handleGroupValueActivities),
new Text('cours plongée',
style: new TextStyle(
color:
groupValueActivities ==
0
? Colors.blue
.shade900
: Colors.black,
)),
],
),
Row(
children: [
Radio(
value: 1,
groupValue:
groupValueActivities,
onChanged:
handleGroupValueActivities),
new Text('sortie bateau',
style: new TextStyle(
color:
groupValueActivities ==
1
? Colors.blue
.shade900
: Colors
.black)),
],
),
Row(
children: [
Radio(
value: 2,
groupValue:
groupValueActivities,
onChanged:
handleGroupValueActivities),
new Text(
'location équipement',
style: new TextStyle(
color:
groupValueActivities ==
2
? Colors.blue
.shade900
: Colors.black,
)),
],
),
],
),
),
),
),
],
),
))
],
),
],
),
)),
);
}
}
//The button where im gonna register these data is on another file.
i fixed this really easy, i dont know why i wrote this question here anyway XD.
here is the code:
final informations = Informations();//added a reference for my informations class
// at the function of my radio i added this code and based on what radio
// is selected i add a diff text to my Informations class variable
void handleGroupValueActivities(int value) {
setState(() {
groupValueActivities = value;
if (groupValueActivities == 0){
informations.activitesProposes = 'cours plongee';
}else if(groupValueActivities == 1){
informations.activitesProposes = 'sortie bateau';
}else if(groupValueActivities == 2){
informations.activitesProposes = 'location equipment';
}else {
infromations.activitesProposes = null;
}// and if none of them is selected i return null.
print(informations.activitesProposes);
});
}
this my screen where i fetch data from API using FutureBuilder . I would like to save data getting from server on device and reuse it when i need . I wouldn't like each time fetch data from the server when i open the screen .
My screen :
and this my code :
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return SafeArea(
/* minimum: const EdgeInsets.only(
top: 20.0, right: 5.0, left: 5.0, bottom: 10.0),*/
child: Center(
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Color(0xFFF6F7F8),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: FutureBuilder(
future: future,
// boxApi.getUser(),
builder: (context, snapshot) {
// ignore: missing_return
print(snapshot.data);
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('no connection');
case ConnectionState.active:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
break;
case ConnectionState.done:
if (snapshot.hasError) {
return Text('error');
} else if (snapshot.hasData) {
// String price = snapshot.data['body'].;
// print("${snapshot.data}");
return Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Container(
padding: EdgeInsets.only(top: 16),
width: MediaQuery.of(context).size.width,
height:
MediaQuery.of(context).size.height / 4,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.white60,
blurRadius: 15.0,
offset: Offset(0.0, 0.75))
],
gradient: LinearGradient(
begin: Alignment(0.5, 0.85),
end: Alignment(0.48, -1.08),
colors: [
const Color(0xFF0B0C3A),
const Color(0xFF010611),
],
stops: [
0.0,
0.5,
],
),
//color: blue,
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(32),
bottomLeft: Radius.circular(32))),
child: Column(
children: [
Row(
children: [
SizedBox(
width: 30,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"${snapshot.data.name}",
style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight:
FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(
"${snapshot.data.phone}",
style: TextStyle(
color: Colors.white60,
fontSize: 18,
//fontWeight: FontWeight.w300
),
),
])
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Container(
margin: EdgeInsets.symmetric(
vertical: 10),
width: size.width * 0.4,
child: ElevatedButton(
onPressed: () {
if (_nameController.text ==
"" &&
_emailController.text ==
"" &&
_adressController
.text ==
"") {
setState(() =>
isButtonDisabled =
true);
} else {
editUserProfile();
}
},
// editUserProfile();
child: Text('Enregistrer'),
style:
ElevatedButton.styleFrom(
primary: Colors.transparent,
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius
.circular(
20),
side: BorderSide(
color: Colors
.white)),
),
)),
SizedBox(
width: 20,
),
],
)
],
),
),
Container(
height: MediaQuery.of(context).size.height /
1.5,
// padding: EdgeInsets.only(
// top: 32,
// ),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Container(
width: size.width * 0.94,
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
left: 10,
right: 10,
bottom: 20,
top: 20),
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(
'Votre nom :',
style: TextStyle(
color: Color(
0xFF4053FCF),
fontSize: 16,
fontWeight:
FontWeight
.w600),
),
IconButton(
icon: Icon(
CommunityMaterialIcons
.pencil,
color: Colors
.grey,
),
onPressed: () {
myFocusNode
.requestFocus();
setState(() {
enableup =
true;
});
})
],
),
TextFormField(
controller:
_nameController,
enabled: enableup,
focusNode:
myFocusNode,
enableInteractiveSelection:
false,
keyboardType:
TextInputType
.text,
decoration: InputDecoration(
hintText:
"${snapshot.data.name}",
hintStyle: TextStyle(
color: Colors
.grey,
fontSize:
14.0)),
),
Future<User> getUser() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
String token = localStorage.getString('access_token');
// print(token);
await checkInternet();
Map<String, String> headers = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
var url = Uri.parse(ApiUtil.GET_USER);
var response = await http.get(url, headers: headers);
switch (response.statusCode) {
case 200:
var body = jsonDecode(response.body);
// print(body);
User users = User.fromJson(body);
// inspect(users);
// print(users);
return users;
break;
case 404:
throw ResourceNotFound('user');
break;
case 301:
case 302:
case 303:
throw RedirectionFound();
break;
default:
return null;
break;
}
}
How i can save data locally and reuse it without connect to the server ?
Update :
response from api :
{
"id": 53,
"activeboxe_id": 35,
"username": "hamid hamid",
"name": "Hamid Ansari",
"email": "hamid#gmail.com",
"adress": "Germany",
"phone": "21625147147",
"email_verified_at": null,
"created_at": "2021-04-28T10:52:31.000000Z",
"updated_at": "2021-05-28T09:35:17.000000Z",
"role": "user"
}
You could use a SQLite DB.
Consider the docs.
There you can find an example.
Consider using Hive or Object_Box. The are no SQL dbs, and they are very fast and performant.
If you are using bloc as your state management, HydratedBloc is also available. Which is what I use personally
App was working perfectly before and then I had to make some changes to allow or restrict calling feature in the app based on subscription level of the user, by passing the variable value from one screen to another using provider.
one Screen 1 i am using :
Future<void> _verifyPuchase(String id) async {
PurchaseDetails purchase = _hasPurchased(id);
if (purchase != null && purchase.status == PurchaseStatus.purchased) {
print(purchase.productID);
if (Platform.isIOS) {
await _iap.completePurchase(purchase);
print('Achats antérieurs........$purchase');
isPuchased = true;
}
isPuchased = true;
checkIsPurchsed(isPurchsed: isPuchased);
} else {
isPuchased = false;
checkIsPurchsed(isPurchsed: isPuchased);
}
}
and have i have a class on screen 1:
class checkIsPurchsed with ChangeNotifier{
bool isPurchsed;
checkIsPurchsed({this.isPurchsed});
notifyListeners();
}
and on screen 5 I have:
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.call), onPressed: () => onJoin("AudioCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.video_call), onPressed: () => onJoin("VideoCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
on screen 5 when i try to open a chat this is what i am getting :
the icon buttons on which i am checking the purchase status appear when chat is opened , but after adding the above mentioned modifications the chat itself isnt opening and instead i am getting the red screen.
Update 1:
class ChatPage extends StatefulWidget {
final User sender;
final String chatId;
final User second;
ChatPage({this.sender, this.chatId, this.second});
#override
_ChatPageState createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
bool isBlocked = false;
final db = Firestore.instance;
CollectionReference chatReference;
final TextEditingController _textController = new TextEditingController();
bool _isWritting = false;
final _scaffoldKey = GlobalKey<ScaffoldState>();
//Ads _ads = new Ads();
#override
void initState() {
//_ads.myInterstitial()
//..load()
//..show();
print("object -${widget.chatId}");
super.initState();
chatReference =
db.collection("chats").document(widget.chatId).collection('messages');
checkblock();
}
var blockedBy;
checkblock() {
chatReference.document('blocked').snapshots().listen((onData) {
if (onData.data != null) {
blockedBy = onData.data['blockedBy'];
if (onData.data['isBlocked']) {
isBlocked = true;
} else {
isBlocked = false;
}
if (mounted) setState(() {});
}
// print(onData.data['blockedBy']);
});
}
List<Widget> generateSenderLayout(DocumentSnapshot documentSnapshot) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
child: documentSnapshot.data['image_url'] != ''
? InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
margin: EdgeInsets.only(
top: 2.0, bottom: 2.0, right: 15),
child: Stack(
children: <Widget>[
CachedNetworkImage(
placeholder: (context, url) => Center(
child: CupertinoActivityIndicator(
radius: 10,
),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
height:
MediaQuery.of(context).size.height * .65,
width: MediaQuery.of(context).size.width * .9,
imageUrl:
documentSnapshot.data['image_url'] ?? '',
fit: BoxFit.fitWidth,
),
Container(
alignment: Alignment.bottomRight,
child:
documentSnapshot.data['isRead'] == false
? Icon(
Icons.done,
color: secondryColor,
size: 15,
)
: Icon(
Icons.done_all,
color: primaryColor,
size: 15,
),
)
],
),
height: 150,
width: 150.0,
color: secondryColor.withOpacity(.5),
padding: EdgeInsets.all(5),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: Text(
documentSnapshot.data["time"] != null
? DateFormat.yMMMd()
.add_jm()
.format(documentSnapshot.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
)),
)
],
),
onTap: () {
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => LargeImage(
documentSnapshot.data['image_url'],
),
),
);
},
)
: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.0, vertical: 10.0),
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.only(
top: 8.0, bottom: 8.0, left: 80.0, right: 10),
decoration: BoxDecoration(
color: primaryColor.withOpacity(.1),
borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Container(
child: Text(
documentSnapshot.data['text'],
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
documentSnapshot.data["time"] != null
? DateFormat.MMMd()
.add_jm()
.format(documentSnapshot
.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
),
),
SizedBox(
width: 5,
),
documentSnapshot.data['isRead'] == false
? Icon(
Icons.done,
color: secondryColor,
size: 15,
)
: Icon(
Icons.done_all,
color: primaryColor,
size: 15,
)
],
),
],
),
],
)),
),
],
),
),
];
}
_messagesIsRead(documentSnapshot) {
return <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
child: CircleAvatar(
backgroundColor: secondryColor,
radius: 25.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(90),
child: CachedNetworkImage(
imageUrl: widget.second.imageUrl[0] ?? '',
useOldImageOnUrlChange: true,
placeholder: (context, url) => CupertinoActivityIndicator(
radius: 15,
),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
),
onTap: () => showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return Info(widget.second, widget.sender, null);
}),
),
],
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: documentSnapshot.data['image_url'] != ''
? InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
margin: EdgeInsets.only(
top: 2.0, bottom: 2.0, right: 15),
child: CachedNetworkImage(
placeholder: (context, url) => Center(
child: CupertinoActivityIndicator(
radius: 10,
),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
height: MediaQuery.of(context).size.height * .65,
width: MediaQuery.of(context).size.width * .9,
imageUrl:
documentSnapshot.data['image_url'] ?? '',
fit: BoxFit.fitWidth,
),
height: 150,
width: 150.0,
color: Color.fromRGBO(0, 0, 0, 0.2),
padding: EdgeInsets.all(5),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: Text(
documentSnapshot.data["time"] != null
? DateFormat.yMMMd()
.add_jm()
.format(documentSnapshot.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
)),
)
],
),
onTap: () {
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => LargeImage(
documentSnapshot.data['image_url'],
),
));
},
)
: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.0, vertical: 10.0),
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.only(top: 8.0, bottom: 8.0, right: 10),
decoration: BoxDecoration(
color: secondryColor.withOpacity(.3),
borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Container(
child: Text(
documentSnapshot.data['text'],
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
documentSnapshot.data["time"] != null
? DateFormat.MMMd()
.add_jm()
.format(documentSnapshot
.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
),
),
],
),
],
),
],
)),
),
],
),
),
];
}
List<Widget> generateReceiverLayout(DocumentSnapshot documentSnapshot) {
if (!documentSnapshot.data['isRead']) {
chatReference.document(documentSnapshot.documentID).updateData({
'isRead': true,
});
return _messagesIsRead(documentSnapshot);
}
return _messagesIsRead(documentSnapshot);
}
generateMessages(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map<Widget>((doc) => Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: doc.data['type'] == "Call"
? [
Text(doc.data["time"] != null
? "${doc.data['text']} : " +
DateFormat.yMMMd()
.add_jm()
.format(doc.data["time"].toDate())
.toString() +
" by ${doc.data['sender_id'] == widget.sender.id ? "You" : "${widget.second.name}"}"
: "")
]
: doc.data['sender_id'] != widget.sender.id
? generateReceiverLayout(
doc,
)
: generateSenderLayout(doc)),
))
.toList();
}
#override
Widget build(BuildContext context) {
ChangeNotifierProvider<checkIsPurchsed>(
create: (context)=>checkblock(),
child: Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
elevation: 0,
title: Text(widget.second.name),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
onPressed: () => Navigator.pop(context),
),
actions: <Widget>[
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.call), onPressed: () => onJoin("AudioCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.video_call), onPressed: () => onJoin("VideoCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
}
The problematic area is:
#override
Widget build(BuildContext context) {
ChangeNotifierProvider<checkIsPurchsed>(
There's no return in front of ChangeNotifierProvider, so it doesn't return a Widget. Correct would be:
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<checkIsPurchsed>(