Related
I am new to flutter and I'm currently developing a flutter application that fetches data from https://private-anon-b242a842d4-carsapi1.apiary-mock.com/manufacturers. I am displaying the image and name from the above JSON file. some of the image URL s don't have images. How can I display an image from my assets folder except for the unavailable images in the JSON file?
Home Page - where i display list of images and names
Future<List<Car>> fetchCar() async {
carList = [];
final response = await http.get(
Uri.parse('https://private-anon-b242a842d4-carsapi1.apiary-mock.com/manufacturers')
);
if (response.statusCode == 200) {
List<dynamic> values = [];
values = json.decode(response.body);
if (values.length > 0) {
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
Map<String, dynamic> map = values[i];
carList.add(Car.fromJson(map));
}
}
setState(() {
carList;
});
}
return carList;
}else {
throw Exception('Failed to load cars');
}
}
#override
void initState() {
fetchCar();
Timer.periodic(Duration(seconds: 10), (timer) => fetchCar());
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: carList.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (_)=>DetailsPAge(
name: carList[index].name,
img_url: carList[index].img_url,
avg_price: carList[index].avg_price,
num_models:carList[index].num_models,
max_car_id: carList[index].max_car_id,
avg_horsepower: carList[index].avg_horsepower,
)),);
},
child: CarCard(
name: carList[index].name,
img_url: carList[index].img_url
),
);
},
));
}
}
class Car {
Car({
required this.name,
required this.id,
required this.img_url,
required this.max_car_id,
required this.num_models,
required this.avg_price,
required this.avg_horsepower
});
String name;
int id;
String img_url;
int max_car_id;
int num_models;
double avg_horsepower;
double avg_price;
factory Car.fromJson(Map<String, dynamic> json) {
return Car(
name: json['name'],
id: json['id'],
img_url: json['img_url'],
max_car_id: json['max_car_id'],
num_models:json['num_models'],
avg_price: json['avg_price'],
avg_horsepower: json['avg_horsepower']
);
}
}
List<Car> carList = [];
CarCard widget - where I customize image and text
class CarCard extends StatelessWidget {
CarCard({
required this.name,
required this.img_url,
});
String name;
String img_url;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 15, left: 10, right: 10),
child: Container(
height: 100,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(4, 4),
blurRadius: 10,
spreadRadius: 1,
),
BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 10,
spreadRadius: 1,
),
],
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(4, 4),
blurRadius: 10,
spreadRadius: 1,
),
BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 10,
spreadRadius: 1,
),
],
),
height: 60,
width: 60,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.network(img_url),
),
),
),
Expanded(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
name,
style: TextStyle(
color: Colors.grey[900],
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
],
),
),
);
}
}
As far as I understood your question you want to display an image from your assets if there are no image in the json.
If that is what you want to do then you can use ?? operator, to check if there is an image in that json, like:
Navigator.of(context).push(MaterialPageRoute(builder: (_)=>DetailsPAge(
name: carList[index].name,
img_url: carList[index].img_url ?? Image.assets("<Your asset image path>"),
avg_price: carList[index].avg_price,
num_models:carList[index].num_models,
max_car_id: carList[index].max_car_id,
avg_horsepower: carList[index].avg_horsepower,
)),);
You can add this everywhere you want an image.
Also don't put all of your code no one is actually going to read and understand all of that; only add the code that is causing the error.
If the image is not in json link, then you can check it first and then show from local assets, lets try
child: Padding(
padding: const EdgeInsets.all(10.0),
child: img_url!=null && img_url.isNotEmpty
? Image.network(img_url)
: Icon(Icons.add),
),
instead of icon you can try with
Align(
alignment: Alignment.center,
child: Image.asset('images/ic_alert_triangle.png'),
),
I am havin this issue where I have a two step form. There is a local JSON file that I load initiating the state to use on the second step in a dropdown widget. However, when I click the continue button and switch to the second form, the variable changes to null causing to get the error "The method 'map' was called on null". I have tried loading the data in the onPressed function of the continueButton Widget, and tried to load again when creating one of the widget of the second form. But I always get this error that the map function was called on null. Help please !!!
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';
import 'package:ofepaw/services/auth.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
class RegisterPage extends StatefulWidget {
final Function toggleView;
RegisterPage({this.toggleView});
#override
State createState() => RegisterPageState();
}
class RegisterPageState extends State<RegisterPage> {
final AuthService _auth = AuthService();
// store the step we are in
int step = 1;
// Text Field
String emailOrPhone = "";
String pass = "";
String verifyPass = "";
String firstName = "";
String lastName = "";
String department = "";
String arrondissement = "";
String commune = "";
// variable for errors
String error = "";
// array containing the forms
var form1;
var form2;
// Controllers for the Textfields
final _emailOrPhoneController = TextEditingController();
final _passwordController = TextEditingController();
final _verifyPassController = TextEditingController();
final _firstNameController = TextEditingController();
final _lastNameController = TextEditingController();
//final _departmentController = TextEditingController();
//load the geographic division of Haiti json file
var division;
// get the locations data
Future<void> loadDivision() async {
String jsonString = await rootBundle
.loadString('assets/haiti_administrative_district.json');
Map<String, dynamic> map = json.decode(jsonString);
List<dynamic> data = map["departments"];
setState(() {
division = data;
});
}
// function to register user in ofepaw database
Future registerUser(
String id, String fname, String lname, String department) async {
final String url = "url go here";
final response = await http.post(url, body: {
"id": id,
"fname": fname,
"lname": lname,
"department": department
});
if (response.statusCode == 201) {
print("This is the response from the server");
print(response.body);
print("Response passed");
} else {
print("Error occured");
}
print(" The response is : ");
print(response.body.toString());
}
//functions for switching forms
getForm(int form) {
if (form == 1) {
return form1;
} else if (form == 2) {
return form2;
}
}
#override
void initState() {
super.initState();
loadDivision();
print(division);
form1 = <Widget>[
firstForm(),
Text("Or Sign Up with social media"),
SizedBox(
height: 20,
),
socialMediaButtons(),
SizedBox(
height: 50,
),
InkWell(
onTap: () {
widget.toggleView();
},
child: Text("Have an account? Login"))
];
form2 = <Widget>[
secondForm(),
InkWell(
//back button
onTap: () => setState(() => step = 1),
child: Text("Back"))
];
}
// dispose all controllers
// dispose of all TextEditingControllers
#override
void dispose() {
_emailOrPhoneController.dispose();
_passwordController.dispose();
_verifyPassController.dispose();
_firstNameController.dispose();
_lastNameController.dispose();
//_departmentController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Material(
child: Expanded(
child: Stack(
children: <Widget>[
// banner with picture
Positioned(
child: banner(),
),
// Login Elements Container
Positioned(
child: Container(
margin: EdgeInsets.only(top: 300.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 20,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.only(
topRight: Radius.circular(50),
topLeft: Radius.circular(50))),
child: Center(
child: Column(
children: getForm(step),
),
),
),
)
],
),
),
);
}
Widget banner() {
return Container(
height: 350,
decoration: BoxDecoration(color: Colors.white),
child: Center(
child: Image.network(
"https://image.freepik.com/free-vector/man-using-his-phone-instead-working_23-2148501890.jpg"),
),
);
}
Widget emailField() {
return TextFormField(
controller: _emailOrPhoneController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "Email or Phone Number",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => emailOrPhone = val);
},
);
}
Widget firstNameField() {
return TextFormField(
controller: _firstNameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "First Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => firstName = val);
},
);
}
Widget lastNameField() {
return TextFormField(
controller: _lastNameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "Last Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => lastName = val);
},
);
}
Widget departmentField() {
return DropdownButtonFormField(
items: division.map<DropdownMenuItem<String>>((value) {
return DropdownMenuItem<String>(
value: value["name"],
child: Text(value["name"]),
);
}).toList(),
hint: Text("Choose the department"),
onChanged: (value) {
setState(() {});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
);
}
Widget arrondissementField() {
return DropdownButtonFormField(
items: [
DropdownMenuItem(
child: Text("Delmas"),
value: 1,
),
DropdownMenuItem(
child: Text("Petion-Ville"),
value: 2,
)
],
hint: Text("Choose the department"),
onChanged: (int value) {
setState(() {});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)));
}
Widget communeField() {
return DropdownButtonFormField(
items: [
DropdownMenuItem(
child: Text("Delmas"),
value: 1,
),
DropdownMenuItem(
child: Text("Petion-Ville"),
value: 2,
)
],
hint: Text("Choose the department"),
onChanged: (int value) {
setState(() {});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)));
}
Widget passwordField() {
return TextFormField(
controller: _passwordController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 5, left: 20, right: 20),
border: InputBorder.none,
hintText: "Password",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => pass = val);
});
}
Widget verifyPasswordField() {
return TextFormField(
controller: _verifyPassController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 5, left: 20, right: 20),
border: InputBorder.none,
hintText: "Reenter Password",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => verifyPass = val);
});
}
Widget socialMediaButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SignInButton(Buttons.Facebook,
mini: true, onPressed: () => print("Facebook Sign in ...")),
SignInButton(Buttons.Google,
//mini: true,
onPressed: () => print("Google Sign in ..."))
],
);
}
Widget continueButton() {
return ButtonTheme(
minWidth: 185.0,
height: 48.0,
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
child: Text("continue"),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
onPressed: () {
print(division);
setState(() {
step = 2;
});
},
));
}
Widget signUpButton() {
return ButtonTheme(
minWidth: 185.0,
height: 48.0,
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
child: Text("Sign Up"),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
onPressed: () async {
dynamic result =
await _auth.registerWithEmailAndPassword(emailOrPhone, pass);
if (result == null) {
setState(() => error = "Email or Password incorrect");
} else {
// Register user ID in the server database
registerUser(result.user.uid, firstName, lastName, department);
}
},
));
}
Widget emailPassField() {
return Container(
// Form input field
margin: EdgeInsets.only(top: 40.0),
width: 320.0,
height: 180.0,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 0.2,
blurRadius: 5,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.circular(20)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
emailField(),
Divider(),
passwordField(),
Divider(),
verifyPasswordField()
],
),
);
}
Widget personalInfoField() {
return Container(
// Form input field
margin: EdgeInsets.only(top: 40.0),
width: 320.0,
height: 310.0,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 0.2,
blurRadius: 5,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.circular(20)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
firstNameField(),
Divider(),
lastNameField(),
Divider(),
departmentField(),
Divider(),
arrondissementField(),
Divider(),
communeField()
],
),
);
}
Widget firstForm() {
return Column(
children: <Widget>[
emailPassField(),
SizedBox(
height: 50,
),
continueButton(),
SizedBox(
height: 50,
),
],
);
}
Widget secondForm() {
return Column(
children: <Widget>[
personalInfoField(),
SizedBox(
height: 40,
),
signUpButton(),
SizedBox(
height: 40,
),
],
);
}
}
The root of your problem starts here String jsonString = await rootBundle.loadString('assets/haiti_administrative_district.json');
Are you sure your project can recognize thise: 'assets/haiti_administrative_district.json'? Have you added it to your assests in pubspec.yaml?
Because this is line is returning null, everything downward will b e returning null, including the error you are reciving.
Future<void> loadDivision() async {
String jsonString = await rootBundle
.loadString('assets/haiti_administrative_district.json');
Map<String, dynamic> map = json.decode(jsonString);
List<dynamic> data = map["departments"];
setState(() {
division = data;
});
}
Here, first make sure data is getting loaded in jsonString.
Second, make sure json.decode(jsonString) is returning json object and not array of json objects.
If it is returning array of json objects, store it in a List<Map>.
Then make a list like this:
List<Map> maps = json.decode(jsonString);
List data=new List();
maps.forEach((element)=>data.add(element['departments']));
I am passing a list of data that I called through API on 1st screen to 2nd screen and I am able to print all the data at once.
but now I want to use this data one by one and I don't know how to do that.... can you help?
this is the second screen -:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'Home_View.dart';
class AboutScreen extends StatefulWidget {
final data;
AboutScreen({Key key,#required this.data}) : super(key: key);
#override
_AboutScreenState createState() => _AboutScreenState(data:data);
}
class _AboutScreenState extends State<AboutScreen> {
var data;
_AboutScreenState({this.data});
int i = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
print(data.toString()); // here i am printing all data
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 150, bottom: 40),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
elevation: 25,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(65),
),
child: CircleAvatar(
child: Icon(Icons.insert_emoticon_outlined, size: 100,),
radius: 80,
foregroundColor: Colors.deepPurpleAccent,
),
),
],
),
),
Text(
'${data[0][i.toString()]}', // here i wanted to get data individually but it's showing error
style: TextStyle(
fontSize: 30,
letterSpacing: 2.5,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 30,),
Text(
'Version 2.2',
style: TextStyle(
fontSize: 20,
letterSpacing: 2.5,
),
),
SizedBox(height: 30,),
Text(
'Developed By Black Console',
style: TextStyle(
fontSize: 20,
letterSpacing: 2.5,
),
),
SizedBox(height: 40,),
FloatingActionButton(
child: Icon(Icons.arrow_back_ios),
backgroundColor: Colors.deepPurpleAccent,
elevation: 16,
onPressed: (){
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => homeView()
));
},
),
],
),
);
}
}
below is the data that I am getting as a list -:
I/flutter ( 4689): {alternateno: [7845659877, 9865358577], coachaddress: [anand vihar, delhi, delhi, Gautam Budha nagar, noida], coachemail: [bct#gmail.com, SSG#gmail.com], coachid: [1, 2], coachname: [BCT Coaching, SSG Coaching], primary_number: [9865328899, 9898557898], userid: [1, 1]}
can you guide me please..
Your data variable seems to be a Map, not a list, so you can access its values like this:
data['alternateno'][i]
I'm new to flutter and i was working on a small poc project. All I Want is that to call a function which is in second page from my first page using abutton click. here what i had done,
1st page
class Mainpage extends StatefulWidget {
#override
_MainpageState createState() => _MainpageState();
}
class _MainpageState extends State<Mainpage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: Padding(
padding: EdgeInsets.only(left: 12),
child: IconButton(
icon: Icon(Icons.menu,
color: Colors.grey[500],
size: 30,),
onPressed: () {
print('Click leading');
},
),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
Text('Basic AppBar'),
]
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.notifications,
color: Colors.grey[500],
size: 30,),
onPressed: () {
Navigator.pushNamed(context, '/notifications');
},
),
],
),
body:
Container(
padding: EdgeInsets.fromLTRB(10,10,10,0),
child: Column(
children:<Widget>[
Row(
children:<Widget>[
]),
SizedBox(height: 60),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
GestureDetector(
child: Image.asset('assets/cam.png',
height:90),
onTap: () {
showDialog(
context: context,
builder: (context) {
return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
elevation: 16,
child: Container(
height: 180.0,
width: 330.0,
child: ListView(
children: <Widget>[
SizedBox(height: 20),
//Center(
Padding(
padding: const EdgeInsets.only(left:15.0),
child: Text(
"Add a Receipt",
textAlign: TextAlign.left,
style: TextStyle(fontSize: 24, color: Colors.black, fontWeight: FontWeight.bold),
),
),
// ),
SizedBox(height: 20),
FlatButton(
child: Text(
'Take a photo..',
textAlign: TextAlign.left,
style: TextStyle(fontSize: 20),
),
onPressed: () {
});
i don't know want to give in the onpressed function at the end of the above code
and the 2nd page is as follow
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File _selectedFile;
bool _inProcess = false;
Map data = {};
Widget getImageWidget() {
if (_selectedFile != null) {
return Image.file(
_selectedFile,
width: 350,
height: 650,
fit: BoxFit.cover,
);
} else {
return Image.asset(
"assets/splashlogo.png",
width: 350,
height: 650,
fit: BoxFit.cover,
);
}
}
getImage(ImageSource source) async {
this.setState((){
_inProcess = true;
});
File image = await ImagePicker.pickImage(source: source);
if(image != null){
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
maxWidth: 1080,
maxHeight: 1080,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: Colors.black,
toolbarWidgetColor: Colors.white,
//toolbarTitle: "RPS Cropper",
statusBarColor: Colors.deepOrange.shade900,
backgroundColor: Colors.black,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false
),
iosUiSettings: IOSUiSettings(
minimumAspectRatio: 1.0,
)
);
this.setState((){
_selectedFile = cropped;
_inProcess = false;
});
} else {
this.setState((){
_inProcess = false;
});
}
}
i needed to call getImage(ImageSource.camera); inside the my onpress function in the 1st page which points to the getimage function on second page.
can anyone help me with it..?
here add this in you 1st page in onpressed
Navigator.pushReplacementNamed(context,'/2ndpage',arguments: {
'pickerCode': "0",
});
and on the second page you do
#override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
data = ModalRoute.of(context).settings.arguments;
print(data);
if(data['pickerCode']=="0"){
getImage(ImageSource.camera);
}
});
}
this is a tricky thing but I think it will help you.
Use a GlobalKey.
GlobalKey<_MyHomePageState> globalImageKey = GlobalKey();
Change this:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}): super(key:key)
#override
_MyHomePageState createState() => _MyHomePageState();
}
when using MyHomePage:
MyHomePage(key: globalImageKey)
call:
globalImageKey.currentState.getImage(ImageSource.camera);
I have worked a little on a flutter json tutorial, where I am able to fetch and parse json data, I am now trying to put the code into a SliverList. But when I debug my app it throws the follwing error on Builder on line 96: The getter 'length' was called on null. Receiver: null Tried calling: length
I am not sure what to do or what to change. Please note that my app consists of 1 Page with tabbar view.
Here is my full code:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:innbo_app/product_model.dart';
Future<List> fetchData(http.Client client) async {
final response = await client
.get('http://my-json-server.typicode.com/tariksalihovic/innbo/receipt');
// Use the compute function to run parsePhotos in a separate isolate.
return compute(parseData, response.body);
}
// A function that converts a response body into a List<Photo>.
List parseData(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map((json) => Receipt.fromJson(json)).toList();
}
class PlaceholderWidget1 extends StatelessWidget {
final Color color;
PlaceholderWidget1(this.color);
#override
Widget build(BuildContext context) {
return Container(
color: color,
);
}
}
class Indbo1 extends StatelessWidget {
final List data;
Indbo1({Key key, this.data}) : super(key: key);
final List<String> listItems = [];
final List<String> _tabs = <String>[
"Alle",
"Anmeldt",
];
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
body: Container(
color: Colors.grey[100],
child: DefaultTabController(
length: _tabs.length, // This is the number of tabs.
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
// These are the slivers that show up in the "outer" scroll view.
return <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
sliver: SliverSafeArea(
top: false,
sliver: SliverAppBar(
centerTitle: true,
title: const Text(
"Indbo",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
fontSize: 16,
),
),
floating: true,
pinned: true,
snap: true,
stretch: false,
bottom: TabBar(
// These are the widgets to put in each tab in the tab bar.
tabs: _tabs
.map((String name) => Tab(text: name))
.toList(),
),
),
),
),
];
},
body: TabBarView(
// These are the contents of the tab views, below the tabs.
children: _tabs.map((String name) {
return SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (BuildContext context) {
return CustomScrollView(
key: PageStorageKey<String>(name),
slivers: <Widget>[
SliverOverlapInjector(
// This is the flip side of the SliverOverlapAbsorber above.
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
SliverPadding(
padding: EdgeInsets.fromLTRB(15, 0, 15, 10),
sliver: SliverList(
delegate: SliverChildListDelegate([
SizedBox(height: 30),
Text(
'Genstande',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700),
),
]),
),
),
SliverList(
delegate: SliverChildListDelegate(
[
Container(
child: FutureBuilder<List>(
future: fetchData(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError)
print(snapshot.error);
return snapshot.hasData
? Indbo1(data: snapshot.data)
: Center(
child:
CircularProgressIndicator());
},
),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 1.0,
color: Colors.grey[200]),
),
color: Colors.white,
),
margin:
EdgeInsets.only(left: 15, right: 15),
),
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 1.0,
color: Colors.grey[200]),
),
color: Colors.white,
),
margin:
EdgeInsets.only(left: 15, right: 15),
child: ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
/*onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Detail(choice: choices[index])),
);
},*/
leading: CircleAvatar(
radius: 26,
backgroundColor: Colors.grey[400],
child: Icon(Icons.phone_iphone,
color: Colors.white),
),
title: Text(
'${data[index].receiptlines[index].name ?? "Empty"}',
style: TextStyle(
color: Colors.black,
fontSize: 16.5,
fontWeight: FontWeight.w700),
),
subtitle: Text(
'${data[index].orderNumber ?? "Empty"}',
style: TextStyle(
color: Colors.grey[700],
fontSize: 12.0),
),
trailing: Text(
'${data[index].price.amount ?? "Empty"}',
style: TextStyle(
color: Colors.black,
fontSize: 16.5,
fontWeight: FontWeight.w800),
),
);
},
),
),
],
),
),
],
);
},
),
);
}).toList(),
),
),
),
),
),
);
}
}
Here is the product_model.dart which is linked to above code:
class Lines {
final String name;
final String productNumber;
Lines({this.name, this.productNumber});
factory Lines.fromJson(Map<String, dynamic> json) {
return Lines(name: json['name'], productNumber: json['productNumber']);
}
}
class Prices {
final int amount;
Prices({this.amount});
factory Prices.fromJson(Map<String, dynamic> json) {
return Prices(
amount: json['amount'],
);
}
}
class Receipt {
final int id;
final String type;
final String receiptId;
final String orderNumber;
final Prices price;
final List<Lines> receiptlines;
Receipt(
{this.id,
this.type,
this.receiptId,
this.orderNumber,
this.price,
this.receiptlines});
factory Receipt.fromJson(Map<String, dynamic> json) {
var list = json['receiptLines'] as List;
List<Lines> receiptLines =
List<Lines>.from(list.map((i) => Lines.fromJson(i))).toList();
return Receipt(
id: json['id'],
type: json['type'],
receiptId: json['receiptId'],
orderNumber: json['orderNumber'],
price: Prices.fromJson(json['price']),
receiptlines: receiptLines
);
}
}