Flutter carouse_slider image always refresh make app crash - flutter

I have problem when listing multi images from api to carousel_slider.
It always crash and show no error.
I have compare to my old app, it works as normal, but another one always crash.
return ChangeNotifierProvider(
create: (context) => HomeProvider(),
child: Consumer<HomeProvider>(builder: (bContext, homeProderAction, _) {
return RefreshIndicator(
key: refreshKey,
onRefresh: () async {
refreshKey.currentState?.show(atTop: false);
await Future.delayed(Duration(seconds: 1));
homeProderAction.setHomeData(homeData: fetchHomeData());
return null;
},
child: FutureBuilder<HomeModel>(
future: _homeData,
builder: (context, snapshot) {
print('hello world');
// if (_source.keys.toList()[0] == ConnectivityResult.wifi ||
// _source.keys.toList()[0] == ConnectivityResult.mobile) {
if (snapshot.hasData &&
snapshot.connectionState == ConnectionState.done) {
// return Container(
// child: ListView.builder(
// itemCount: 2 + snapshot.data.categories.length,
// shrinkWrap: true,
// addAutomaticKeepAlives: true,
// itemBuilder: (context, ind) {
// //Developer sum array of banner and course together
// //That's why list index 0 for homepage banner
// //And other for other ...
// if (ind == 0) {
return Container(
width: MediaQuery.of(context).size.width,
child: CarouselSlider.builder(
enableInfiniteScroll: true,
viewportFraction: 1.0,
height: 100,
itemCount: snapshot.data.courses.length,
itemBuilder: (context, ind) {
return Container(
width: 100,
height: 100,
color: Colors.pink,

Related

Flutter FutureBuilder duplicates items inside a GridView

It seems that the GridView.builder inside FutureBuilder duplicates each element a number of times equal to the list length.
Here is the code:
InformationScreen:
List<Reference> documentReference = [];
Widget showSavedDocument() => FutureBuilder(
future: _futureListResult,
builder: (context, AsyncSnapshot<ListResult> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.items.length,
itemBuilder: (context, index) {
final photo = snapshot.data!.items[index].getDownloadURL();
final photoName = snapshot.data!.items[index].name;
final metaData = snapshot.data!.items[index].getMetadata();
documentReference = snapshot.data!.items;
return Column(
children: [
FutureBuilder(
future: metaData,
builder: (context, AsyncSnapshot<FullMetadata> snapshot) {
if(snapshot.hasData) {
photoType = snapshot.data!.contentType!;
}
return Container();
},
),
FutureBuilder(
future: photo,
builder: (context, AsyncSnapshot<String?> snapshot) {
if (snapshot.hasData) {
final image = snapshot.data;
List<Document> documents = [];
for (int i = 0; i < documentReference.length; i++) {
Document document = Document(user!.uid, image!, photoName, photoType);
documents.add(document);
}
return DocumentGrid(documents: documents,); // <------------------------------
}
return Container();
},
),
],
);
},
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
}
if (snapshot.connectionState == ConnectionState.waiting || !snapshot.hasData) {
return const Loader();
}
if (snapshot.hasError) {
return Utils.showErrorMessage(snapshot.hasError.toString());
}
return Container();
},
);
DocumentGrid
import 'package:flutter/material.dart';
import 'package:app_test/constant/color.dart';
import '../constant/text.dart';
import '../model/document.dart';
class DocumentGrid extends StatelessWidget {
final List<Document> documents;
const DocumentGrid({Key? key, required this.documents}) : super(key: key);
#override
Widget build(BuildContext context) {
return buildGridView();
}
//****************************************************************************
// Create GridView
//****************************************************************************
Widget buildGridView() => GridView.builder(
itemCount: documents.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 2,
mainAxisSpacing: 2,
),
itemBuilder: (context, index) {
final photo = documents[index].photo;
final title = documents[index].title;
final type = documents[index].type;
return buildGridViewItem(photo, title, type);
},
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
//****************************************************************************
// Create GridView item
//****************************************************************************
Widget buildGridViewItem(String photo, String? title, String type) => Container(
width: 50,
height: 50,
color: phoneButtonColor,
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
children: [
buildNetworkImage(photo, type),
buildBlackOpacity(title),
],
),
);
//****************************************************************************
// Create Network image
//****************************************************************************
Widget buildNetworkImage(String photo, String type) => Image.network(
fit: BoxFit.cover,
width: 100,
height: 100,
photo,
errorBuilder: (context, exception, stackTrace) {
return type == "pdf" || type != "jpg"
|| type != "jpeg" || type != "png"
? Image.asset(
fit: BoxFit.cover,
width: 100,
height: 100,
"assets/images/pdf.png",
)
: Container(
color: grey,
width: 100,
height: 100,
child: const Center(
child: Text(
errorLoadImage,
textAlign: TextAlign.center,
),
),
);
},
);
//****************************************************************************
// Create Black opacity
//****************************************************************************
Widget buildBlackOpacity(String? title) => Container(
color: Colors.black54,
padding: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 20,
),
child: Column(
children: [
Expanded(
child: Center(
child: Text(
title!,
style: const TextStyle(
fontSize: 20,
color: Colors.white,
),
),
),
),
],
),
);
}
How can I solve that, thanks in advance
Problem solved
Replacing ListView by GridView
Widget showSavedDocument() => FutureBuilder(
future: _futureListResult,
builder: (context, AsyncSnapshot<ListResult> snapshot) {
if(snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return GridView.builder(
itemCount: snapshot.data!.items.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 2,
mainAxisSpacing: 2,
),
itemBuilder: (context, index) {
final instructorDocument = snapshot.data!.items;
final photo = instructorDocument[index].getDownloadURL();
final photoName = instructorDocument[index].name;
final metaData = instructorDocument[index].getMetadata();
return Column(
children: [
FutureBuilder(
future: metaData,
builder: (context, AsyncSnapshot<FullMetadata> snapshot) {
if (snapshot.hasData) {
photoType = snapshot.data!.contentType!;
}
return Container();
},
),
FutureBuilder(
future: photo,
builder: (context, AsyncSnapshot<String?> snapshot) {
if (snapshot.hasData) {
final image = snapshot.data!;
return Expanded(
child: buildGridViewItem(image, photoName, photoType),
);
}
return Container();
},
),
],
);
},
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
}
if(snapshot.connectionState == ConnectionState.waiting || !snapshot.hasData) {
return const Loader();
}
if(snapshot.hasError) {
return Utils.showErrorMessage(snapshot.hasError.toString());
}
return Container();
},
);

FutureBuilder and Services function

I am using future builder with service function like this, when getUserProfile function
When I get the APIService.getUserProfile() funciton return Forbidden(403) error I want to navigate to login page, how can I do that where can I add this navigator function in my code ? How can I detect and return Login Page
body: FutureBuilder(
future: APIService.getUserProfile(),
builder: (
BuildContext context,
AsyncSnapshot<String> model,
) {
if (model.hasData) {
return SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 240,
child: FutureBuilder(
future: getCurrentUser(),
builder: (context, snapshot) {
return ListView.separated(
itemBuilder: (context, index) {
print(index);
if (username == null) {
return Text(
""); //GetUserName(documentId: user!.uid);
} else {
print("build");
return MyCard(
balance: balance ?? 0,
creditCardsNumber: 0,
userName: username.toString(),
card: myCards[index],
);
}
},
separatorBuilder: (context, index) {
return SizedBox(width: 10);
},
itemCount: 1,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
);
}),
),
SizedBox(
height: 30,
),
Text(
"Recent Payments",
style: ApptextStyle.BODY_TEXT,
),
SizedBox(
height: 15,
),
FutureBuilder(
future: getCurrentUser(),
builder: (context, snapshot) {
return ListView.separated(
itemBuilder: (context, index) {
if (username != null) {
return TransactionCard(
transaction: myTransactions[index]);
} else {
return Text("");
}
},
separatorBuilder: (context, index) {
return SizedBox(height: 10);
},
itemCount: myTransactions.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
);
})
],
),
),
);
} else if (model.hasError) {
print("HEREEE");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
return Text("asdasfsdfd");
}
return Text("");
}));

Future builder build only after all recursive call finished

my recursive function to get all .jpg files from device
Directory dir = Directory("/storage/emulated/0");
late CameraController controller;
List<String> visited = [];
List<String> files = [];
Future getphotos(olddir) async {
Directory newdir = olddir;
for (var item in newdir.listSync()) {
if (item.runtimeType.toString() == "_Directory" &&
!visited.contains(item.toString()) &&
!item.path.contains(".thumbnail")) {
visited.add(item.toString());
await getphotos(item);
} else {
if (item.path.endsWith(".jpg")) {
files.add(item.path);
}
}
}
my future builder
FutureBuilder<Object>(
future: temp(),
builder: (context, snapshot) {
return GridView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5),
//if file/folder list is grabbed, then show here
itemCount: snapshot.hasData ? files.length : 5,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(3.0),
child: !snapshot.hasData
? Image.asset("assets/images/load.gif")
: Image.file(
File(files[index]),
fit: BoxFit.cover,
filterQuality: FilterQuality.low,
width: 200,
height: 200,
),
);
});
});
problem: my futurebuilder build its child widget only when the above recursive function is finished, screen stuck while its loading all the images path

flutter: randomize item count in list View

i implemented listView in flutter and it shows product count=5 , but i wanted these 5 items to be generated randomly , is there a way to do it? thanks in advance
ps: i tried code depending on answer below but it gives me error count!=null
Expanded(
child: SizedBox(
height: 210.0,
child: FutureBuilder(
future: httpService.getProducts(),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text('Loading...'),
),
);
} else if (snapshot.data.length == 0) {
return Container(
child: Center(
child: Center(
child: Text('No offers'),
),
),
);
} else {
var rndItems = snapshot.data.shuffle();
return ListView.separated(
separatorBuilder:
(BuildContext context, int index) {
return SizedBox(height: 3);
},
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: rndItems ,
itemBuilder: (ctx, i) => (PdtItem(
title: snapshot.data[i].title,
imgUrl: snapshot.data[i].imgUrl,
price: snapshot.data[i].price,
pdt2: snapshot.data[i])),
);
If you want the items from snapshot.data to be listed in a random order then you may shuffle the data as follows :
....
snapshot.data.shuffle();
....
If you want to display random number of items everytime then
....
import 'dart:math';
....
var rng = new Random();
var rndItems = rng.nextInt(snapshot.data.length);
....
.....
scrollDirectionn: Axis.horizontal,
shrinkWrap: true,
itemCount: rndItems,
itemBuilderr: (ctx, i) => (PdtItem(
.....

Better way to pass selected index in flutter

I have data from firestore
I need to display the name in a single page and the name of content in another page and so episodes
Is there a better way than this
tvshow page
FutureBuilder(
future: Provider.of<Data>(context).fetchShows(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
tvSelected = index;
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return SeasonsPage(selectedTv: tvSelected);
}));
},
child: Container(
margin: EdgeInsets.all(10.0),
width: 100.0,
color: Colors.orangeAccent,
child: Text(snapshot.data[index].name),
),
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
seasons page:
FutureBuilder(
future: Provider.of<Data>(context).fetchShows(),
builder: (context, snapshot) => snapshot.hasData
? ListView.builder(
itemCount: snapshot.data[selectedTv].content.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
selectedSeason = index;
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return EpisodesPage(
selectedTv: selectedTv,
selectedSeason: selectedSeason,
);
}));
},
child: Container(
margin: EdgeInsets.all(10.0),
width: 100.0,
color: Colors.orangeAccent,
child: Text(
snapshot.data[selectedTv].content[index].name),
),
);
},
)
: Center(child: CircularProgressIndicator()),
),
episodes page:
FutureBuilder(
future: Provider.of<Data>(context).fetchShows(),
builder: (context, snapshot) => snapshot.hasData
? ListView.builder(
itemCount: snapshot.data[selectedTv].content[selectedSeason]
.episodes.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(10.0),
width: 100.0,
color: Colors.orangeAccent,
child: Text(snapshot.data[selectedTv]
.content[selectedSeason].episodes[index]),
);
},
)
: Center(child: CircularProgressIndicator()),
),
look at when I pass a route page
.............................
.............................
...........................
Firstly you you create a new provider class that will hold the indices of the currently selected tv,episode and season as shown bellow:
class CurrentIndexProvider with ChangeNotifier {
int _selectedTv;
int _selectedSeason;
int _selectedEpisode;
set selectedTv(int newIndex) {
this._selectedTv = newIndex;
notifyListeners();
}
set selectedSeason(int newIndex) {
this._selectedSeason = newIndex;
notifyListeners();
}
set selectedEpisode(int newIndex) {
this._selectedEpisode = newIndex;
notifyListeners();
}
int get selectedTv => this._selectedTv;
int get selectedSeason => this._selectedSeason;
int get selectedEpisode => this._selectedEpisode;
}
Then your tv shows page becomes:
final selectedItems = Provider.of<CurrentIndexProvider>(context);
FutureBuilder(
future: Provider.of<Data>(context).fetchShows(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
// tvSelected = index; -->we dont need this anylonger
//we set the current show number to the index of the current
//listview item when tapped
selectedItems.selectedSeason=index;
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return SeasonsPage(
//we don't need to pass anything in the constructor again
// selectedTv: tvSelected
);
}));
},
child: Container(
margin: EdgeInsets.all(10.0),
width: 100.0,
color: Colors.orangeAccent,
child: Text(snapshot.data[index].name),
),
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
your seasons page becomes
final selectedItems = Provider.of<CurrentIndexProvider>(context);
FutureBuilder(
future: Provider.of<Data>(context).fetchShows(),
builder: (context, snapshot) => snapshot.hasData
? ListView.builder(
itemCount: snapshot.data[ selectedItems.selectedTv].content.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
//selectedSeason = index; --> we dont need this any longer
selectedItems.selectedSeason=index;
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return EpisodesPage(
//we don't need any parameter in the constructor now
// selectedTv: selectedTv,
// selectedSeason: selectedSeason,
);
}));
},
child: Container(
margin: EdgeInsets.all(10.0),
width: 100.0,
color: Colors.orangeAccent,
child: Text(
snapshot.data[selectedItems.selectedTv].content[index].name),
),
);
},
)
: Center(child: CircularProgressIndicator()),
),
And finally the episodes page becomes
final selectedItems = Provider.of<CurrentIndexProvider>(context);
FutureBuilder(
future: Provider.of<Data>(context).fetchShows(),
builder: (context, snapshot) => snapshot.hasData
? ListView.builder(
itemCount: snapshot.data[selectedItems.selectedTv ].content[selectedItems.selectedSeason]
.episodes.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(10.0),
width: 100.0,
color: Colors.orangeAccent,
child: Text(snapshot.data[selectedItems.selectedTv]
.content[selectedItems.selectedSeason].episodes[index]),
);
},
)
: Center(child: CircularProgressIndicator()),
),
With this you can have access to the currently selected tv show or seasons or even episodes anywhere within you code by using provider. hope this helped