I have modified my code. I thought I could achieve what I am willing to do but I am still having an issue. The first image is fine, but when I am adding more images, they don't display to the screen. The idea is to allow the user to click on a button to select one or several images. Then, he can tap on a second button and add one pfd file, it is like adding attachment in email.Then, if the user wants he can tap on the first button and add an other image. The list of all the documents should be displayed on the screen. I though that maybe a set State is missing somewhere. Here is the code. I do not understand where is my mistake. Thank you in advance.
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
List<PlatformFile>? _paths;
List<String> filesGB =[];
bool _loadingPath = false;
String fileExtension='';
String _fileName='';
// To access the pictures
void _openPictureFileExplorer() async {
setState(() => _loadingPath = true);
try {
_paths = (await FilePicker.platform.pickFiles(
type: FileType.media,
allowMultiple: true,
))?.files;
if (_paths != null) {
_paths!.forEach((element) {
filesGB.add(element.path.toString());
print(filesGB);
print(filesGB.length);
});
setState(() {
});
}
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
//#############
//Display card with button to select type of document
child: Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//Attachement
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.attach_file),
Text('Attachment'),
],
)
),
onTap: () async {
fileExtension = 'pdf';
_openDocumentFileExplorer();
},
),
),
//Photo
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {
fileExtension = 'jpeg';
_openPictureFileExplorer();
},
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: filesGB.isNotEmpty ?
Column(
children: listOfCards(filesGB),
)
:Text('Nothing to display'),
),
]),)))));
}
}
List<Widget> listOfCards(List<String> item){
List<Widget> list = <Widget>[];
ListView.builder(
itemCount: filesGB.length,
itemBuilder: (BuildContext ctxt, int index) {
return new Container(
height: 114,
child: GestureDetector(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113, width: 113,
child: Image.file(File(item[i].toString()),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(item[i]
.split('/')
.last),
),
),
],
),
),),
),
);
});
return list;
}
first of all, you don't need to use for loop for building your pictures list
just use ListView.builder
but about your problem, I think it happens because you set selected pictures in a row
then return that row as a child of your column
so your pictures align horizontally and column just show widgets in vertical aligns
in other words, your column just have one child, and its a Row
so column just show pictures as possible then you just see the first picture.
for solving this problem you should return a list of widgets in the listOfCards function
just do these simple changes and I hope your problem solved
change your function return parameter to List<Widget>
Widget listOfCards(List<String> item) {
to
List<Widget> listOfCards(List<String> item) {
then just return your list
return list;
and your column should look like this
Column(
children: listOfCards(filesGB),
)
I have find a working solution. It does what I was expecting with image. I still have a problem when I delete a record, the card is not removed. I do not find where I should use the setState. I will continue to investigate.
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
//#############
//Display card with button to select type of document
child: Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//Attachement
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.attach_file),
Text('Attachment'),
],
)
),
onTap: () async {
fileExtension = 'pdf';
_openDocumentFileExplorer();
},
),
),
//Photo
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {
fileExtension = 'jpeg';
_openPictureFileExplorer();
},
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: filesGB.isNotEmpty ?
Column(
children: getList(),//[listOfCards(filesGB)],
)
:Text('Nothing to display'),
),
]),)))));
}
}
List<Widget> getList() {
List<Widget> childs = [];
for (var i = 0; i < filesGB.length; i++) {
childs.add(
GestureDetector(
onTap: (){
print ("Pressed");
},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113,width: 113,
child: fileExtension == 'pdf'?
Image.asset('assets/logo_pdf.png',
// fit: BoxFit.fill,
// width: double.infinity,
):
Image.file(File(filesGB[i].toString()),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(filesGB[i].toString().split('/').last,//_nameOfFile,//name,
style: TextStyle(fontWeight: FontWeight.bold),),
),
),
Padding(
padding: const EdgeInsets.only(right:25.0),
child: IconButton(onPressed: (){
//delete a record and the card displaying this record
// Delete the selected image
// This function is called when a trash icon is pressed
if (filesGB.length > 1) {
filesGB.removeAt(i);
print(filesGB);
setState(() {});
}
},
icon:Icon (Icons.delete, color: Colors.red,),),
)
],
),
),
//subtitle: Text(path),
),
));}
return childs;
}
Related
my video call output
when logged another person to this video call then shows like this.But I want when someone logged to video call then my video should be small.
like this.
and also when click my video then my video should be big and another person's video should be small. how to do that ? I couldn't find the any documentation how to do that
Code video call ui
// video view
Widget _viewRows() {
final views = _getRenderViews();
switch (views.length) {
case 1:
return Column(
children: <Widget>[_videoView(views[0])],
);
case 2:
return Column(
children: <Widget>[
_expandedVideoRow([views[0]]),
_expandedVideoRow([views[1]])
],
);
case 3:
return Column(
children: <Widget>[
_expandedVideoRow(views.sublist(0, 2)),
_expandedVideoRow(views.sublist(2, 3))
],
);
case 4:
return Column(
children: <Widget>[
_expandedVideoRow(views.sublist(0, 2)),
_expandedVideoRow(views.sublist(2, 4))
],
);
default:
}
return Container();
}
How customize the video UI like as I mentioned?
error
To create the layout which you want, edit _viewRow(CallNotifier notifier) and _expandedVideoRow(List views) function with following code : -
Widget _viewRows(CallNotifier notifier) : -
case 2:
return Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
child: Stack(
children: [
_expandedVideoRow([views[secondScreen]]),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 10, bottom: 10),
child: GestureDetector(
onTap: () {
tempSwap = firstScreen;
firstScreen = secondScreen;
secondScreen = tempSwap;
setState(() {});
},
child: SizedBox(
height: 200,
width: 100,
child: _expandedVideoRow([views[firstScreen]])),
),
),
),
],
));
Above code contains _expandedVideoRow([views[secondScreen]]), which is just a simple Expandable Container and we are passing the index of the screen as a parameter. In our case, there are 2 screens hence 2 index that is 0 and 1. I have declared three integer variables here, int firstScreen = 0, int secondScreen = 1 and int tempSwap = 0. The second _expandedVideoRow([views[firstScreen]]) is wrapped by GesutreDector, so when the user taps on that screen the indexes of the variable are swapped which results in swapping the screens, SizedBox to reduce its width and height and Align widget to give the desired position to the second screen.
Widget _expandedVideoRow(List views) : -
Widget _expandedVideoRow(List<Widget> views) {
final wrappedViews = views.map<Widget>(_videoView).toList();
return Row(
children: wrappedViews,
);
}
Remove the Expanded widget that wraps the row like the above code because we can't use the Expanded under the Stack widget.
If you wish to change the bottom icons, then change _toolbar(CallNotifier notifier) function according to your need.
Widget _toolbar(CallNotifier notifier) {
return Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () {
_onToggleMute(notifier);
setState(() {
isMute = !isMute;
});
},
child: Icon(
isMute ? Icons.mic_off : Icons.mic,
color: isMute ? Colors.white : Colors.teal,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: isMute ? Colors.teal : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: () => _onCallEnd(context),
child: Icon(
Icons.call_end,
color: Colors.white,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
),
],
),
);
}
Code which I use in my app, full code : -
class _CallScreenState extends State<CallScreen> {
double globalHeight;
int firstScreen = 0;
int secondScreen = 1;
int tempSwap = 0;
bool isMute = false;
void initState() {
super.initState();
}
List<Widget> _getRenderViews(CallNotifier model) {
final List<StatefulWidget> list = [];
list.add(RtcLocalView.SurfaceView());
model.users
.forEach((int uid) => list.add(RtcRemoteView.SurfaceView(uid: uid)));
return list;
}
Widget _videoView(view) {
return Expanded(child: Container(child: view));
}
Widget _expandedVideoRow(List<Widget> views) {
final wrappedViews = views.map<Widget>(_videoView).toList();
return Row(
children: wrappedViews,
);
}
Widget _viewRows(CallNotifier notifier) {
final views = _getRenderViews(notifier);
switch (views.length) {
case 1:
return Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
child: Column(
children: <Widget>[_videoView(views[0])],
));
case 2:
return Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
child: Stack(
children: [
_expandedVideoRow([views[secondScreen]]),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 10, bottom: 10),
child: GestureDetector(
onTap: () {
tempSwap = firstScreen;
firstScreen = secondScreen;
secondScreen = tempSwap;
setState(() {});
},
child: SizedBox(
height: 200,
width: 100,
child: _expandedVideoRow([views[firstScreen]])),
),
),
),
],
));
default:
}
return Container();
}
Widget _toolbar(CallNotifier notifier) {
return Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () {
_onToggleMute(notifier);
setState(() {
isMute = !isMute;
});
},
child: Icon(
isMute ? Icons.mic_off : Icons.mic,
color: isMute ? Colors.white : Colors.teal,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: isMute ? Colors.teal : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: () => _onCallEnd(context),
child: Icon(
Icons.call_end,
color: Colors.white,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
),
],
),
);
}
void _onCallEnd(BuildContext context) {
Navigator.pop(context);
}
void _onToggleMute(CallNotifier notifier) {
notifier.isMuted = notifier.isMuted;
notifier.engine.muteLocalAudioStream(notifier.isMuted);
}
#override
Widget build(BuildContext context) {
return BaseWidget<CallNotifier>(
model: CallNotifier(),
onModelReady: (model) => model.init(widget.channelName, widget.token),
builder: (context, notifier, child) {
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: Stack(
children: <Widget>[
_viewRows(notifier),
Align(
alignment: Alignment.bottomCenter,
child: _toolbar(notifier)),
],
),
),
);
});
}
}
I am trying to make a list view only occupy part of the screen, but it keeps growing till the end not respecting the contianer constraints. I tried to use a sizedbox too but it didn' work. List tiles outside the container are shown without any widget inside, but the background is shown anyways
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: pedidos,
builder: (context, AsyncSnapshot<List<Pedido>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: ListView.builder(
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Hero(
tag:
"pedidos_card${snapshot.data![index].idPedido}",
child: ListTile(
tileColor: Colors.white,
leading: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle),
child: Center(
child: Text(
style: Theme.of(context)
.textTheme
.headlineSmall,
"${snapshot.data![index].idPedido}"),
),
),
title: Text(
'Pedido: ${snapshot.data![index].idPedido}'),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Text(
'Estado: ${snapshot.data![index].estadoPedido.last.tipoEstadoPedido.name}'),
SizedBox(height: 10),
Text(
"Cliente: ${snapshot.data![index].cliente.nombre}")
],
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
trailing: Checkbox(
value: pedidosSeleccion
.contains(snapshot.data![index]),
onChanged: (bool? value) {
// value = checkboxList[index];
// setState(() {});
},
),
onTap: () {
bool isSelected = pedidosSeleccion
.contains(snapshot.data![index]);
if (isSelected) {
pedidosSeleccion
.remove(snapshot.data![index]);
} else {
pedidosSeleccion.add(snapshot.data![index]);
}
setState(() {});
},
),
));
}),
),
ElevatedButton(
onPressed: () {}, child: Text('Ver ultima milla')),
],
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
}
}
example
you can use Expanded instead of Sizedbox
eg:-
Column(
children:[
Expanded(flex:9,
child: ListView(
padding: const EdgeInsets.only(top: 10.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
),
),
Expanded(flex:1,
child:
ElevatedButton(
// fill in required params
),
)
])
I recently upgrade all the depencies. It required to change all my codes.
Now I face an issue to retrieve data from Firebase.
The main codes impacted are below.
BlocBuilder - cubit was replaced by bloc
BlocBuilder(
bloc: ordersBloc,
buildWhen: (previous, current) {
if (current is UpdateOrderAnalyticsState ||
current is GetOrderAnalyticsFailedState ||
current is GetOrderAnalyticsInProgressState) {
return true;
}
return false;
},
builder: (context, state) {
if (state is GetOrderAnalyticsInProgressState) {
return Shimmer.fromColors(
period: Duration(milliseconds: 800),
baseColor: Colors.grey.withOpacity(0.5),
highlightColor: CompanyColors.color[800].withOpacity(0.5),
child: ShimmerCommonMainPageSmallItem(size: size),
);
}
if (state is GetOrderAnalyticsFailedState) {
return Center(child: Text('FAILED'));
}
if (state is UpdateOrderAnalyticsState) {
orderAnalytics = state.orderAnalytics;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Material(
child:
InkWell(
splashColor: CompanyColors.color[700].withOpacity(0.5),
onTap: () {
HapticFeedback.heavyImpact();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => InventoryPage()),
);
},
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 1),
child: Container(
padding: const EdgeInsets.all(10.0),
decoration: _mainthembox,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'GESTION INVENTAIRE',
overflow: TextOverflow.clip,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
color: CompanyColors.color[50],
fontSize: 15,
fontWeight: FontWeight.w500,
),
),
SizedBox(
height: 5.0,
),
Container(
width: 55.0,
height: 55.0,
alignment: Alignment.center,
padding: const EdgeInsets.all(15.0),
decoration: _thembox,
child: Icon(
Icons.account_balance_outlined,
color: CompanyColors.color[50],
size: 25.0,
),
),
SizedBox(
height: 10.0,
),
],
),
),
),
),
),
),
),
CloudFirestore - documentSnapshot.data()['cancelledOrders'] was replaced by documentSnapshot.get('cancelledOrders')
class OrderAnalytics {
var cancelledOrders;
var cancelledSales;
var deliveredOrders;
var deliveredSales;
var newOrders;
var newSales;
var processedOrders;
var processedSales;
var totalOrders;
var totalSales;
OrderAnalytics({
this.cancelledOrders,
this.cancelledSales,
this.deliveredOrders,
this.deliveredSales,
this.newOrders,
this.newSales,
this.processedOrders,
this.processedSales,
this.totalOrders,
this.totalSales,
});
factory OrderAnalytics.fromFirestore(DocumentSnapshot documentSnapshot) {
return OrderAnalytics(
cancelledOrders: documentSnapshot.get('cancelledOrders'),
cancelledSales: documentSnapshot.get('cancelledSales'),
deliveredOrders: documentSnapshot.get('deliveredOrders'),
deliveredSales: documentSnapshot.get('deliveredSales'),
newOrders: documentSnapshot.get('newOrders'),
newSales: documentSnapshot.get('newSales'),
processedOrders: documentSnapshot.get('processedOrders'),
processedSales: documentSnapshot.get('processedSales'),
totalOrders: documentSnapshot.get('totalOrders'),
totalSales: documentSnapshot.get('totalSales'),
);
}
}
see below error messages
I have a simple cart page I am showing products on the cart page. The issue is when I am deleting an item it's deleting but in the widget, it's not deleting I need to go back and come again to show the changes. I try to rise setState also but not working.
My code
class _CartPageState extends State<CartPage> {
num amount = 0;
bool checkLogin = false;
void navigateToAddressPage() {
Get.to(AddressPage());
}
check() async {
final storage = new FlutterSecureStorage();
String imi = await storage.read(key: "imei");
print(imi);
if (imi == "loginhuavaha") {
setState(() {
this._query();
checkLogin = true;
});
}
}
#override
void initState() {
setState(() {
this.check();
});
}
List<Widget> textWidgetList = List<Widget>();
void _query() async {
print('cart');
final dbHelper = DatabaseHelper.instance;
final allRows = await dbHelper.queryAllRows();
allRows.forEach((row) {
amount += double.parse(row['price']);
print(amount);
print(row);
});
for (int i = 0; i < allRows.length; i++) {
textWidgetList.add(Card(
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
margin: EdgeInsets.symmetric(vertical: 8.0),
child: Container(
width: double.infinity,
height: 120.0,
padding: EdgeInsets.all(12.0),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12.0),
child: Image.network(allRows[i]['image'],
width: 100, height: 100)),
SizedBox(width: 12.0),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
allRows[i]['title'],
textAlign: TextAlign.start,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(width: 5.0),
Row(
children: [
GestureDetector(
onTap: () async {
print('delete');
final id = await dbHelper.queryRowCount();
print(id);
final rowsDeleted = await dbHelper.delete(
id, allRows[i]['id']);
print('deleted $rowsDeleted row(s): row $id');
setState(() {
});
},
child: Icon(
FlutterIcons.delete_outline_mco,
),
)
],
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
allRows[i]['price'],
),
),
// Counter(),
],
),
],
),
),
)
],
),
),
));
}
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(context),
body: checkLogin
? Container(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(children: textWidgetList),
],
),
),
)
: Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(child: Text('Your are not login')),
SizedBox(height: 10),
SizedBox(
width: 85.0,
height: 50.0,
child: RaisedButton(
color: Theme.of(context).primaryColor,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Text(
'LOGIN',
style: Theme.of(context).textTheme.button,
).tr(),
onPressed: () {
Get.offAll(SignInPage());
},
),
),
])),
),
);
}
You can see I have added a comment in my code I delete the product and it actually deleted from database but state isn't changing of widget -_-
I think what you need here is the Provider package. Provider makes state management easier a lot. Just define a model class that extends ChangeNotifier and then wrap your widgets with ChangeNotifierProvider<Model_class_name>. To access the fields Use Provider.of(context).var or Provider.of(context).function
First of all you need to put textWidgetList in the setState since you manipulate those Widgets I guess. Secondly you have to put a key to those Widgets due to how Flutter handles elements in a list on the UI.Have a look at this page https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
Its Simple Man
Once the item is removed
use setState((){})
setState(() {
//Inside setState Clear the allrows list
allrows.clear();
//Then get the allrows again so that the deleted data will not be shown
allRows = await dbHelper.queryAllRows();
});
setState rebuilds your widgets
My goal: When the user presses the "List" button inside "_mainListItem" I want the listview to get sorted by orderBy. Aswell as updated on screen
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class mainlist extends StatefulWidget {
#override
_mainlistpage createState() => _mainlistpage();
}
class _mainlistpage extends State<mainlist> {
Widget homePage() {
return StreamBuilder(
stream: Firestore.instance.collection("Test").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text("Loading");
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_mainListItem(context, snapshot.data.documents[index]));
},
);
}
Widget _mainListItem(BuildContext context, DocumentSnapshot document) {
return Card(
color: Colors.white,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => profile(context, document)));
},
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12))),
child: Row(
children: [
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
children: <Widget>[
Stack(
alignment: Alignment.topRight,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 5),
child: ClipRRect(
borderRadius:
BorderRadius.circular(0.0),
child: FittedBox(
child: Image.asset(
"assets/Profile Picture.png",
fit: BoxFit.fill,
)),
),
),
Padding(
padding: const EdgeInsets.only(
top: 7, right: 4),
child: Text(
'Test',
style: TextStyle(fontSize: 12),
),
),
]),
Row()
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
document['name'],
),
// Text("2km"),
],
),
],
),
],
),
),
],
),
),
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 5, bottom: 5),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 10, right: 7),
child: Container(
child: Material(
borderRadius: BorderRadius.circular(5),
shadowColor: Colors.black,
elevation: 1,
child: SizedBox(
height: 28,
width: 68,
child: IconButton(
padding: EdgeInsets.only(bottom: 10),
**icon: Icon(Icons.list),
disabledColor: Colors.blue,
iconSize: 25,**
)),
),
),
),
],
),
)
],
)
],
),
),
),
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
backgroundColor: Colors.grey,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.red,
),
title: Text("Test"),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.menu),
iconSize: 30,
color: Colors.white,
)
],
),
body: homePage(),
);
}
}
I have tried
- adding the streambuilder function into the ontapped: on the List button
- have read and watched every video there is and still can't find the solution
note: the app looks weird because I deleted unnecessary information
You can sort the list items before the snapshot method like:
.orderBy('sortField', descending: true).snapshot()
I hope this works for you.
Try mapping the values to a List<CustomObject> and using the list of objects in your list view.
i suggest you use state to determine the field how your list will be sorted by.
this is what i'd do to achieve this (continuing from the same code):
...
class _mainlistpage extends State<mainlist> {
String _orderBy = 'defaultSort'; //? HERE YOU PUT WHAT YOUR SORTING FIELD NAME IS
bool _isDescending = true; //? THIS IS WHAT WILL SET THE ORDER SORTING
Widget homePage() {
return StreamBuilder(
stream: Firestore.instance
.collection("Test")
.orderBy(_orderBy, descending: _isDescending) //? PUT THE ORDERBY QUERY HERE
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text("Loading");
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_mainListItem(context, snapshot.data.documents[index]));
},
);
}
...
somewhere in the class, put the button or dropdown and use setState(...) to set the
states of the new variables.
NOTE: you might have to create 'indexes' in firestore. you will get errors when a new
index is required.