Condition don't work with StatelessWidget and Provider in Flutter,
Hopefully, I need that FloatingActionButton show up in specific tab but current code does not work properly. FloatingActionButton work in all tab.
I tried to debug and found index value is reflected but the Button does not disappear when changing tab.
return DefaultTabController(
length: 3,
initialIndex: 0,
child: ChangeNotifierProvider<MainModel>(
create: (_) => MainModel()..getWorkoutListRealtime(),
child: Scaffold(
appBar: AppBar(
title: Text("Workout at home"),
actions: [
Consumer<MainModel>(builder: (context, model, child) {
final isActive = model.checkShouldActiveCompleteButton();
return FlatButton(
onPressed: isActive
? () async {
await model.deleteCheckedItems();
}
: null,
child: Text(
'削除',
style: TextStyle(
color:
isActive ? Colors.white : Colors.white.withOpacity(0.5),
),
),
);
})
],
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
),
body: TabBarView(
children: [
Consumer<MainModel>(builder: (context, model, child) {
------------------------------------------------------------------
Consumer<MainModel>(builder: (context, model, child) {
return SimpleDatumLegend.withSampleData(model);
}),
CountdownTimer(),
],
),
floatingActionButton:
Consumer<MainModel>(builder: (context, model, child) {
final index = DefaultTabController.of(context).index;
return index == 1
? FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddPage(model),
fullscreenDialog: true,
),
);
},
child: Icon(Icons.touch_app),
)
: SizedBox.shrink();
}),
I use DefaultTabController because I use Stateless widget and Provider function.
Related
I have the following code and could not figure out what is the problem.
I want to pass the Bluetooth device to the container in the class DeviceData and this class returns the container. I am beginner in Flutter and when I read the documentation could not understand what they are talking about.
But the first problem is
Can't define the 'const' constructor because the field 'uppersection' is initialized with a non-constant value. Try initializing the field to a constant value, or removing the keyword 'const' from the
and then device cannot be accessed:
The instance member 'device' can't be accessed in an initializer. Try replacing the reference to the instance member with a different expression
class DeviceData extends StatelessWidget {
const DeviceData({Key key, this.device}) : super(key: key);
final BluetoothDevice device;
final uppersection = new Container(
child: Row(
children: <Widget>[
StreamBuilder<BluetoothDeviceState>(
stream: device.state,
initialData: BluetoothDeviceState.connecting,
builder: (c, snapshot) => ListTile(
leading: (snapshot.data == BluetoothDeviceState.connected)
? Icon(Icons.bluetooth_connected)
: Icon(Icons.bluetooth_disabled),
title: Text('Device is ${snapshot.data.toString().split('.')[0]}.'),
subtitle: Text('${device.id}'),
trailing: StreamBuilder<bool>(
//The below stream is to show either a refresh button or
//CircularProgress based on the service discovering status,
//and a IndexedStack widget is used to present the needed widget
stream: device.isDiscoveringServices,
initialData: false,
builder: (c, snapshot) => IndexedStack(
index: snapshot.data ? 0 : 0,
children: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () => device.discoverServices(),
),
IconButton(
icon: SizedBox(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Colors.grey),
),
width: 17.0,
height: 17.0,
),
onPressed: null,
),
],
),
),
),
),
],
),
);
#override
Widget build(BuildContext context) {
return new Container(
child: Column(
children: <Widget>[
uppersection,
],
),
);
}
}
You should rather make upperSection a getter.
Like so:
Container get upperSection{
return Container(
child: Row(
children: <Widget>[
StreamBuilder<BluetoothDeviceState>(
stream: device.state,
initialData: BluetoothDeviceState.connecting,
builder: (c, snapshot) => ListTile(
leading: (snapshot.data == BluetoothDeviceState.connected)
? Icon(Icons.bluetooth_connected)
: Icon(Icons.bluetooth_disabled),
title: Text('Device is ${snapshot.data.toString().split('.')[0]}.'),
subtitle: Text('${device.id}'),
trailing: StreamBuilder<bool>(
//The below stream is to show either a refresh button or
//CircularProgress based on the service discovering status,
//and a IndexedStack widget is used to present the needed widget
stream: device.isDiscoveringServices,
initialData: false,
builder: (c, snapshot) => IndexedStack(
index: snapshot.data ? 0 : 0,
children: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () => device.discoverServices(),
),
IconButton(
icon: SizedBox(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Colors.grey),
),
width: 17.0,
height: 17.0,
),
onPressed: null,
),
],
),
),
),
),
],
),
);
}
I'm fetching data from an api source , the data is fetched properly , then i store the data in sqflite , so basically after doing both , i need to check if there is connection so that i show data from internet other than that i get data back from database , now since i'm using futurebuilder which return internet async operation result , how would i be also to get list of data from database , any help is appreciated guys and thank you in advance.
This is what i have tried so far
#override
void initState() {
super.initState();
dbHelper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text("News Application"),
centerTitle: true,
backgroundColor: Colors.black,
titleTextStyle: TextStyle(color: Colors.white),
),
body: FutureBuilder (
future: Future.wait([getEverything(),dbHelper.getAllNews()]),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
if(snapshot.hasError) {
// So basically here if there is an error , i woul like to show data from database
// i tried to get data from snapshot like this : snapshot.data[0]...and snapshot.data[1]
// but no data is returned..
return new Center(
child: new CircularProgressIndicator(
backgroundColor: Colors.black,
),
);
} else {
if(snapshot.connectionState == ConnectionState.done){
return new Container(
color: Colors.black,
child: GridView.count(
padding: const EdgeInsets.all(20),
crossAxisCount: 2,
children: List.generate(snapshot.data.articles.length, (index) {
return new GestureDetector(
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailsScreen(
image: snapshot.data.articles[index].urlToImage,
author: snapshot.data.articles[index].author,
title: snapshot.data.articles[index].title,
description: snapshot.data.articles[index].description,
publishedAt: snapshot.data.articles[index].publishedAt,
content: snapshot.data.articles[index].content,
))
);
},
child: Card(
elevation: 12,
child: new Column(
children: [
Image.network(snapshot.data.articles[index].urlToImage,
width: 250,),
Text(snapshot.data.articles[index].description)
],
),
),
);
}
)));
}
}
return new Center(
child: Visibility(
visible: true,
child: CircularProgressIndicator(
backgroundColor: Colors.black,
),
),
);
},
),
);
}
I have a showDialog() function in flutter web, but it will only works this way (2 show dialog in one function), if I comment out the other one, the dialog will not show. I don't really understand why I need to put 2 showDialog() in order for it to show up. Here is the code:
onDeleteTap(String id) async {
print(id);
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Hapus?'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
],
),
),
actions: <Widget>[
TextButton(
child: Text('Batal'),
onPressed: () {
},
),
SizedBox(
width: 150.0,
child: ErrorButton(
text: "Hapus",
onClick: () {
},
),
),
],
);
},
);
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Hapus?'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
],
),
),
actions: <Widget>[
TextButton(
child: Text('Batal'),
onPressed: () {
},
),
SizedBox(
width: 150.0,
child: ErrorButton(
text: "Hapus",
onClick: () {
},
),
),
],
);
},
);
I think before you are calling onDeleteTap you must be using navigator.pop(context). You can check by not showing any dialog to check if you are really poping a screen (If you are having a pop your current screen will close or you will have a black screen) or you can use the debbuger to check all the lines that passes before getting to this code.
As seen in the picture, there is a collection structure within the firestore. I want to show it with a listview by reaching the document information at the end. But I can't view it on the screen.
Code here:
#override
Widget build(BuildContext context) {
randevular = databaseRef
.collection(
'kuaforumDB/$_salonID/BekleyenRandevular/')
.snapshots();
return StreamBuilder<QuerySnapshot>(
stream: randevular,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(!snapshot.hasData) {
return Column(
children:<Widget> [
SizedBox(
height: 100,
),
Center(
child: Image.asset("assets/images/icons/fon.webp",matchTextDirection: true,
height: 140.0,
width: 140.0,
),),
SizedBox(
height: 20
),
Center(
child: new Text('Henüz bir randevu oluşturmadınız.')
)
],
);
}
else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: new Center(
child: new CircularProgressIndicator(
value: null,
strokeWidth: 7.0,
),
)
);
} else {
return ListView(
children: snapshot.data.documents
.map((document) {
var query = databaseRef
.collection('kuaforumDB/')
.document('$_salonID')
.collection('BekleyenRandevular')
.document(document.documentID)
.collection('get')
.snapshots();
return StreamBuilder<QuerySnapshot> (
stream: query,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot2){
if (!snapshot2.hasData) return Text("Loading...");
return ListView(
children: snapshot2.data.documents
.map((DocumentSnapshot doc) => Card(
child: ListTile(
leading: IconButton(
tooltip: '',
icon: const Icon(Icons.check_circle, color: Colors.red,),
color: doc['randevuTarih']
.toDate()
.isBefore(DateTime.now())
? Colors.green
: Colors.orangeAccent,
iconSize: 30,
onPressed: () {},
),
title: Text(AppConstants.formatter
.format((doc['randevuTarih'].toDate())
.add(Duration(hours: 0)))
.toString()),
subtitle: Text('Randevu Onay Bekleniyor.'),
trailing: Icon(Icons.keyboard_arrow_right,
color: Colors.grey, size: 30.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (content) => MyPendingDetailPage(
salonID: _salonID.toString(),
userID: mPhone,
randevuID:
doc.documentID.toString(),
randevuTarih: AppConstants
.formatter
.format((doc['randevuTarih']
.toDate())
.add(Duration(hours: 0)))
.toString(),
randevuHizmet: doc['hizmetler'],
randevuFiyat:
doc['fiyat'].toString(),
randevuSure:
doc['sure'].toString(),
randevuFavori:
doc['favori'] == null
? false
: doc['favori'],
randevuBittimi:
doc['randevuTarih']
.toDate()
.isBefore(
DateTime.now())
? true
: false,
ayBasi: startofmonth,
sonrandevu : doc['randevuTarih'],
)));
}, )))
.toList(),
);
},
);
}).toList());
}
});
}
Using nested Listview in the code above may have caused a question. But I don't know how to solve this. When I check it, I see that I can actually pull the data, but I can't show it on the screen.
I am unable to build the children Operations and Logistics widget in the following code. I have tried setState and valuelistenableBuilder, but nothing is working. Operations and Logistics store their own list (and some other data), when they are first built (init is called) they fetch the data from API.
final GlobalKey<OperationsState> operationsKey = GlobalKey();
final GlobalKey<LogisticsState> logisticsKey = GlobalKey();
Widget build(BuildContext context) {
_tabsList = [
Tab(
child: Text(
'Operations',
style: CustomAppTheme.tabHeading,
overflow: TextOverflow.ellipsis,
),
),
Tab(
child: Text(
'Logistics',
style: CustomAppTheme.tabHeading,
overflow: TextOverflow.ellipsis,
),
),
];
// Operations and Logistics are stateful widget with their own state/data
_tabBarViewList = [
Tab(
child: Operations(
operationsKey: operationsKey,
logisticsKey: logisticsKey,
),
),
Tab(
child: Logistics(),
),
];
return DefaultTabController(
length: 2,
initialIndex: 0,
child: Scaffold(
key: scaffoldKey,
floatingActionButton: ValueListenableBuilder(
valueListenable: _showFloatingActionButton,
builder: (_, showButton, child) {
return showButton
? FloatingActionButton(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return CreateRequest();
})).then((val) {
// on successfull request creation I am passing 'reload' to refresh the tabs
if (val == 'reload') {
// _refreshLeaves.value++;
setState(() {
});
}
});
},
child: Icon(Icons.add),
backgroundColor: CustomAppTheme.primaryColor,
)
: Container();
},
),
appBar: AppBar(), // code omitted as not related to the question
body: ValueListenableBuilder(
valueListenable: _refreshLeaves,
builder: (_, refresh, child) {
return TabBarView(
// controller: _tabController,
children: _tabBarViewList);
},
),
),
);
}```
I finally solved it... instead of passing already initialized GlobalKey() I passed UniqueKey(). This updated the children correctly whenever setState() is called.