I am trying to read data from postgresql, display in listview, select (single/multiple) displayed items and process further. Able to do with sample data but while displaying data from Postgres DB facing challenges at highlighted area. Any suggestions would be appreciated.
(I am trying to read data from postgresql, display in listview, select (single/multiple) displayed items and process further. Able to do with sample data but while displaying data from Postgres DB facing challenges at highlighted area. Any suggestions would be appreciated.)
**app_db.dart**
import 'package:postgres/postgres.dart';
class AppDatabase {
PostgreSQLConnection? connection;
PostgreSQLResult? _fetchSellerDataResult;
AppDatabase() {
connection = (connection == null || connection!.isClosed == true
? PostgreSQLConnection("10.0.2.2", 5432, "dev", username: "postgres", password: "admin")
: connection);
fetchDataFuture = [];
}
// Fetch Data Section
List<dynamic> fetchDataFuture = [];
Future<List<dynamic>> fetchSellerData() async {
try {
await connection!.open();
await connection!.transaction((fetchDataConn) async {
_fetchSellerDataResult = await fetchDataConn.query(
"select cust_id, cust_name, mmt, available_amount, false AS isSelected from api_positionstest2",
allowReuse: false,
timeoutInSeconds: 30,
);
if (_fetchSellerDataResult!.affectedRowCount > 0) {
fetchDataFuture = _fetchSellerDataResult!.toList(growable: true);
} else {
fetchDataFuture = [];
} });
} catch (exc) {
fetchDataFuture = [];
exc.toString();
}
return fetchDataFuture;
}}
**model_positions.dart**
import 'package:e2/Models/app_db.dart';
class ModelsPositions {
List<dynamic> sellerDataFuture = [];
Future<List<dynamic>> fetchSellerData() async {
sellerDataFuture = await AppDatabase().fetchSellerData();
return sellerDataFuture;
}}
**MasterPositions.dart**
class MasterPositions {
String custID;
String custName;
double mtm;
double availableCash;
bool isSelected = false;
MasterPositions(
{required this.custID,
required this.custName,
required this.mtm,
required this.availableCash});}
**master_control.dart**
import 'package:flutter/material.dart';
import 'package:e2/Models/model_positions.dart';
class MasterControl extends StatefulWidget {
const MasterControl({super.key});
#override
State<MasterControl> createState() => _MasterControlState();
}
class _MasterControlState extends State<MasterControl> {
List<MasterPositions> selectedContacts = [];
List<MasterPositions> fetchedPositions = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => Scaffold(
body: FutureBuilder<List<dynamic>>(
future: ModelsPositions().fetchSellerData(),
builder: (context, snapshot) {
final positions = snapshot.data ?? [];
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return Center(child: Text('Error while loading Master Positions screen'));
} else {
return buildPositions(positions);
} } }), );
Widget buildPositions(List<dynamic> positions) {
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: positions.length,
itemBuilder: (context, index) {
final pos = positions[index];
final custID = pos.elementAt(0).toString();
final custName = pos.elementAt(1).toString();
final mtm = double.tryParse(pos.elementAt(2)) ?? 0.0;
final availableCash = double.tryParse(pos.elementAt(3)) ?? 0.0;
final isSelected = pos.elementAt(4);
return ListTile(
horizontalTitleGap: -5,
title: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(custID),
const SizedBox(height: 5),
Text(custName)],),),],),),
leading: isSelected
? Icon( Icons.check_circle, color: Colors.green[700],)
: const Icon(Icons.check_circle_outline, color: Colors.grey,),
onTap: () {
setState(() {
positions[index].elementAt(4) = !positions[index].elementAt(4); `**--> suggestion needed here**`
if (positions[index] == true) {
selectedContacts.add(
MasterPositions(custID: custID, custName: custName, mtm: mtm, availableCash: availableCash));
} else if (positions[index] == false) {
selectedContacts.removeWhere(
(element) => element.custID == pos[index].custID);
}}); }, );});}
}
Related
I have two widgets that both use the same Future to display CircularProgressIndicators and then show the widget once the future completes. But the CircularProgressIndicators do not animate, so they are just small squares. They animate the very first time after a full compile, but they do not animate ever again, not even after an app refresh. I have tried with other animating widgets to confirm, and they are indeed static:
#override
Widget build(BuildContext context) {
_mapLoadedNotifier = ref.read(mapLoadedProvider.notifier);
_mapLoaded = ref.watch(mapLoadedProvider);
theVm = ref.watch(searchPageVmProvider);
return Row(children: [ _mapOverlay(),_mapWidget(),]);
}
Widget _mapOverlay() {
return theVm.when(
data: (store) {
vm = store;
if (!vm!.hasSearched) {
vm!.isMapLoading = true;
}
vm!.ref = ref;
return SearchFormBuilder(
initState: vm!.initState,
model: Search(search: SearchByTermSuggestion('')),
builder: (context, formModel, child) {
return Container(
padding: PAD_M_TOP,
alignment: Alignment.topLeft,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: PAD_M),
width: sizingInfo.maxWidthS,
color: Colors.transparent,
child: VpCombinationAutocompleteField(
formControl: formModel.searchControl,
labelText: '',
hintText: 'Search',
widgetRef: vm!.ref!,
widgetOnSuggestionSelected:
(Suggestion suggestion) =>
suggestion.onSelected())));
});
},
error: (error, s) => Text(error.toString()),
loading: () {
return const Center(
child: SizedBox(
height: 30,
width: 30,
child: Center(child: CircularProgressIndicator())),
);
});
}
Widget _mapWidget() {
return FutureBuilder<SearchPageVm>(
future: ref.watch(searchPageVmProvider.future),
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: SizedBox(
height: 30,
width: 30,
child: Center(child: CircularProgressIndicator())),
);
}
vm = snapshot.data;
return StreamBuilder<dynamic>(
stream: vm!.map$,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
vm!.vpMap = snapshot.data;
if (!vm!.hasSearched) {
vm!.isMapLoading = true;
}
vm!.ref = ref;
}
return _googleMap(vm!);
});
}));
}
When I remove the StreamBuilder, they both animate correctly. This does not appear to be a riverPod issue, since I have tried plain Flutter FutureBuilders and it has the same issue. I've tried so many alternatives. The StreamBuilder stops the FutureBuilders CircularProgressIndicators from animating. Why?
It is the same issue as here:
Flutter CircularProgressIndicator() animation is not working inside Riverpod`s ref.watch().when
The provider:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:vepo/src/_common/extensions/vegan_item_establishments.dart';
import '../../../_common/constants/presentation/colors.dart';
import '../../../_common/enums/vegan_item_type.dart';
import '../../../_common/services/theme_mode.dart';
import '../../../_common/services/user.dart';
import '../../../application/local/form_capabilities.dart';
import '../../../application/local/map_data/map.dart';
import '../../../application/local/suggestion/search_by_term/search_by_term_suggestion.dart';
import '../../../application/search_params/vegan_item/vegan_item_search_params.dart';
import '../../../domain/vegan_item_establishment/_common/vegan_item_establishment.dart';
import 'search.dart';
import 'search_results_provider.dart';
final searchPageVmProvider = FutureProvider<SearchPageVm>((ref) async {
final userWithLocation = await ref.watch(userWithLocationProvider.future);
final vm = SearchPageVm(
userWithLocation: userWithLocation,
);
vm.search();
return vm;
});
class SearchPageVm {
bool hasSearched = false;
late GoogleMap? googleMapWidget;
bool isMapLoading = true;
VpMap? vpMap;
WidgetRef? ref;
ThemeMode? themeMode;
Color? statusBarColor;
String? searchText;
Stream<VpMap>? map$;
late final StreamController<VpMap> mapController =
StreamController.broadcast();
late UserWithLocation _userWithLocation;
Set<Marker> markers = <Marker>{};
Stream<String?>? searchTerm;
GoogleMapController? googleMapController;
SearchPageVm({required UserWithLocation userWithLocation}) {
map$ = mapController.stream;
_userWithLocation = userWithLocation;
}
#override
Search get model => Search(search: SearchByTermSuggestion(''));
Position get userPosition => _userWithLocation.userPosition;
/// Add an array of search results to the map
void addResults(Iterable<VgnItmEst> searchResults) {
mapController.add(VpMap(
position: _userWithLocation.userPosition,
markers: searchResults.markers));
_animateCamera(searchResults);
}
#override
void initState(BuildContext context, SearchForm formModel, [dynamic args]) {
if (!hasSearched) {
search();
hasSearched = true;
}
themeMode = ref?.read(themeModeServiceProvider);
statusBarColor = themeMode == ThemeMode.light
? BACKGROUND_COLOR
: DARK_THEME_BACKGROUND_COLOR_LIGHT;
}
/// Search for results and add them to the map
Future<List<VgnItmEst>?> search(
{String searchTerm = '', VgnItmType? category}) async {
final searchResults =
await _search(searchTerm: searchTerm, category: category);
addResults(searchResults ?? []);
return searchResults;
}
void _animateCamera(Iterable<VgnItmEst> searchResults) {
googleMapController?.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(
searchResults.first.establishment!.location!.latitude,
searchResults.first.establishment!.location!.longitude),
zoom: 13)));
}
Future<List<VgnItmEst>?> _search(
{required String searchTerm, VgnItmType? category}) async {
final result = await ref?.watch(searchResultsProvider(VgnItmSearchParams(
searchTerm: searchTerm,
page: 1,
pageSize: 10,
vgnItmDiscriminators: category != null ? [category.name] : null))
.future);
return result;
}
}
final searchResultsProvider =
FutureProvider.family<List<VgnItmEst>, VgnItmSearchParams>(
(ref, searchParams) async {
List<VgnItmEst>? searchResults;
final allVgnItmsGooglePlacesRepo = ref.read(allVgnItmEstsRepoProvider);
searchResults = (await allVgnItmsGooglePlacesRepo.search(searchParams))?.data;
return searchResults!;
});
Just Make your own progress dialog for just do single change and change will reflect whole code.
class ProgressBar extends StatelessWidget {
final Color color;
ProgressBar({this.color = Colors.amber});
Widget build(BuildContext context) {
return Center(
child: SizedBox(
height: 40,
width: 40,
child: CircularProgressIndicator(color:color))
);}
The way you handle different state of your FutureBuilder is wrong, also when you use FutureBuilder, you should use ref.read, you need to change your _mapWidget to this:
Widget _mapWidget() {
return FutureBuilder<SearchPageVm>(
future: ref.read(searchPageVmProvider.future), // <=== change this
builder: (context, snapshot) { // <=== change this
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const Center(
child: SizedBox(
height: 30,
width: 30,
child: Center(child: CircularProgressIndicator())),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
vm = snapshot.data;
return StreamBuilder<dynamic>(
stream: vm!.map$,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
vm!.vpMap = snapshot.data;
if (!vm!.hasSearched) {
vm!.isMapLoading = true;
}
vm!.ref = ref;
}
return _googleMap(vm!);
});
}
}
});
}
I am new to Flutter and am currently working on a Flutter app that downloads files from given links. The issue is that when only one link app is working fine but when more than one link arrive file does not download. I receive the link data in json file then I parsed the json and used these links inside the listview.builder. I tried very much but could not find the solution. Here is the code for the screen. Main issue is that I think state is not managed well.
dsharing.json file contain name and links of files
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import '../services/services.dart';
class ReceiveScreen extends StatefulWidget {
const ReceiveScreen({Key? key, }) : super(key: key);
#override
State<ReceiveScreen> createState() => _ReceiveScreenState();
}
class _ReceiveScreenState extends State<ReceiveScreen> {
Map<int, double> progress = {};
int received = 0;
int total = 0;
var _url = "http://192.168.1.100:50500";
List<Receiver> receivers = [];
#override
initState()
{
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Receive Files"),
) ,
body: Column(
children: [
ElevatedButton(
onPressed: ()async
{
await getUrls();
},
child: const Text("Get Response")
),
Text(rsponse),
FutureBuilder(
future: getUrls(),
builder: (context, AsyncSnapshot<Files> snapshot)
{
if(!snapshot.hasData)
{
return const Center(child: CircularProgressIndicator());
}
Files files = snapshot.data!;
return ListView.builder(
itemCount: files.names!.length,
shrinkWrap: true,
itemBuilder: (context, index)
{
return Column(
children: [
ElevatedButton(
onPressed: () async
{
final path = "/storage/emulated/0/Download/${files.names![index]}";
await Dio().download(
files.urls![index],
path,
onReceiveProgress: (received, total)
{
progress[index] = received/total;
}
);
},
child: Text("${files.names![index] } Download")
),
LinearProgressIndicator(
value: progress[index],
minHeight: 20,
)
],
);
}
);
}
)
],
)
);
}
String rsponse = "";
fetchDataApi() async
{
var response = await get(Uri.parse("$_url/dsharing.json"));
if(response.statusCode == 200)
{
return jsonDecode(response.body);
}
}
Future<Files> getUrls() async
{
var data = await fetchDataApi();
return Files.fromJson(data, _url);
}
}
class Files
{
final List? names;
final List? urls;
Files({ this.names, this.urls});
factory Files.fromJson(Map map, String url)
{
var fileNames = [];
String name = map['name'];
if(name.contains(":"))
{
int index = name.indexOf(":") + 1;
name = name.substring(index + 1, name.length);
var x = name.replaceAll(" ", '^*&');
fileNames = x.split("^*&").toList();
}
else
{
fileNames.add(name);
}
var x = map['data'].toString().split("|dsharing|").toList();
var fileUrls = x.map((i) => url + "?/q="+ i).toList();
return Files(
names: fileNames,
urls: fileUrls
);
}
}
Hope Well,
I am using firebase realtime database on my flutter app (similar social media app). i have feed page and feed state page. i wanna show 10 posts first and after scroll bottom, load again 10 posts. i tried some methods but not working.
my codes
feed page code
Widget build(BuildContext context) {
var authstate = Provider.of<AuthState>(context, listen: false);
return Consumer<FeedState>(
builder: (context, state, child) {
final List<FeedModel> list = state.getPostList(authstate.userModel);
return CustomScrollView(
slivers: <Widget>[
child,
state.isBusy && list == null
? SliverToBoxAdapter(
child: Container(
height: fullHeight(context) - 135,
child: CustomScreenLoader(
height: double.infinity,
width: fullWidth(context),
backgroundColor: Colors.white,
),
),
)
: !state.isBusy && list == null
? SliverToBoxAdapter(
child: EmptyList(
'Follow someone',
subTitle:
'goto search page to find & follow Someone.\n When they added new post,\n they\'ll show up here.',
),
)
: SliverList(
delegate: SliverChildListDelegate(
list.map(
(model) {
return Container(
color: Colors.white,
child: Post(
model: model,
trailing: PostBottomSheet().PostOptionIcon(
context,
model: model,
type: PostType.Post,
scaffoldKey: scaffoldKey),
),
);
},
).toList(),
),
)
],
);
},
feed state code
List<FeedModel> get feedlist {
if (_feedlist == null) {
return null;
} else {
return List.from(_feedlist.reversed);
}
}
List<FeedModel> getPosttList(UserModel userModel) {
if (userModel == null) {
return null;
}
return feedlist;
}
I modified your code and use a ScrollController to load more data when the user reaches the end of the loaded data. (The data provider is hard-coded but you should be able to relate it to your scenario.) Note that I changed your code to use SliverChildBuilderDelegate which is more efficient.
import 'package:flutter/material.dart';
class ScrollTest extends StatefulWidget {
#override
_ScrollTestState createState() => _ScrollTestState();
}
class _ScrollTestState extends State<ScrollTest> {
bool isLoading = false;
bool isEnd = false;
final List<FeedModel> list = [];
ScrollController _controller;
_scrollListener() async {
var position = _controller.offset /
(_controller.position.maxScrollExtent -
_controller.position.minScrollExtent);
if (position > 0.5 && !_controller.position.outOfRange) {
await _getMoreData(list.length);
}
}
#override
void initState() {
super.initState();
_controller = ScrollController();
_controller.addListener(_scrollListener);
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
_getMoreData(list.length);
}
Future<void> _getMoreData(int index) async {
if (!isLoading) {
setState(() {
isLoading = true;
});
var tlist = await Feed.getPostList(index);
setState(() {
if (tlist.length == 0) {
isEnd = true;
} else {
list.addAll(tlist);
index = list.length;
}
isLoading = false;
});
}
}
#override
Widget build(BuildContext context) {
return CustomScrollView(
controller: _controller,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
color: Colors.white,
height: 300,
child: Text(list[index].text),
);
},
childCount: list.length,
),
),
SliverFillRemaining(
child: Center(
child: isEnd ? Text('End') : CircularProgressIndicator(),
)),
],
);
}
}
// Dummy FeedModel
class FeedModel {
final String text;
FeedModel(this.text);
}
// Dummy Feed provider
class Feed {
static final data = [
FeedModel('1'),FeedModel('2'),FeedModel('3'),FeedModel('4'),
FeedModel('5'),FeedModel('6'),FeedModel('7'),FeedModel('8'),
FeedModel('9'),FeedModel('10'),FeedModel('11'),FeedModel('12'),
FeedModel('13'),
];
static Future<List<FeedModel>> getPostList(int index) async {
List<FeedModel> l = [];
for (var i = index; i < index + 5 && i < data.length; i++) {
l.add(data[i]);
}
await Future.delayed(Duration(seconds: 1));
return l;
}
}
I'm new in flutter, I'd like to know how to add an item list dynamically to ListView without reloading data in FutureBuilder.
When I add an item to the ListView, it duplicate the list and then added the item to that list.
The Following code, include Model clas called Job.
JobListView is a stateful widget that include the dynamic ListView.
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class Job {
#required
String company;
String description;
String employmentType;
int id;
String location;
String position;
List<String> skillsRequired;
Job(
this.company,
this.description,
this.employmentType,
this.id,
this.location,
this.position,
this.skillsRequired);
Job.fromJson(Map<String, dynamic> json) {
company = json['company'];
description = json['description'];
employmentType = json['employmentType'];
id = json['id'];
location = json['location'];
position = json['position'];
if (json['skillsRequired'] != null) {
skillsRequired = new List<String>();
json['skillsRequired'].forEach((v) {
skillsRequired.add(v);
});
}
}
}
class JobListView extends StatefulWidget {
#override
_JobListViewState createState() => _JobListViewState();
}
class _JobListViewState extends State<JobListView> {
List<Job> data = List<Job>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Job>>(
future: _getJob(),
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
return _listViewFormat(data);
} else if (snapshot.hasError) {
return Container();
}
return Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
},
) ,
floatingActionButton: (FloatingActionButton(child: Icon(Icons.add),onPressed: (){
setState(() {
var j = Job("CompanyX","Eng.5 position","Full-time",0,"Cairo","Senior",null);
data.add(j);
});
},)),
);
}
}
ListView _listViewFormat(List<Job> data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(data[index].position, data[index].description, Icons.work);
});
}
ListTile _tile(String title, String subtitle, IconData iconData) {
return ListTile(
title: Text(title, style: TextStyle(fontSize: 20)),
subtitle: Text(
subtitle,
style: TextStyle(fontSize: 12),
),
leading: Icon(iconData),
trailing: Icon(Icons.arrow_right),
);
}
Future<List<Job>> _getJob() async {
String baseUrl = 'https://mock-json-service.glitch.me';
var response = await get(baseUrl);
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((job) => new Job.fromJson(job)).toList();
}
}
Check out this more explanation How to deal with unwanted widget build?
if future changes you will see changes
Move _getJob method inside initState like this:
class _JobListViewState extends State<JobListView> {
List<Job> data = List<Job>();
Future<List<Job>> getJobFuture;
#override
void initState() {
super.initState();
getJobFuture = _getJob();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Job>>(
future: getJobFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
return _listViewFormat(data);
} else if (snapshot.hasError) {
return Container();
}
return Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
},
) ,
floatingActionButton: (FloatingActionButton(child: Icon(Icons.add),onPressed: (){
setState(() {
var j = Job("CompanyX","Eng.5 position","Full-time",0,"Cairo","Senior",null);
data.add(j);
});
},)),
);
}
}
I am new to flutter and i current have an app that has a grid view that gets its list from an api. Some of the grid view items have child nodes in them, so what i want to achieve is to set a click function that checks if there is a child node and if that is true; i would want to re-populate the same grid view but with only members of the child node. is this possible in flutter?
import 'package:bringam/network/Models/ProductGroupModel.dart';
import 'package:bringam/network/sharedpreferences/SharedPreferences.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Product_Category extends StatefulWidget {
#override
_Product_CategoryState createState() => _Product_CategoryState();
}
class _Product_CategoryState extends State<Product_Category> {
Future<List<ProductGroupModel>> _getChildrenCategories(String tag) async {
List<ProductGroupModel> categories = [];
SharedPref sharedPref = SharedPref();
var cacheCategories =
json.decode(await sharedPref.read('PRODUCT_CATEGORY'));
// FILTERING THE LIST STARTS
var filteredJson =
cacheCategories.where((i) => i["ParentGroupId"] == tag).toList();
// FILTERING THE LIST ENDS
for (var u in filteredJson) {
ProductGroupModel productCat = ProductGroupModel(
u["Description"],
u["IconURL"],
u["ProductGroup"],
u["ParentGroupId"],
u["HasChildNode"],
u["Order"]);
categories.add(productCat);
}
print(categories);
return categories;
}
Future<List<ProductGroupModel>> _getCategories() async {
List<ProductGroupModel> categories = [];
SharedPref sharedPref = SharedPref();
var cacheCategories =
json.decode(await sharedPref.read('PRODUCT_CATEGORY'));
if (cacheCategories.isEmpty) {
var data = await http.get(
'PRIVATE API ENDPOINT PLEASE');
var jsonData = json.decode(data.body);
// FILTERING THE LIST STARTS
var filteredJson =
jsonData.where((i) => i["ParentGroupId"] == '0').toList();
// FILTERING THE LIST ENDS
for (var u in filteredJson) {
ProductGroupModel productCat = ProductGroupModel(
u["Description"],
u["IconURL"],
u["ProductGroup"],
u["ParentGroupId"],
u["HasChildNode"],
u["Order"]);
categories.add(productCat);
}
} else {
// FILTERING THE LIST STARTS
var filteredJson =
cacheCategories.where((i) => i["ParentGroupId"] == '0').toList();
// FILTERING THE LIST ENDS
for (var u in filteredJson) {
ProductGroupModel productCat = ProductGroupModel(
u["Description"],
u["IconURL"],
u["ProductGroup"],
u["ParentGroupId"],
u["HasChildNode"],
u["Order"]);
categories.add(productCat);
}
return categories;
}
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getCategories(),
builder: (BuildContext context,
AsyncSnapshot<List<ProductGroupModel>> snapshot) {
if (snapshot.data == null) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:
2),
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 0,
color: Colors.transparent,
child: Hero(
tag: snapshot.data[index].ProductGroup,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
bool hasChild = snapshot.data[index].HasChildNode;
if (hasChild == true) {
setState(() {
_getChildrenCategories(
snapshot.data[index].ProductGroup);
});
} else {
Scaffold.of(context).showSnackBar(SnackBar(
content: new Text("Nothing found!"),
duration: const Duration(milliseconds: 500)));
}
},
child: GridTile(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
backgroundImage:
NetworkImage(snapshot.data[index].IconURL),
radius: 75.0,
),
Text(
snapshot.data[index].Description,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
color: Colors.white,
),
),
],
),
),
),
),
),
);
});
}
},
);
}
}
//THE MODEL CLASS
class ProductGroupModel {
final String Description;
final String IconURL;
final String ProductGroup;
final String ParentGroupId;
final bool HasChildNode;
final int Order;
ProductGroupModel(
this.Description,
this.IconURL,
this.ProductGroup,
this.ParentGroupId,
this.HasChildNode,
this.Order,
);
}