Unable to load asset(Image) Flutter - flutter

This is my API code and I'm passing the image path from here into flutter to determine which image to load. However, all of the other data such as price or title are loading but the image is not loading and throwing an error of unable to load asset.
app.post('/products',(req,res)=>{
//console.log(req.body.LanguageID);
//console.log(req.body.CategoryID);
console.log(req.body);
res.status(200).json({
"StatusCode": 200,
"StatusMessage": "success",
"Data": [
{
"Id": "p8",
"title": "Sufiyan",
"ImageAsset": "assets/images/plant3.png",
"price": 80.0
},
{
"Id": "p8",
"title": "Sufiyan",
"ImageAsset": "assets/images/plant1.png",
"price": 90.0
}
],
"Message": null,
// "localId": '8',
// "idToken": '',
// "error": {
// "message": ""
// },
// "expiresIn": "9"
});
});
app.listen(5000);
That's how I am loading data from the provider into the widget and unable to comprehend why this is not working as I am a newbie to flutter and unable to understand it.
#override
void initState() {
// TODO: implement initState
super.initState();
//gettingData();
final productData = Provider.of<Products>(context, listen: false);
productData.fetchData(context);
// Create TabController for getting the index of current tab
_controller = TabController(length: list.length, vsync: this);
_containerheight = _totalarrayheight(8) * 140;
}
#override
Widget build(BuildContext context) {
final productData = Provider.of<Products>(context);
final products = productData.items;
final featuredProducts = productData.featuredItems;
_controller!.addListener(() {
setState(() {
_selectedIndex = _controller!.index;
if (_controller!.index == 0) {
_containerheight =
140 * _totalarrayheight(products.length.toDouble());
} else {
_containerheight =
140 * _totalarrayheight(featuredProducts.length.toDouble());
}
});
if (kDebugMode) {
print("Selected Index: " + _controller!.index.toString());
}
});
That is my provider code:
class Products with ChangeNotifier {
late List<ProductList> _items = [];
fetchData(context) async {
_items = await getData();
notifyListeners();
}
Widget to create the grid for product
class NewProductGrid extends StatelessWidget {
const NewProductGrid({
Key? key,
required this.products,
}) : super(key: key);
final List<ProductList> products;
#override
Widget build(BuildContext context) {
return StaggeredGridView.countBuilder(
padding: EdgeInsets.only(right: 30, left: 10, top: 10),
physics:
NeverScrollableScrollPhysics(), // to disable GridView's scrolling
shrinkWrap: false,
crossAxisCount: 4,
itemCount: products.length,
itemBuilder: (BuildContext context, int index) => GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(ProductDetail.routeName,
arguments: {'id': products[index].id});
},
child: Container(
//padding: EdgeInsets.only(left:40.0),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 35.0),
child: Container(
height: 150,
width: 150,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: primary_background_six,
),
),
),
Container(
child: Image.asset(
"${products[index].imageAsset}",
fit: BoxFit.cover,
)),
Container(),
],
),
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: Text(
"\$${products[index].price.toInt()}",
style: TextStyle(fontFamily: 'Morganite Light', fontSize: 50),
),
),
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: Text(
"${products[index].title}",
style: TextStyle(fontFamily: 'PlayFairDisplay', fontSize: 18),
),
),
],
),
),
),
staggeredTileBuilder: (int index) =>
StaggeredTile.count(2, index.isEven ? 3 : 3),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
);
}
}
screen code where the widget is called.
Container(
height: _containerheight,
child: TabBarView(
controller: _controller,
children: <Widget>[
Container(
//height: 140.0 * _totalarrayheight(tagObjs.length.toDouble()),
child: NewProductGrid(
products: products),
)
Product list model code:
import 'package:flutter/material.dart';
class ProductList with ChangeNotifier {
final String id;
final String title;
final String imageAsset;
final num price;
bool isFavorite;
ProductList({
required this.id,
required this.title,
required this.price,
required this.imageAsset,
this.isFavorite = false,
});
factory ProductList.fromMap(Map<String, dynamic> json) {
return ProductList(
id: json['id'],
title: json['title'],
imageAsset: json['imageAsset'],
price: json['price']);
}
factory ProductList.fromJson(Map<String, dynamic> json) {
print('Json:');
print(json);
return ProductList(
id: json['id'] ?? '',
title: json['title'] ?? '',
imageAsset: json['imageAsset'] ?? '',
price: json['price'] ?? 0);
}
void toggleFavoriteStatus() {
isFavorite = !isFavorite;
notifyListeners();
}
}

The image asset in response has an upper case i and the model of product list has image asset with lower case i
Change the model to this
import 'package:flutter/material.dart';
class ProductList with ChangeNotifier {
final String id;
final String title;
final String imageAsset;
final num price;
bool isFavorite;
ProductList({
required this.id,
required this.title,
required this.price,
required this.imageAsset,
this.isFavorite = false,
});
factory ProductList.fromMap(Map<String, dynamic> json) {
return ProductList(
id: json['id'],
title: json['title'],
imageAsset: json['ImageAsset'],
price: json['price']);
}
factory ProductList.fromJson(Map<String, dynamic> json) {
print('Json:');
print(json);
return ProductList(
id: json['id'] ?? '',
title: json['title'] ?? '',
imageAsset: json['ImageAsset'] ?? '',
price: json['price'] ?? 0);
}
void toggleFavoriteStatus() {
isFavorite = !isFavorite;
notifyListeners();
}
}

Related

Flutter List of dynamic checkboxex from API

I am a learner and new to Flutter.
I want help with the followings
I need to get a list of items with checkboxes from and API
I should be able to select a single or multiple checkboxes
If I select a checkbox its should display the total amount selected
if I select two checkboxes, its should sum the total of the two for me and display it.
Below is what I have done so far.
I will greatly appreciate your solutions
here is my code
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:liquid_pull_to_refresh/liquid_pull_to_refresh.dart';
import 'dart:convert';
import 'dart:ffi';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stachup/models/TeamModel.dart';
import 'package:stachup/models/newStaches.dart';
import 'package:stachup/models/TeamModel.dart';
class Stash extends StatefulWidget {
String first_name;
String token;
String referalcode;
String last_name;
Stash(
{Key? key,
required this.first_name,
required this.token,
required this.last_name,
required this.referalcode})
: super(key: key);
#override
State<Stash> createState() => _StashState();
}
class _StashState extends State<Stash> {
bool isChecked = false;
String? first_name;
String? token;
String? last_name;
String? referalcode;
bool setup = false;
String? setupError;
bool _isChecked = false;
late SharedPreferences logindata;
userData() async {
logindata = await SharedPreferences.getInstance();
first_name = logindata.getString('first_name')!;
last_name = logindata.getString('last_name')!;
referalcode = logindata.getString('referalcode')!;
token = logindata.getString('token')!;
setState(() {});
}
List<Team> teams = [];
Future getData() async {
var response = await http.get(Uri.https(
'incoming.isplitpay.com', 'api/durationlist', {'token': token}));
var jsonData = jsonDecode(response.body);
print(token);
for (var eachTeam in jsonData) {
var datetime = DateTime.parse(eachTeam["paid_date"]);
final team = Team(
id_pes: eachTeam['id_pes'],
amount: eachTeam['amount'],
paid_date: datetime,
);
teams.add(team);
}
// print(teams.length);
}
#override
void initState() {
super.initState();
userData();
}
#override
Widget build(BuildContext context) {
//getData();
return Scaffold(
backgroundColor: Colors.blue.shade50,
body: FutureBuilder(
future: getData(),
builder: ((context, snapshot) {
//if done loading show data
if (snapshot.connectionState == ConnectionState.done) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
itemCount: teams.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 80,
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
),
color: Colors.grey[50],
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Checkbox(
checkColor: Colors.white,
value: _isChecked,
onChanged: (bool? value) {
setState(() {
_isChecked = value!;
});
print(value);
},
),
Text(
'GHS ' + teams[index].amount,
style: GoogleFonts.lato(
fontSize: 16,
),
),
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
'Savings for',
style: GoogleFonts.lato(
fontSize: 16,
),
),
),
Text(
"${teams[index].paid_date.day.toString().padLeft(2, '0')}-${teams[index].paid_date.month.toString().padLeft(2, '0')}-${teams[index].paid_date.year}",
style: GoogleFonts.lato(
fontSize: 16,
),
),
],
)
],
),
),
);
}),
);
//else show circule progress bar
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
),
);
}
}
My Model
import 'package:flutter/material.dart';
class Team {
final String id_pes;
final String amount;
final DateTime paid_date;
Team({
required this.id_pes,
required this.amount,
required this.paid_date,
});
}
class UserProgress {
final int goaldays;
final double progress;
UserProgress({
required this.goaldays,
required this.progress,
});
}
You can add a variable inside the Class Team to control the CheckBox.
The checked list can be filtered out through the List.where() function.
I added the Tooltip() Widget to show the expected effect.
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Team> dataList = [
Team(id_pes: '1', amount: '10', paid_date: DateTime.now()),
Team(id_pes: '2', amount: '20', paid_date: DateTime.now()),
Team(id_pes: '3', amount: '30', paid_date: DateTime.now()),
Team(id_pes: '4', amount: '40', paid_date: DateTime.now()),
Team(id_pes: '5', amount: '50', paid_date: DateTime.now()),
Team(id_pes: '6', amount: '60', paid_date: DateTime.now()),
];
Widget _buildListItem(int index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 80,
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
),
color: Colors.grey[50],
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Checkbox(
checkColor: Colors.white,
value: dataList[index].isChecked ?? false,
onChanged: (bool? value) {
setState(() {
dataList[index].isChecked = value;
});
print(value);
},
),
Text(
'GHS ' + dataList[index].amount,
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
var checkedList = dataList.where((data) => data.isChecked ?? false);
var totalAmount = checkedList.isNotEmpty
? 'TotalAmount:${checkedList.reduce((before, after) => Team(amount: '${double.parse(before.amount) + double.parse(after.amount)}', id_pes: '_', paid_date: DateTime.now())).amount} '
: '';
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: dataList.length,
itemBuilder: (context, index) {
return Tooltip(
message: totalAmount, child: _buildListItem(index));
}));
}
}
class Team {
final String id_pes;
final String amount;
final DateTime paid_date;
bool? isChecked;
Team({
required this.id_pes,
required this.amount,
required this.paid_date,
this.isChecked,
});
}

Unhandled Exception: Converting object to an encodable object failed: Instance of 'Athlete'

I'm trying to send to my POST Http request a json array as body but it throws this error:
Unhandled Exception: Converting object to an encodable object failed: Instance of 'Athlete'
I want to pass an array with only three parameters of my Athlete model to the post request.
Can you help me figure out how I can do that?
My model
List<Athlete> athleteFromJson(String str) =>
List<Athlete>.from(json.decode(str).map((x) => Athlete.fromJson(x)));
String athleteToJson(List<Athlete> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Athlete {
Athlete(
{required this.id,
required this.firstName,
required this.lastName,
required this.fatherName,
required this.currentMonthPresences,
this.isSelected = false,
required this.hasDebt,
this.department,
this.teamKey});
late int id;
late String firstName;
late String lastName;
late String fatherName;
late int currentMonthPresences;
bool isSelected = false;
late bool hasDebt;
final Department? department;
final TeamKey? teamKey;
factory Athlete.fromJson(Map<String, dynamic> json) => Athlete(
id: json['id'],
firstName: json['firstName'],
lastName: json['lastName'],
fatherName: json['fatherName'],
currentMonthPresences: json['currentMonthPresences'],
hasDebt: json['hasDebt'],
department: Department.fromJson(json["department"]),
teamKey: TeamKey.fromJson(json["team"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"firstName": firstName,
"lastName": lastName,
"fatherName": fatherName,
"currentMonthPresences": currentMonthPresences,
"hasDebt": hasDebt,
"department": department?.toJson(),
"teamKey": teamKey?.toJson(),
};
Athlete.newSelectedAthlete(this.id, this.department, this.teamKey);
}
The screen where I send the array to POST request
class SelectedAthletes extends StatefulWidget {
const SelectedAthletes({Key? key}) : super(key: key);
static const routeName = '/selectedAthletes';
#override
State<SelectedAthletes> createState() => _SelectedAthletesState();
}
class _SelectedAthletesState extends State<SelectedAthletes> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as List<Athlete>;
return Scaffold(
body: Stack(
children: [
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ListView.builder(
shrinkWrap: true,
cacheExtent: 34,
primary: true,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.only(
top: 10,
bottom: 56,
),
itemCount: args.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'ID: ${args[index].id}',
style: const TextStyle(
color: Colors.blue, fontSize: 14),
),
],
),
Row(
children: [
Flexible(
child: Text(
'${args[index].lastName} ${args[index].firstName}',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Cera',
fontWeight: FontWeight.bold,
fontSize: 18),
),
),
],
),
],
));
},
)
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
height: 60,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
disabledBackgroundColor: Colors.grey),
onPressed: () async {
ApiService.insertPresences(getJsonArray(args));
},
child: const Center(
child: Text(
'SEND',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 18),
),
),
),
),
),
],
));
}
String getJsonArray(List<Athlete> args) {
var selectedAthletes = <Athlete>[];
for (int i = 0; i < args.length; i++) {
Athlete sa = Athlete.newSelectedAthlete(
args[i].id, args[i].department, args[i].teamKey);
selectedAthletes.add(sa);
}
var jsonExport = json.encode(selectedAthletes);
print(jsonExport);
return jsonExport;
}
}
My POST request
static Future<Athlete?> insertPresences(String getJson) async {
try {
final response = await http.post(
Uri.parse('$uri/insert-presences'),
headers: <String, String>{
'Authorization': 'Basic ...',
'Content-Type': 'application/json; charset=UTF-8',
'Accept': 'application/json'
},
body: json.encode([
{
"getJson": getJson
}
]),
);
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
if (response.statusCode == 200) {
print("status 200");
return null;
} catch (e) {
logger.e(e.toString());
}
return null;
}
My raw body in POSTMAN
[
{
"athleteId" : "16198",
"departmentId":"3",
"teamId":"278"
}
]
It is probably because of your models toJson method, it should look like this
class Athlete {
String? athleteId;
String? departmentId;
String? teamId;
Athlete({this.athleteId, this.departmentId, this.teamId});
Athlete.fromJson(Map<String, dynamic> json) {
athleteId = json['athleteId'];
departmentId = json['departmentId'];
teamId = json['teamId'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['athleteId'] = this.athleteId;
data['departmentId'] = this.departmentId;
data['teamId'] = this.teamId;
return data;
}
}

How can I map a JSON map to single key multiple values

This might be a bit of broad question.
I have an JSON Map Array which i can parse normally. But i would like to MAP multiple Values to a Single key. I am stuck and unsure how to proceed.
My JSON output. I cannot change this.
{
"pos":"1",
"element":"37542",
"title":"Easy On Me",
"inter":"Adele",
"isnew":"0"
},
{
"pos":"66",
"element":"37183",
"title":"Send My Love",
"inter":"Adele",
"isnew":"0"
}
this is just a snippet of the actual JSON objects
what I would like to do is something like Map<String,List<String,String>>
Adele
Easy On Me, 37542
Send My Love, 37183
Searching online I find a lot of examples how to parse JSON normally, but never found a version where you can iterate through a JSON version like above and pull parts of the map out and add it to another.
any help would be appreciated. Thank you in advance
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
class SongList {
final List<Song> songs;
SongList({
required this.songs,
});
factory SongList.fromJson(List<dynamic> parsedJson) {
List<Song> songs = <Song>[];
songs = parsedJson.map((i) => Song.fromJson(i)).toList();
return SongList(songs: songs);
}
}
class Song {
final String? pos;
final String? element;
final String? title;
final String? inter;
final String? isnew;
const Song(
{required this.pos,
required this.element,
required this.title,
required this.inter,
required this.isnew});
factory Song.fromJson(Map<String, dynamic> data) {
return Song(
pos: data['pos'] as String?,
element: data['element'] as String?,
title: data['title'] as String?,
inter: data['inter'] as String?,
isnew: data['isnew'] as String?,
);
}
}
import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
class Songs extends StatefulWidget {
final String pos;
final String element;
final String title;
final String inter;
final String isnew;
const Songs(
{super.key,
required this.pos,
required this.element,
required this.title,
required this.inter,
required this.isnew});
#override
State<Songs> createState() => _SongsState();
}
class _SongsState extends State<Songs> {
late AudioPlayer player;
#override
void initState() {
super.initState();
player = AudioPlayer();
}
#override
void dispose() {
player.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var titles = Row(
mainAxisSize: MainAxisSize.min,
children: [
Column(children: [
SizedBox(
height: 25,
width: 200,
child: Text(
widget.title,
style: const TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 25,
width: 200,
child: Text(
widget.inter,
style: const TextStyle(fontSize: 10),
textAlign: TextAlign.center,
),
),
]),
],
);
return FittedBox(
fit: BoxFit.contain,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Center(
child: SizedBox(
height: 50,
width: 50,
child: Align(
alignment: Alignment.center,
child: widget.isnew != "1"
? Text(
widget.pos.toString(),
textAlign: TextAlign.center,
)
: const Text(
"new",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.red),
)))),
],
),
Column(
children: [
SizedBox(
height: 50,
width: 50,
child: Image.network(
'${'http://www.example.com/${widget.element}'}.jpg'),
),
],
),
Column(
children: [
titles,
],
),
Column(
children: [
SizedBox(
height: 50,
width: 50,
child: TextButton(
onPressed: () async {
final url =
'${'http://www.example.com/${widget.element}'}.mp3';
await player.setUrl(url);
player.play();
},
child: Image.asset('assets/images/btn_play.png'),
),
),
],
),
Column(
children: [
SizedBox(
height: 50,
width: 50,
child: TextButton(
// ignore: avoid_print
onPressed: () =>
print('pressed button download!! ${widget.element}'),
child: Image.asset('assets/images/btn_download.png'),
),
),
],
),
],
)));
}
}
Future<SongList> fetchSong() async {
final response = await http
.get(Uri.parse('http://example.com'));
if (response.statusCode == 200) {
return SongList.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to Load Songs');
}
}
//snippet from class that instatiates
late Future<SongList> futureSong;
#override
void initState() {
super.initState();
futureSong = fetchSong();
}
//snippet from class that builds the list
FutureBuilder<SongList>(
future: futureSong,
builder: (context, AsyncSnapshot<SongList> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.songs.length,
itemBuilder: (context, index) {
if (snapshot.data!.songs[index].element.toString() !=
"null") {
return Songs(
element:
snapshot.data!.songs[index].element.toString(),
inter: snapshot.data!.songs[index].inter.toString(),
isnew: snapshot.data!.songs[index].isnew.toString(),
pos: snapshot.data!.songs[index].pos.toString(),
title: snapshot.data!.songs[index].title.toString());
} else {
return const SizedBox(height: 0);
}
});
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
}
This might work:
void main() {
var data=[
{
"pos":"1",
"element":"37542",
"title":"Easy On Me",
"inter":"Adele",
"isnew":"0"
},
{
"pos":"66",
"element":"37183",
"title":"Send My Love",
"inter":"Adele",
"isnew":"0"
},
{
"pos":"80",
"element":"5000",
"title":"Enjoy the silence",
"inter":"Depeche Mode",
"isnew":"0"
},
{
"pos":"100",
"element":"6000",
"title":"In your room",
"inter":"Depeche Mode",
"isnew":"0"
}
];
var result = <String,List<Map<String,String>>>{};
for (var d in data) {
print(d);
var e={"element":d["element"]!, "title": d["title"]!};
var key=d["inter"]!;
if (result.containsKey(key)) {
result[key]!.add(e);
} else {
result[key]=[e];
}
}
print(result);
}
You can achieve this by creating a subclass.
Interpret interpretFromJson(String st) => Interpret.fromJson(json.decode(st));
class Interpret{
Interpret({
required this.name,
required this.titles,
});
final String name;
final List<Title> titles;
factory Interpret.fromJson(Map<String, dynamic> json) => Title(
name: json["inter"],
titles: List<Title>.from(json.map((x) => Title.fromJson(x))),
);
}
class Title {
Title({
required this.name,
required this.element,
});
final String name;
final double element;
factory Title.fromJson(Map<String, dynamic> json) => Title(
name: json["name"],
element: json["element"],
);
Then you can just call it like.
InterpretFromJson(json);

How to do infinite scrolling in flutter?

I want to scroll infinitely as much my product has. I have total 412 pages. When I scroll to the end I want to show more item of next pages. that means infinite scrolling. how to do this? i have implemented the ScrollController.
this is my Api:
https://www.moharaj.com.bd/api/new/collection/products?page=1
this is my model class:
// To parse this JSON data, do
//
// final newCollectionProductModel = newCollectionProductModelFromJson(jsonString);
import 'dart:convert';
NewCollectionProductModel newCollectionProductModelFromJson(String str) =>
NewCollectionProductModel.fromJson(json.decode(str));
String newCollectionProductModelToJson(NewCollectionProductModel data) =>
json.encode(data.toJson());
class NewCollectionProductModel {
NewCollectionProductModel({
required this.currentPage,
required this.data,
required this.firstPageUrl,
required this.from,
required this.lastPage,
required this.lastPageUrl,
required this.nextPageUrl,
required this.path,
required this.perPage,
required this.prevPageUrl,
required this.to,
required this.total,
});
final int currentPage;
final List<Datum> data;
final String firstPageUrl;
final int from;
final int lastPage;
final String lastPageUrl;
final String nextPageUrl;
final String path;
final int perPage;
final dynamic prevPageUrl;
final int to;
final int total;
factory NewCollectionProductModel.fromJson(Map<String, dynamic> json) =>
NewCollectionProductModel(
currentPage: json["current_page"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
firstPageUrl: json["first_page_url"],
from: json["from"],
lastPage: json["last_page"],
lastPageUrl: json["last_page_url"],
nextPageUrl: json["next_page_url"],
path: json["path"],
perPage: json["per_page"],
prevPageUrl: json["prev_page_url"],
to: json["to"],
total: json["total"],
);
Map<String, dynamic> toJson() => {
"current_page": currentPage,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"first_page_url": firstPageUrl,
"from": from,
"last_page": lastPage,
"last_page_url": lastPageUrl,
"next_page_url": nextPageUrl,
"path": path,
"per_page": perPage,
"prev_page_url": prevPageUrl,
"to": to,
"total": total,
};
}
class Datum {
Datum({
required this.id,
required this.name,
required this.price,
required this.salePrice,
required this.slug,
required this.discount,
required this.thumnail,
required this.productImage,
});
final int id;
final String name;
final String price;
final String salePrice;
final String slug;
final int discount;
final String thumnail;
final List<ProductImage> productImage;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
id: json["id"],
name: json["name"],
price: json["price"],
salePrice: json["sale_price"],
slug: json["slug"],
discount: json["discount"],
thumnail: json["thumnail"],
productImage: List<ProductImage>.from(
json["product_image"].map((x) => ProductImage.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"price": price,
"sale_price": salePrice,
"slug": slug,
"discount": discount,
"thumnail": thumnail,
"product_image":
List<dynamic>.from(productImage.map((x) => x.toJson())),
};
}
class ProductImage {
ProductImage({
required this.id,
required this.productId,
required this.productImage,
required this.createdAt,
required this.prefixUrl,
required this.updatedAt,
});
final int id;
final int productId;
final String productImage;
final DateTime createdAt;
final String prefixUrl;
final DateTime updatedAt;
factory ProductImage.fromJson(Map<String, dynamic> json) => ProductImage(
id: json["id"],
productId: json["product_id"],
productImage: json["product_image"],
createdAt: DateTime.parse(json["created_at"]),
prefixUrl: json["prefix_url"],
updatedAt: DateTime.parse(json["updated_at"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"product_id": productId,
"product_image": productImage,
"created_at": createdAt.toIso8601String(),
"prefix_url": prefixUrl,
"updated_at": updatedAt.toIso8601String(),
};
}
this is my Service class Code:
import 'dart:convert';
import 'package:infinite_pagination/NewArrival.dart';
import 'package:infinite_pagination/NewCollectionProductModel.dart';
import 'package:http/http.dart' as http;
/**
* This is a Service Class.
* This Service Class is used for New COllection Product.
*
*/
class NewCollectionProductService {
static var product;
static Future<NewCollectionProductModel>
getNewCollectionProductService() async {
try {
final response = await http.get(Uri.parse(
"https://www.moharaj.com.bd/api/new/collection/products?page=$pageNumber"));
//print(response);
if (response.statusCode == 200 || response.statusCode == 201) {
final decode = jsonDecode(response.body);
product = NewCollectionProductModel.fromJson(decode);
return product;
} else {
return product;
}
} catch (error) {
throw Exception();
}
}
}
this is product Class:
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
var size = 180.0;
var iconSize = 10.0;
Widget Products(String ImgLocation, name, price, discountPrice, discountPercent,
reviews, BuildContext context) {
return Container(
height: 300,
child: Card(
child: Padding(
padding: EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
'$ImgLocation',
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
return loadingProgress == null
? child
: Center(
child: LinearProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
));
// : LinearProgressIndicator();
},
width: MediaQuery.of(context).size.width,
height: size,
),
),
),
Text(
'$name',
textAlign: TextAlign.start,
),
Text(
'৳ $price',
style: TextStyle(
fontSize: 15,
color: Colors.red,
fontWeight: FontWeight.bold),
textAlign: TextAlign.left,
),
Text.rich(
TextSpan(
children: <TextSpan>[
// ignore: unnecessary_new
TextSpan(
text: '৳ $discountPercent',
style: const TextStyle(
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
),
TextSpan(
text: ' -$discountPrice%',
),
],
),
),
Row(
children: [
Icon(
Icons.star,
color: Color(0xFFFfebf50),
size: iconSize,
),
Icon(
Icons.star,
color: Color(0xFFFfebf50),
size: iconSize,
),
Icon(
Icons.star,
color: Color(0xFFFfebf50),
size: iconSize,
),
Icon(
Icons.star,
color: Color(0xFFFfebf50),
size: iconSize,
),
Icon(
Icons.star,
color: Color(0xFFFfee9c3),
size: iconSize,
),
SizedBox(
width: 5,
),
Text(
'($reviews)',
style: TextStyle(fontSize: iconSize),
)
],
)
],
)),
),
);
}
this is my home page:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:infinite_pagination/NewArrivalController.dart';
import 'package:infinite_pagination/NewCollectionProductModel.dart';
import 'package:infinite_pagination/NewCollectionProductService.dart';
import 'package:infinite_pagination/Products.dart';
//------------------------------------------------------------
// this widget is for Upcoming categories
//------------------------------------------------------------
class NewArrival extends StatefulWidget {
#override
State<NewArrival> createState() => _NewArrivalState();
}
var pageNumber = 1;
class _NewArrivalState extends State<NewArrival> {
NewArrivalController newArrivalController = Get.put(NewArrivalController());
late Future<NewCollectionProductModel> getData;
ScrollController scrollController = ScrollController();
#override
void initState() {
getData = NewCollectionProductService.getNewCollectionProductService();
// TODO: implement initState
super.initState();
scrollController.addListener(() {
print(scrollController.position.pixels);
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
pageNumber++;
print(pageNumber);
}
});
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
scrollController.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('New Arrival',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
)),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: MaterialButton(
color: Colors.red,
child: Text("View All"),
onPressed: () {}),
)
],
),
Container(
// height: 200,
child: collectionOfData())
],
),
),
),
);
}
collectionOfData() {
return FutureBuilder<NewCollectionProductModel>(
future: getData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
controller: scrollController,
physics: NeverScrollableScrollPhysics(),
// scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: snapshot.data!.data.length,
// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 2),
itemBuilder: (context, int index) {
var product = snapshot.data!.data[index];
//slug = product.slug;
String image = product.productImage[0].prefixUrl.toString() +
product.productImage[0].productImage.toString();
return GestureDetector(
onTap: () {},
child: Container(
height: 300,
width: 200,
child: Products(
image,
product.name,
product.price,
product.discount,
product.salePrice,
product.id,
context,
),
),
);
});
} else {
return Center(child: CircularProgressIndicator());
}
});
}
}
you can manage in 2 ways.
without package: manage scrolling point & total page, current page & per page items.
using pagination_view and other packages.
you can also check the below links.
raywenderlich-pagination
mobikul-pageination
stack-overfllow-query
Simple Example without packages:
Declare the below code initially.
ScrollController _scrollController = new ScrollController();
var pageNumber = 1;// update in API CALL
total_page = 0; // update in API CALL
current_page = 0; // update in API CALL
List<ModelClass> arrList = [];
Add below code init method
_scrollController.addListener(() async {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
if (currentPage != total) { // on bottom scroll API Call until last page
currentPage += 1;
apiCall(page: currentPage);
}
}
});
If No data is found & add Pull to refresh widget.
Widget noDataFound() {
return RefreshIndicator(
onRefresh: apiCall(),
child: Center(
child: Text('No Data Found!'),
),
);
}
in Build Widget
arrList.isNotEmpty ? ListView.separated(
padding: const EdgeInsets.all(16.0),
separatorBuilder: (c, index) {
return SizedBox(
height: 20.0,
);
},
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
itemCount: arrList.size + 1,
itemBuilder: (_, index) {
if (index == arrList.length) { // Always one widget 'Loading...' added end of list it will Hide/Show based on condtion.
return Visibility(
visible:
current_page != totalPage ? false:true,
child: Center(
child: Text('Loading...',),
);
} else {
return ... listViewItemWidget;
}
}) : noDataFound()
API Call Function
apiCall(int page = 0){
// update all pagenation variables After API get & map data sucessfully
currentPage , Total page , list value
// Add one condition to store data
if (page == 0) { // If Pull to refresh.
arrList.clear();
arrList = [mapData list from API]; // New data load.
} else {
arrList.add([mapData list from API]); // Append new data in old list
}
}
You can look at the infinite_scroll_pagination package
You can use custom ScrollController to listen when to load more items:
import 'package:flutter/widgets.dart';
class InfiniteListenerController extends ScrollController {
final VoidCallback? onLoadMore;
InfiniteListenerController({this.onLoadMore}) {
if(onLoadMore != null) addListener(_endListener);
}
void _endListener() {
if (position.pixels == position.maxScrollExtent) {
onLoadMore?.call();
}
}
#override
void dispose() {
if(onLoadMore != null) removeListener(_endListener);
super.dispose();
}
}

How to filter list item in getx

I have a to-do app, where I have a list of items with scheduled date and time, title, details, and task done or not. I want to filter the list of todos depending on if its done or not done, How do I implement this in the getx Controller.
Model:
class Todo {
String title;
String details;
String? date;
String? time;
bool done;
bool dateAndTimeEnabled;
int id;
Todo(
{required this.title,
required this.details,
required this.date,
required this.time,
this.dateAndTimeEnabled = true,
required this.id,
this.done = false});
factory Todo.fromJson(Map<String, dynamic> json) => Todo(
id: json['id'],
title: json['title'],
details: json['details'],
done: json['done'],
date: json['date'],
time: json['time'],
dateAndTimeEnabled: json['dateAndTimeEnabled']);
Map<String, dynamic> toJson() => {
'id': id,
'title': title,
'details': details,
'done': done,
'date': date,
'time': time,
'dateAndTimeEnabled': dateAndTimeEnabled
};
}
Getx controller:
class TodoController extends GetxController {
var todos = <Todo>[].obs;
#override
void onInit() {
List? storedTodos = GetStorage().read<List>('todos');
if (storedTodos != null) {
todos.assignAll(storedTodos.map((e) => Todo.fromJson(e)).toList());
}
ever(todos, (_) {
GetStorage().write('todos', todos.toList());
});
super.onInit();
}
}
Update
#override
void initState() {
todoController.getDoneTodos();
super.initState();
}
GestureDetector(
onTap: () {
Get.to(() => const doneTodos());
},
child: Padding(
padding: const EdgeInsets.only(top: 20.0, left: 14.0, right: 12.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('${todoController.doneTodos.length}', style: Theme.of(context).textTheme.headline1,),
Text("Done", style: Theme.of(context).textTheme.headline1)
],),
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
height: 138.0,
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
boxShadow: [
BoxShadow(
color: Theme.of(context).shadowColor,
offset: const Offset(2.5, 2.5),
blurRadius: 5.0,
spreadRadius: 1.0,
),
],
borderRadius:
BorderRadius.circular(14.0))
),
),
),
I tried to wrap the Text widget with Obx but it throws this error: FlutterError (setState() or markNeedsBuild() called during build.
In your controller:
var doneTodos = <Todo>[].obs;
getDoneTodos(){
doneTodo.assignAll(todos.where(element)=>element.done == true).toList());
}