passing data immediately without using setstate - flutter

Is there a way to pass data when from alert dialogue box to the same screen immediately without using setstate?
Widget setupShadeColorContainer(
List<ShadeColorDatabase> allShadeData, BuildContext context) {
return SizedBox(
height: 300.0, // Change as per your requirement
width: 300.0, // Change as per your requirement
child: GridView.builder(
shrinkWrap: true,
itemCount: allShadeData.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4, crossAxisSpacing: 10, mainAxisSpacing: 10),
itemBuilder: (ctx, i) {
return GestureDetector(
onTap: () {
rPassedChooseColor = allShadeData[i].rValue;
gPassedChooseColor = allShadeData[i].gValue;
bPassedChooseColor = allShadeData[i].bValue;
setState(() {
Navigator.pop(context, [
rPassedChooseColor,
gPassedChooseColor,
bPassedChooseColor
]);
});
},
child: Container(
child: Stack(
children: [
Container(
color: Color.fromRGBO(
allShadeData[i].rValue!.toInt(),
allShadeData[i].gValue!.toInt(),
allShadeData[i].bValue!.toInt(),
1),
),
Padding(
padding: const EdgeInsets.only(top: 45, left: 5),
child: Text("${allShadeData[i].colorCode}"),
)
],
),
),
);
}),
);
}
showAllColors(
List<ShadeColorDatabase> shadeData, BuildContext context) async {
final size = MediaQuery.of(context).size;
final GlobalKey<FormState> _form = GlobalKey<FormState>();
TextEditingController searchController = TextEditingController();
showDialog(
barrierDismissible: true,
context: context,
builder: (ctx) {
return WillPopScope(
onWillPop: () async => false,
child: AlertDialog(
title: Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Fashion's Color",
style: TextStyle(
color: ChooseColor(0).appBarColor1, fontSize: 14),
),
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.clear))
],
),
Form(
key: _form,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
border: const OutlineInputBorder(
borderSide: BorderSide.none,
),
contentPadding: EdgeInsets.symmetric(
vertical: size.height * 0.001,
horizontal: size.width * 0.030),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.red, width: 1),
borderRadius: BorderRadius.circular(5)),
// labelText: 'Phone Number',
fillColor: const Color(0xffF6F9FA),
filled: true,
hintText: 'Search Color',
prefixIcon: const Icon(Icons.search),
hintStyle: TextStyle(
fontSize: size.height * 0.012 +
size.width * 0.012,
color: Colors.black26),
),
controller: searchController,
),
SizedBox(height: size.height * 0.035),
],
)),
],
),
),
content: setupShadeColorContainer(shadeData, context),
),
);
});
This is my dialogue box this dilogue box open over a screen and i want to pass data from this dilogue box to the same page immediately without using setstate is there any way i can achieve that?. Thanks

showDialog() can return future, and you can return data(myData) on closing dialog using
Navigator.of(context).pop(myData);
showAllColors() async {
final data = await showDialog(context: context, builder: (c){
// on closing dialog
Navigator.of(context).pop(passData);
return data;
}
When you use showAllColors try putting await on async method and also make sure to handle null data.

Related

Flutter ListView can't tap items

I'm using flutter_maps map and overlaying a custom search bar with drop down menu. When user searches, locations appear and should be clickable. Using the below code, the UI appears, but clicks aren't possible and nothing happens. I've also noticed the list view can't be scrolled either, can anyone see what the issue is?
List<Widget> _locations = [];
Future<void> searchLocations(String input) async {
final database =
await $FloorLocalDatabase.databaseBuilder('local_database.db').build();
final locationsDao = database.locationDao;
locationsDao.searchLocations(input).then((value) => {
setState(() {
_locations = [];
value.forEach((element) {
_locations.add(locationItem(element));
});
})
});
}
#override
Widget build(BuildContext context) {
return FlutterMap(
options: MapOptions(
center: LatLng(51.5072, -0.1276),
zoom: zoom,
interactiveFlags: InteractiveFlag.pinchZoom | InteractiveFlag.drag,
),
children: [
TileLayer(
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png"),
MarkerLayer(markers: _markers),
Padding(
padding:
const EdgeInsets.only(top: 16.0, left: 16.0, right: 16.0),
child: SizedBox(
height: 56.0,
child: Card(
shape: roundedCorner32,
elevation: 6.0,
child: Wrap(children: [
Column(children: [
TextField(
cursorColor: Theme.of(context).colorScheme.secondary,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(left: 16.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
borderSide: const BorderSide(
width: 0,
style: BorderStyle.none,
)),
filled: true,
hintStyle: TextStyle(color: Colors.grey[800]),
hintText: search,
fillColor: Colors.white),
onChanged: (value) {
searchLocations(value);
},
),
if (_locations.isNotEmpty) ...[
Card(
color: Theme.of(context).colorScheme.primary,
shape: roundedCorner16,
elevation: 6.0,
child: Wrap(children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.all(8.0),
color: Theme.of(context).colorScheme.primary,
child: ListView.separated(
shrinkWrap: true,
itemCount: _locations.length,
itemBuilder:
(BuildContext context, int index) {
return GestureDetector(
onTap: () {
print("XXXXXXXXXXX");
},
child: _locations[index],
);
}, separatorBuilder: (BuildContext context, int index) {
return const SizedBox(height: 8.0);
},),
),
),
]),
)
]
]),
]),
),
)),
]);
}
Widget locationItem(Location location) {
return AutoSizeText(buildFullLocation(location), maxLines: 1);
}
How about try wrap the TextFiled widget in an Inkwell or GestureDetector widget?
GestureDetector(
onTap: (){},
child: TextField()),

Dynamic listview in flutter

I'm new to Flutter, but I'm trying to make an app with a ListView. The ListView is a list of exercises, within each exercise the number of sets can be added. The problem comes when i press the button add exercise. The above exercise with sets is just copied. I would like a new exercise tab with 0 sets. Below the code can be found.
Here is a picture of the list.
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "null",
);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
titleSection,
// ignore: unnecessary_new
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text);
eCtrl.clear();
setState(() {});
},
),
Expanded(
// ignore: unnecessary_new
child: new ListView.builder(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Card(
child: Padding(
padding: EdgeInsets.all(10),
child: ExpansionTile(
initiallyExpanded: true,
title: Text(
litems[Index],
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(child: Text(" ")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
],
),
// ignore: sort_child_properties_last
children: <Widget>[
ListView.builder(
shrinkWrap: true,
itemCount: sets.length,
itemBuilder:
(BuildContext context, int Index1) {
return Dismissible(
key: UniqueKey(),
// only allows the user swipe from right to left
direction:
DismissDirection.endToStart,
// Remove this product from the list
// In production enviroment, you may want to send some request to delete it on server side
onDismissed: (_) {
setState(() {
sets.removeAt(Index1);
});
},
// ignore: sort_child_properties_last
child: Card(
elevation: 0,
child: Padding(
padding: EdgeInsets.all(1),
child: ListTile(
title: Text(
" ",
style: const TextStyle(
fontSize: 10,
fontWeight:
FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(
child: Text(" "),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
],
),
))),
background: Container(
color: Colors.red,
margin:
const EdgeInsets.symmetric(
horizontal: 15,
),
alignment: Alignment.centerRight,
child: const Text(
"Delete",
style: TextStyle(
color: Colors.white,
),
)));
}),
Padding(
padding: EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () {
sets.add('sets-test');
setState(() {});
},
child: const Text('+ Add Set')),
),
const SizedBox(height: 5),
],
leading: IconButton(
icon: const Icon(
Icons.close,
color: Colors.red,
),
onPressed: () {
litems.removeAt(Index);
setState(() {});
},
),
)));
})),
ElevatedButton(
onPressed: () {
litems.add("new");
setState(() {});
},
child: const Text('Add Exercises')),
ElevatedButton(
onPressed: () {
createUser(user1, "5");
exercise.setExerciseTotals();
//saveExercise(exercise);
final workout = Workout([exercise, exercise1], "Det gik fint",
"10", 60, "type", "name", true, 0, 0, 0);
//workout.setWorkoutTotals();
saveWorkout(workout, userID);
},
child: const Text('pop')),
bottomSection,
],
),
));
}
You are not copy the item, you logic is that add new Item with null value, change decoratedField to this:
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "0",
);

Searchbar didn't worked properly in the draggablescrollablesheet (Flutter)

I'm a Flutter newbie. I had a trouble with my own searchbar in the draggable bottom sheet. I created a draggable bottom sheet to search for information when clicking to the search field from the main screen. I added a searchbar and a listview in the sheet but the searchbar did not work properly. It could not instantly filter out the data, it just showed the results when closing the keyboard. Anyone helps me please.
class AddPersonalInfo extends StatefulWidget {
final String mail, password;
const AddPersonalInfo({Key? key, required this.mail, required this.password})
: super(key: key);
#override
_AddPersonalInfoState createState() => _AddPersonalInfoState();
}
class _AddPersonalInfoState extends State<AddPersonalInfo> {
TextEditingController _search = TextEditingController();
List<City> cites = [
City(id: 1, code: "HN", name: "Ha Noi"),
City(id: 2, code: "HCM", name: "Ho CHi Minh"),
City(id: 3, code: "DN", name: "Da Nang"),
City(id: 4, code: "HP", name: "Hai Phong"),
City(id: 5, code: "CT", name: "Can Tho"),
City(id: 6, code: "DNN", name: "Dong Nai"),
City(id: 7, code: "KH", name: "Khanh Hoa"),
City(id: 8, code: "PY", name: "Phu Yen"),
City(id: 9, code: "NT", name: "Nha Trang"),
City(id: 10, code: "VL", name: "Vinh Long"),
City(id: 11, code: "HD", name: "Hai Duong"),
City(id: 12, code: "BD", name: "Binh Duong")
];
City? selected;
List<City> foundCity = [];
#override
void initState() {
super.initState();
setState(() {
foundCity = cites;
});
}
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
Orientation orientation = MediaQuery.of(context).orientation;
return GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: LayoutBuilder(builder: (context, snapshot) {
if (snapshot.maxWidth <= screenSize.width &&
orientation == Orientation.portrait) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.fromLTRB(30 * screenScale(context), 0,
30 * screenScale(context), 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
children: [
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.only(
bottom: 20 * screenScale(context)),
child: introText("Create account", context),
),
backBtn(context),
],
),
mainText(
"Let's create an account to grab all latest gadgets and enjoy the best experiences.",
context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [_fnameField(), _lnameField()],
),
_phoneField(),
GestureDetector(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (context) => buildSheet(),
),
child: Container(
height: 50,
margin: EdgeInsets.only(top: 15),
padding: EdgeInsets.only(left: 10, right: 7),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(7),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
selected == null
? Text("Select city",
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade700))
: Text("${selected!.name}",
style: TextStyle(
fontSize: 16, color: Colors.black)),
Icon(Ionicons.chevron_down_outline, size: 24)
],
),
),
)
],
),
),
);
} else {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.fromLTRB(30 * screenScale(context), 0,
30 * screenScale(context), 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [],
),
),
);
}
}),
),
),
);
}
Widget buildSheet() {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: DraggableScrollableSheet(
initialChildSize: 0.9,
builder: (_, controller) => Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
child: Column(
children: [
Divider(
thickness: 4,
color: Colors.grey.shade300,
endIndent: 170,
indent: 170,
),
Padding(
padding: EdgeInsets.only(bottom: 15, top: 5),
child: Text("Select city",
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold)),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: TextFormField(
controller: _search,
keyboardType: TextInputType.name,
style: TextStyle(fontSize: 16 * fontScale(context)),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(7 * screenScale(context))),
contentPadding:
EdgeInsets.only(top: 10 * screenScale(context)),
hintText: 'Search',
prefixIcon: Icon(Ionicons.search_outline),
),
onChanged: (value) {
setState(() {
foundCity = cites
.where(
(city) => city.name.toLowerCase().contains(value))
.toList();
});
},
),
),
Expanded(
child: foundCity.length > 0
? ListView.builder(
itemCount: foundCity.length,
itemBuilder: (context, index) {
final city = foundCity[index];
return ListTile(
title: Text(city.name),
onTap: () {
Navigator.of(context).pop();
setState(() {
selected = city;
});
},
);
},
)
: Padding(
padding: EdgeInsets.only(top: 50),
child: Text(
"No data.",
style: TextStyle(fontSize: 16),
),
),
),
],
),
),
),
);
}
}
Ok I checked you code, and it seems you missed a small issue, when you're creating a showModalBottomSheet, it's no longer part of your stateful widget
I've adjusted the code so that it works now:
Widget buildSheet(BuildContext context) {
return StatefulBuilder(builder: (BuildContext context, setState) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: DraggableScrollableSheet(
initialChildSize: 0.9,
builder: (_, controller) => Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
child: Column(
children: [
Divider(
thickness: 4,
color: Colors.grey.shade300,
endIndent: 170,
indent: 170,
),
Padding(
padding: EdgeInsets.only(bottom: 15, top: 5),
child: Text("Select city",
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold)),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: TextFormField(
controller: _search,
keyboardType: TextInputType.name,
style: TextStyle(fontSize: 16),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(7)),
contentPadding: EdgeInsets.only(top: 10),
hintText: 'Search',
prefixIcon: Icon(Icons.access_alarm),
),
onChanged: (value) {
setState(() {
foundCity = cites
.where((city) =>
city.name!.toLowerCase().contains(value))
.toList();
});
},
),
),
Expanded(
child: foundCity.isNotEmpty
? ListView.builder(
itemCount: foundCity.length,
itemBuilder: (context, index) {
final city = foundCity[index];
return ListTile(
title: Text(city.name!),
onTap: () {
Navigator.of(context).pop();
setState(() {
selected = city;
});
},
);
},
)
: Padding(
padding: EdgeInsets.only(top: 50),
child: Text(
"No data.",
style: TextStyle(fontSize: 16),
),
),
),
],
),
),
),
);
});
}

Tab Bar in Flutter

I want to implement Tab Bar in my application having length 2 named "Need Help" and "Help Requests". In "Need Help" tab, I want my first container (i.e. Upload data to Firestore Database) and in "Help Requests" tab, I want my second container (i.e. Retrieve data from Firestore Database). I am new to flutter and will be very much grateful to you if you can help me.
Source code:
import 'package:chat_app/group_chats/group_info.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../constants.dart';
import '../global_data.dart';
class FinancialRoom extends StatelessWidget {
final String groupChatId, groupName;
FinancialRoom({required this.groupName, required this.groupChatId, Key? key})
: super(key: key);
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final FirebaseAuth _auth = FirebaseAuth.instance;
final _formKey = GlobalKey<FormState>();
TextEditingController amountValue = TextEditingController();
void onSend() async {
Map<String, dynamic> data = {
"amount": amountValue.text,
"sendBy": _auth.currentUser!.displayName,
"type": "text",
"time": FieldValue.serverTimestamp(),
};
amountValue.clear();
await _firestore
.collection('groups')
.doc(groupChatId)
.collection('chats')
.add(data);
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: Text(groupName),
actions: [
IconButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => GroupInfo(
groupName: groupName,
groupId: groupChatId,
),
),
),
icon: Icon(Icons.more_vert)),
],
),
body: SafeArea(
child: ListView(padding: EdgeInsets.all(20.0), children: [
Container(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 10.0,
),
TextFormField(
controller: amountValue,
decoration: InputDecoration(
hintText: 'Enter the amount you want',
labelText: 'Enter the amount you want',
prefixIcon: Icon(Icons.account_balance_wallet_outlined),
enabledBorder: kEnabledBorder,
focusedBorder: kFocusedBorder,
errorBorder: kErrorBorder,
focusedErrorBorder: kErrorBorder,
),
onTap: () {
},
// The validator receives the text that the user has entered.
validator: (value) {
if (value!.isEmpty) {
return 'Please enter the amount you want';
}
return null;
},
),
SizedBox(
height: kInputSpacing,
),
SizedBox(
width: double.infinity,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
color: Colors.blue,
textColor: Colors.white,
padding: EdgeInsets.only(top: 16.0, bottom: 16.0),
onPressed: onSend,
child: Text(
'SEND',
style: kButtonTextStyle,
),
),
),
],
),
),
Container(
height: size.height / 1.27,
width: size.width,
child: StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('groups')
.doc(groupChatId)
.collection('chats')
.orderBy('time')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
Map<String, dynamic> data =
snapshot.data!.docs[index].data()
as Map<String, dynamic>;
return messageTile(size, data);
},
);
} else {
return Container();
}
},
),
),
]),
),
);
}
Widget messageTile(Size size, Map<String, dynamic> data) {
return Builder(builder: (_) {
if (data['type'] == "text") {
return Container(
width: size.width,
alignment: data['sendBy'] == _auth.currentUser!.displayName
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 14),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.blue,
),
child: Column(
children: [
Text(
data['sendBy'],
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
SizedBox(
height: size.height / 200,
),
Text(
data['amount'],
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
)),
);
} else if (data['type'] == "img") {
return Container(
width: size.width,
alignment: data['sendBy'] == _auth.currentUser!.displayName
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
height: size.height / 2,
child: Image.network(
data['amount'],
),
),
);
} else if (data['type'] == "notify") {
return Container(
width: size.width,
alignment: Alignment.center,
child: Container(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black38,
),
child: Text(
data['message'],
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
);
} else {
return SizedBox();
}
});
}
}
It's very straightforward to implement a simple TabBar in your app. All you need is a TabController and two widgets called TabBar and TabBarView. Here is a simple example:
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
]),
),
body: TabBarView(children: [
// Tab 1
Container(color: Colors.red),
// Tab 2
Container(color: Colors.blue),
]),
),
);
Now all you need to do is to replace children inside TabBarView with whatever you want to display.

Enabled button with. a state variable in a blocbuilder

I have a bloc which I use to upload images from the gallery. I then have a TextField where I enter text. And finally another bloc where I have a button. The button is used to submit the data to a server(image and text). My problem is enabling the button. My code for enabling is:
class ObservationPage extends StatefulWidget {
#override
_ObservationPageState createState() => _ObservationPageState();
}
class _ObservationPageState extends State<ObservationPage> {
List<File> files = [];
TextEditingController _descriptionController = TextEditingController();
TextEditingController _taskNameController = TextEditingController();
String taskName;
List<String> _selectedUsers = [];
bool _enabled = false;
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
BlocProvider.of<ImageBloc>(context).add(DeleteAllImages(files: files));
return true;
},
child: Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
centerTitle: true,
iconTheme: IconThemeData(
color: RioColours.darkGrey,
),
backgroundColor: Colors.grey[200],
elevation: 0,
title: Text('Observation',style:TextStyle(color: Colors.black))
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(left: 20.0, right: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20,),
Column(children: [
AutoSizeText(
'Make an Observation and assign to a colleague ',
maxLines: 1,
style: RioTextStyle.auditQuestion(context),
),
SizedBox(height: 20,),
AttachPhoto(),
SizedBox(height: 20,),
BlocBuilder<ImageBloc, ImageState>(builder: (context, state) {
if (state is ImageInitial) {
return Container();
}
if (state is ImageLoadInProgress) {
return CircularProgressIndicator();
}
if (state is ImageLoadSuccess) {
//print(state.files);
files = state.files;
return SizedBox(
//height: MediaQuery.of(context).size.height*.5,
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: state.files.length,
itemBuilder: (context, item) {
return Padding(
padding: const EdgeInsets.only(bottom:10.0),
child: ImageContainer(context: context, file: state.files[item]),
);
}),
);
}
if (state is NoImages) {
return Container();
}
if (state is ImageLoadFailure) {
return Container();
}
return Container();
})
]),
Text(
'Notes',
style: RioTextStyle.auditHeaders(context),
),
SizedBox(
height:10
),
SizedBox(height: 140,
child: TextField(
textInputAction: TextInputAction.next,
keyboardType: TextInputType.multiline,
maxLines: 5,
controller: _descriptionController,
onChanged: (String value) {
setState(() {});
},
style: TextStyle(fontSize: 16.0, height: 2.0, color: Colors.black),
decoration: new InputDecoration(
hintStyle: RioTextStyle.hintText(context),
fillColor: Colors.white,
filled: true,
focusedBorder: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey[300]),
),
hintText: "Enter your notes here"
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * .04,
),
Text(
'Task Name',
style: RioTextStyle.auditHeaders(context),
),
SizedBox(
height: 10
),
TextField(
controller: _taskNameController,
onChanged: (String value) {
setState(() {});
},
textInputAction: TextInputAction.next,
style: TextStyle(fontSize: 16.0, height: 2.0, color: Colors.black),
decoration: new InputDecoration(
fillColor: Colors.white,
filled: true,
focusedBorder: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey[300]),
),
hintStyle: RioTextStyle.hintText(context),
hintText: "Enter your task name here"
),
),
SizedBox(
height: 20
),
SizedBox(
height: 20
),
BlocBuilder<ObservationBloc, ObservationState>(builder: (context, state) {
if (state is UsersLoadInProgress) {
return Center(child: CircularProgressIndicator());
}
if (state is UsersLoadSuccess) {
final users = state.users;
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
'Assign to',
style: RioTextStyle.auditHeaders(context),
),
SizedBox(
height: MediaQuery.of(context).size.height * .02,
),
MultiSelectDialogField(
buttonIcon: Icon(Icons.arrow_drop_down,color: Colors.grey,),
chipDisplay: MultiSelectChipDisplay(
chipColor: Colors.white,
textStyle: TextStyle(color: Colors.black),
),
onConfirm: (results) {
_selectedUsers.clear();
for (User user in results) {
_selectedUsers.add(user.id);
setState(() {
_enabled = true;
});
}
// _selectedUsers = results;
print(_selectedUsers);
},
items: users.map((user) => MultiSelectItem<User>(user, user.first_name)).toList(),
title: Text(
'Assign Owners',
style: TextStyle(color: RioColours.splashBlue),
),
cancelText: Text(
"CANCEL",
style: TextStyle(color: RioColours.splashBlue),
),
confirmText: Text(
"ASSIGN",
style: TextStyle(color: RioColours.splashBlue),
),
buttonText: Text(
"Choose Owners",
style: RioTextStyle.dropDownHint(context),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * .05,
),
]);
}
if (state is UserLoadFailure) {
return Text('error');
}
return Container();
}),
BlocConsumer<ButtonBloc, ButtonState>(listener: (context, state) {
if (state is UploadFailure) {
RioHelpers.showFailureFlushBar(context, 'Error Uploading');
Navigator.of(context).pop();
}
if (state is UpLoadSuccess) {
_submit();
}
}, builder: (context, state) {
if (state is Loading) {
return Center(child: CircularProgressIndicator());
}
if (state is ButtonInitial) {
print(_enabled);
return SizedBox(
height: MediaQuery.of(context).size.height * .07,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: (_descriptionController.text.isNotEmpty && _taskNameController.text.isNotEmpty && _enabled) ? () => callupLoad() : null,
color: RioColours.splashBlue,
child: Text(
'Submit',
style: RioTextStyle.buttonText(context),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
);
}
if (state is UpLoadSuccess) {
BlocProvider.of<ImageBloc>(context).add(DeleteAllImages(files: files));
return SizedBox(
height: MediaQuery.of(context).size.height * .07,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: (_descriptionController.text.isNotEmpty && _taskNameController.text.isNotEmpty && _enabled) ? () => callupLoad() : null,
color: RioColours.splashBlue,
child: Text(
'Submit',
style: RioTextStyle.buttonText(context),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
);
}
if (state is UploadFailure) {
return SizedBox(
height: MediaQuery.of(context).size.height * .07,
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () {},
//onPressed: (controller.text.isNotEmpty && _enabled) ? () => callupLoad() : null,
color: RioColours.splashBlue,
child: Text(
'Submit',
style: RioTextStyle.buttonText(context),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
);
}
return Container(
color: Colors.yellow,
height: 10,
);
}),
SizedBox(
height: MediaQuery.of(context).size.height * .12,
),
],
),
),
)),
);
}
callupLoad() {
BlocProvider.of<ButtonBloc>(context).add(UploadTaskRequest(files: files, notes: _descriptionController.text, taskName: _taskNameController.text, owners: _selectedUsers));
}
_submit() async {
print('called called called called called ');
RioHelpers.showSuccessFlushBar(context, 'Observation recorded');
BlocProvider.of<ImageBloc>(context).add(DeleteAllImages(files: files));
await Future.delayed(Duration(seconds: 3));
Navigator.of(context).pop();
}
#override
void initState() {
BlocProvider.of<ObservationBloc>(context).add(RequestUsers());
super.initState();
print("init calledx");
_enabled = false;
}
}
So the _controller works great for enabling/disabling the button. However _enabled which is a boolean state variable is my problem. In my blocbuilder I update my state to _enabled= true when the image upload is successful. However this is not making any difference to enabling the button. I've also updated the state variable using a bloclistener but that didn't work either.
How can I trigger the button to be enabled when I upload an image from the Gallery
Set a local variable in the builder, not in the class itself, unless you want to use in another place. If you want to do so, wrap the variable assignment in a setState call.