I want the photos taken on the same date to be in the same group.
This is my gallery
I want this
Future<List<VideoImageDataModel>> fetchPhotos() async {
var dataList = await Historydao().ImageData();
return dataList;
}
FutureBuilder<List<VideoImageDataModel>>(
future: fetchPhotos(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var photoList = snapshot.data;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: (10 / 10), crossAxisCount: 4),
itemCount: photoList?.length,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: EdgeInsets.fromLTRB(5, 5, 0, 0),
//padding: EdgeInsets.fromLTRB(10, 5, 0, 0),
child: Hero(
tag: photoList![index].thumbnail,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ImagePage(
photoList[index]
.thumbnail
.toString())));
},
child: Stack(fit: StackFit.expand,
children: [
Image.file(
fit: BoxFit.cover,
File(photoList[index].thumbnail.toString()),
),
Positioned(
right: 3,
bottom: 3,
child: Column(crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${DateFormat('Hm', 'en_US').format(DateTime.fromMillisecondsSinceEpoch(photoList[index].id))}',
style: const TextStyle(
color: Colors.white,
fontSize: 9,
fontWeight: FontWeight.bold),
),
Text(
'${DateFormat('dd/MM/yyyy').format(DateTime.fromMillisecondsSinceEpoch(photoList[index].millisecond))}',
style: TextStyle(
color: Colors.white,
fontSize: 9,
fontWeight: FontWeight.bold),
), ],),),],),),),);}, );
} else {
return const Center(
child: CircularProgressIndicator(
color: Colors.blue,
),
);
}
},
),
I am creating my gallery using gridview builder.Thumbnail is photo name.I am generating date data using milliseconds.I want to show photos taken on the same day as a group.I can find the changed date using for loop.i don't know how to do this.
Related
I am trying to create a dialog to show a list of reviews on click event. However, the code below always generate an extra bottom padding after each gridview item and i was unable to find out which widget caused this extra padding.
Hopefully, someone can help me point me to the right direction. thanks much!
showDialog(
context: context,
builder: (_) {
return Dialog(
backgroundColor: Colors.orange[200],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
elevation: 16,
child: Container(
padding: EdgeInsets.only(bottom: 50),
child: StreamBuilder<QuerySnapshot>(
// stream: firestoreInstance.collection("requests").snapshots(),
stream: streamForReviews,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('');
case ConnectionState.waiting:
return new Text('');
default:
if (snapshot.hasError) {
return new Text('error');
}
if (snapshot.data != null) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
if (snapshot.data!.docs.length > 1) {
} else if (snapshot.data!.docs.length == 1) {
} else {}
});
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
),
scrollDirection: Axis.vertical,
shrinkWrap: true,
padding: EdgeInsets.zero,
// itemCount: snapshot.data.documents.length,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
// List rev = snapshot.data.documents.reversed.toList();
String comments =
snapshot.data!.docs[index].get("comments");
String reviewerName =
snapshot.data!.docs[index].get("name");
num rating = snapshot.data!.docs[index].get("rating");
String downloadURL =
snapshot.data!.docs[index].get("imageURL");
Timestamp reviewTimeStamp =
snapshot.data!.docs[index].get("createdDTG");
DateTime reviewDateTime =
DateTime.parse(reviewTimeStamp.toDate().toString());
DateFormat reviewDateTimeFormat =
new DateFormat('dd MMM yyyy');
String reviewDateTimeString =
reviewDateTimeFormat.format(reviewDateTime);
return Container(
padding: EdgeInsets.symmetric(
vertical: 20, horizontal: 20),
child: Column(
children: [
SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Image.network(
downloadURL,
fit: BoxFit.fitHeight,
height: 100,
),
),
SizedBox(width: 10),
Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment:
// CrossAxisAlignment.stretch,
children: [
Text(reviewDateTimeString,
style: TextStyle(
color: Colors.orange[800],
fontSize: 18,
// fontStyle: FontStyle.italic,
)),
SizedBox(height: 2),
Text(reviewerName,
style: TextStyle(
color: Colors.orange[800],
fontSize: 18,
)),
SizedBox(height: 2),
RichText(
text: TextSpan(
// style: Theme.of(context).textTheme.body1,
children: [
WidgetSpan(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 2.0),
child: Icon(
Icons.star,
color: Colors.orange,
size: 18,
),
),
),
TextSpan(
text: rating.toString(),
style: new TextStyle(
fontSize: 16.0,
color: Colors.orange[800],
),
),
],
),
),
SizedBox(height: 2),
],
),
Align(
alignment: Alignment.centerLeft,
child: Text(comments,
style: TextStyle(
color: Colors.orange[800],
fontSize: 16,
// fontStyle: FontStyle.italic,
)),
),
Divider(color: Colors.orange, thickness: 1),
],
),
);
},
);
} else {
return new Text('data null');
}
}
},
),
));
});
You need to change the value of childAspectRatio in SliverGridDelegateWithFixedCrossAxisCount widget. The default is 1, which means that grid items will have a width that is equal to their height. In your case, the width is approximately 2x of the height. your code should be like this:
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: 2, //try to change this number to see how it changes the dimensions of the grid item
I am facing problem in using stream builder. Actually, I have a dropdown list and below it I have gridview to show product categories according to options chose in dropdown list. I have to use two stream builders, one for option(s) list in dropdown and other is for gridview. Dropdown is wroking fine but gridview is not changing data according to option choose in dropdown list.
Please help
My dropdown widget
Widget dropDownMenu({
required Size size,
BuildContext? context,}) {
return StatefulBuilder(builder: (context, setState) {
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('options').get(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error while loading'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SpinKitFadingCircle(
itemBuilder: (BuildContext context, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven
? MyStyles.themeData().primaryColor
: Colors.green,
),
);
},
),
);
}
if (snapshot.hasData && snapshot.data!.docs.isEmpty) {
return Center(child: Text('No Data'));
}
return Container(
height: size.height * 0.100,
padding: EdgeInsets.all(20.0),
color: Colors.white,
child: DropdownButton<String>(
dropdownColor: Colors.white,
elevation: 1,
value: viewModel.dropDownValue!,
hint: Text('Choose one option'),
items:
snapshot.data!.docs.map<DropdownMenuItem<String>>((value) {
return DropdownMenuItem<String>(
value: value.get('options'),
child: Text(
value.get('options'),
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
color: MyStyles.themeData().primaryColor,
fontSize: size.height * 0.024,
fontWeight: FontWeight.w600,
),
),
);
}).toList(),
onChanged: (value) {
setState(() {
viewModel.dropDownValue = value;
});
}),
);
},
);
});}
My gridview Widget
Widget buildGridView({Size? size, BuildContext? context}) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('categories')
.where('options', isEqualTo: viewModel.dropDownValue)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error while loading'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SpinKitFadingCircle(
itemBuilder: (BuildContext context, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven
? MyStyles.themeData().primaryColor
: Colors.green,
),
);
},
),
);
}
if (snapshot.hasData && snapshot.data!.docs.isEmpty) {
return Center(child: Text('No Categories available'));
}
return GridView.builder(
padding: const EdgeInsets.only(bottom: 70),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 1,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
),
itemCount: snapshot.data!.size,
itemBuilder: (BuildContext ctx, index) {
return GestureDetector(
onTap: () {},
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 3.0),
height: size!.height * 0.200,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Color(0x99C4C4C4),
blurRadius: 12,
offset: Offset(4, 4),
spreadRadius: 0,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: size.height * 0.120,
width: size.width * 0.120,
child: Image.network(
snapshot.data!.docs[index]['image'])),
SizedBox(height: size.height * 0.015),
Text(
snapshot.data!.docs[index]['name']!,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.poppins(
color: MyStyles.themeMode().textColor,
fontSize: size.height * 0.022,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
},
);
},
),
),
);}
I want to rebuild stream everytime I change options in dropdown. How can I achieve this?
I got a page in flutter than contains future builder, and the result of it displayed in list view builder. When I get small amount of data, flutter display the data without any problem. But when I get large amount of data, it display nothing.
What I get from this problem is when I get large amount of data, future builder hasn't finished get the data before the page is shown.
How can I make the page wait for the future finished to get the data before the page is shown?
Thanks
FutureBuilder<List<SalesTable>>(
future: SelectSalesTable.getSalesTable(widget.kodesales,
daterange1.format(widget.tgl1), daterange2.format(widget.tgl2)),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none) {
return new Text('No Data..!!');
} else if (snapshot.connectionState == ConnectionState.waiting) {
return new Center(child: CircularProgressIndicator());
} else {
if (snapshot.hasData) {
List<SalesTable> data = snapshot.data;
return Container(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Card(
shadowColor: Colors.grey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 10,
child: Padding(
padding:
const EdgeInsets.fromLTRB(5, 10, 5, 10),
child: ListTile(
title: Text(
data[index].name +
' | ' +
data[index].Category,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold)),
subtitle: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text(
'Date : ' +
dateformat3.format(
data[index]
.date1),
style: TextStyle(
fontWeight:
FontWeight.bold)),
)
],
),
],
),
onTap: () {},
),
),
),
),
],
);
},
itemCount: data.length,
),
],
));
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
}
return Center(child: CircularProgressIndicator());
},
)
In the code below, I am trying to pass data from the home screen to the detail screen when user clicks on any of the product listed on the home screen. I seem to be having difficulty here.
Similar Question but does not solve my issue
Excerpt of the code at the home screen.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("name")
.limit(12)
.orderBy("Published Date", descending: true)
.snapshots(),
builder: (context, snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return GridView.builder(
physics: ScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10,
),
itemBuilder: (BuildContext context, int index){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: spinkit,
);
}
print("${snapshot.data.documents[index].get('Product Title')}");
return GestureDetector(
onTap: (){
// ===> SEND USER TO THE DETAILS SCREEN <===
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsScreen()),
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Stack(
children: [
Container(
height: 150,
width: 150,
child: Image.network(
snapshot.data.documents[index].get('image') ?? spinkit,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
Positioned(
left: 0,
bottom: 0,
child: Container(
height: 20,
width: 150,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black38,
Colors.black38,
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
)),
),
),
Positioned(
left: 4,
bottom: 5,
child: Text(
snapshot.data.documents[index].get('name') ?? "Product Name",
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Palette.whiteColor,
fontSize: 11,
fontWeight: FontWeight.bold),
),
)
],
),
),
);
}
);
},
)
And excerpt of the code at the Details Screen. what you see at the detail screen is data that I have populated manually. it is not coming from firestore.
class ProductDetailsScreen extends StatefulWidget {
#override
_ProductDetailsScreenState createState() => _ProductDetailsScreenState();
}
class _ProductDetailsScreenState extends State<ProductDetailsScreen> {
final productDb = FirebaseFirestore.instance.collection("name");
User user = FirebaseAuth.instance.currentUser;
final spinkit = SpinKitHourGlass(
color: Colors.white,
size: 50.0,
);
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackPressed,
child: Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.only(left: 15, right: 15, top: 3, bottom: 10),
child: FutureBuilder(
future: productDb.get(),
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: spinkit,
);
}
return Container(
child: ListView(
children: [
Column(
children: [
Center(
child: Container(
width: 350,
child: Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(8),
child: Container(
height: 220,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage("asset/images/headphone.jpg",)
)
),
),
),
),
),
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Item Name",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
Text("Item Price",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
],
),
SizedBox(height: 10,),
Text("Item Description",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
Container(
height: 1,
width: 100,
color: Colors.black12,
),
SizedBox(height: 10,),
Container(
height: 140,
width: 350,
child: SingleChildScrollView(
child: Wrap(
children: [
Text(
"What is Lorem Ipsum Lorem Ipsum is simply dummy "
"text of the printing and typesetting industry"
" Lorem Ipsum has been the industry's standard"
" dummy text ever since the 1500s when an "
"unknown printer took a galley of type and "
"scrambled it to make a type specimen book "
"it has?",
textAlign: TextAlign.justify,
style: TextStyle(
color: Palette.blackColor,
fontSize: 16,
),),
]
),
),
),
],
),
],
),
);
},
),
)),
),
);
}
}
In your GestureDetector onTap
// ===> SEND USER TO THE DETAILS SCREEN WITH DOC<===
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsScreen(snapshot.data.documents[index])),
);
Then
class ProductDetailsScreen extends StatefulWidget {
ProductDetailsScreen(this.doc);
QueryDocumentSnapshot doc;
#override
_ProductDetailsScreenState createState() => _ProductDetailsScreenState();
}
Access in _ProductDetailsScreenState as widget.doc.
The document data will be found at widget.doc.data as a Map<String, dynamic>.
I need to change the place of the widget in my UI. But I could not achieve it.
I tried this code But it does not work for me. If someone knows how to do it please help.
Change Place of BankCard Widget to Another BankCard Widget, or change the place of any widgets in a Column.
Below you can find code that I tried:
Widget nonNullBody(List<GetConversionCards> cards) {
_column=Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"fromSum".tr(),
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w700),
textAlign: TextAlign.left,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: BankCard(
card: Bank.CreditCardModel.fromUzCard(
cards[bloc.selectedIndex.value])),
),
IconButton(
icon: Icon(Icons.sync),
onPressed: () {
_key.currentState.setState(() {
Widget t=_column.children[0];
_column.children[0]=_column.children[3];
_column.children[3]=t;
});
},
),
Text("toVisa".tr(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700),
textAlign: TextAlign.left),
Padding(
padding: const EdgeInsets.all(8.0),
child: BankCard(
card: Bank.CreditCardModel.fromVisaCard(
cards[bloc.selectedIndex.value])),
),
],);
bloc.tokenCardUzs = cards[0].uzsCardId;
final size = MediaQuery.of(context).size;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
child: Container(
height: size.height - appBar().preferredSize.height + 5,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 30,
child: ValueListenableBuilder(
valueListenable: bloc.selectedIndex,
builder: (context, v, w) {
return ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: cards.length,
itemBuilder: (context, index) {
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(
vertical: 12.0, horizontal: 2.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: bloc.selectedIndex.value == index
? Color.fromRGBO(0, 0, 0, 0.9)
: Color.fromRGBO(0, 0, 0, 0.4)),
);
});
}),
),
Flexible(
fit: FlexFit.loose,
flex: 5,
child: PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: cards.length,
onPageChanged: (_) {
bloc.tokenCardUzs = cards[_].uzsCardId;
bloc.selectedIndex.value = _;
},
itemBuilder: (BuildContext context, int index) {
return StatefulBuilder(
key: _key,
builder: (BuildContext context,
void Function(void Function()) state) {
return _column; );
}),
),
Flexible(
child: TextFieldWidget(
controller: bloc.amountFieldController,
iconData: Icons.monetization_on,
validator: null,
hintText: "enterAmount".tr(),
labelText: "dollarCurrency".tr(),
),
),
ConfirmButton(
text: 'next'.tr(),
onPressed: () {
showPopUp(context, () async {
Navigator.of(context, rootNavigator: true).pop();
waitTransactionWidget(context);
int usd =
(double.parse(bloc.amountFieldController.text) * 100)
.toInt();
bool result = await Repository.getInstance()
.convUzsUsd(bloc.tokenCardUzs, usd);
print("result conv $result");
Navigator.of(context, rootNavigator: true).pop();
Navigator.pushReplacement(
context,
PageTransition(
child: MyHomePage(),
type: PageTransitionType.fade));
},
title: Text("wouldYouLikeToExchange".tr()),
subtitle: Text("${bloc.amountFieldController.text} " +
"dollarCurrency".tr()));
},
),
],
),
),
),
);
}
I recommend you create a list that contains widgets then assign it to the childrens parameters of Column. So when you change something about the list it will change the column as well.
like this :
List<Widget> list = new List();
#override
Widget build(BuildContext context) {
Column(
children: list,
);
}
adjustWidgetList() {
setState(() {
list.add(Text("lorem ipsum"));
list.add(Text("dolar sit amet."));
.
.
.
list.remove(0);
});
}
But don't forget to make your changes inside of setState.