How do I select individual image for a favorite icon with onPressed ()? - flutter

Here is the entire code. I simply want the heart icon to change color when selected as favorite, then push the saved favorite item to a saved favorites page. I have no idea how to do it with stream builder.
ERROR is : In this code, when I click on a image icon, all image's icon get
selected as favorite.
class CloudAlbum extends StatefulWidget {
static const routeName = '/album';
#override
_CloudAlbumState createState() => _CloudAlbumState();
}
class _CloudAlbumState extends State<CloudAlbum> {
#override
void initState() {
super.initState();
_getCurrentUser();
}
final FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseUser loggedInUser ;
_getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
try {
if (user != null) {
setState(() {
loggedInUser = user;
print(loggedInUser.email);
print(loggedInUser.uid);
final email = loggedInUser.email;
return email;
});
}
} catch(e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
String email = "";
setState(() {
email = loggedInUser.email;
});
//final imgid = ModalRoute.of(context).settings.arguments as String;
final favImg = Provider.of<FavImg>(context, listen: false);
var users = Firestore.instance.collection('abc').document('xyz').collection(email).snapshots();
return StreamBuilder(
stream: users,
builder: (ctx, streamSnapshot) {
if (streamSnapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
final docs = streamSnapshot.data.documents;
//List<bool> _isFavorited = List<bool>.generate(docs.length, (_) => false);
print(docs);
return GridView.builder(
itemCount: docs.length,
itemBuilder: (ctx, index) =>
Container(
padding: EdgeInsets.all(5),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: GridTile(
child: GestureDetector(
onTap: () {
// Navigator.of(context).pushNamed(
// FullImage.routeName);
},
child: Hero(
tag: docs[index]['id'],
child: FadeInImage(
placeholder: AssetImage('assets/images/placeholder.png'),
image: NetworkImage(docs[index]['imgurl']),
fit: BoxFit.cover,
),
),
),
footer: GridTileBar(
backgroundColor: Colors.black26,
leading:
Consumer<FavImg>(
builder: (ctx, favImg, _) =>
// IconButton(
// onPressed: () => setState(()
// => _isFavorited[index]= !_isFavorited[index]),
// icon: _isFavorited[index]
// ? Icon(Icons.star)
// : Icon(Icons.star_border),
// ),
IconButton(
icon: Icon(
favImg.isFavorite ? Icons.favorite : Icons.favorite_border,
size: 35.0,
),
color: Colors.red,
onPressed: () {
favImg.toggleFavoriteStatus(
docs[index]['id'],
);
},
),
),
),
),
),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 2,
crossAxisSpacing: 1,
mainAxisSpacing: 5,
),
);
}
);
}
}
favimg.dart
class FavImg with ChangeNotifier {
final String imageUrl;
final String id;
bool isFavorite;
FavImg({
#required this.imageUrl,
#required this.id,
this.isFavorite = false,
});
void toggleFavoriteStatus(String id) {
isFavorite = !isFavorite;
notifyListeners();
}
}
ERROR is : In this code, when i click on a image icon, all image's icon get selected as favorite.

Related

ImagePicker with Bloc - Flutter

How to add a stream with a picture(ImagePicker) in the bloc architecture, which can be selected from the phone, what should the widget look like?
My example is without validation whether it is to be included?
How should I work in a bloc along with the avatar photo?
I do not know how to approach it and what steps would be taken when it comes to both validation of such a photo, if possible, and the use of stream with bloc, any help is very welcome.
class ProfileView extends StatefulWidget {
const ProfileView({Key? key}) : super(key: key);
#override
_ProfileViewState createState() => _ProfileViewState();
static Route route() {
return MaterialPageRoute<void>(builder: (_) => ProfileView());
}
}
class _ProfileViewState extends State<ProfileView> {
final bloc = Bloc();
#override
Widget build(BuildContext context) {
return Scaffold(
body: _profilePage(context),
);
}
Widget _profilePage(BuildContext context) {
return ColorfulSafeArea(
color: orange,
child: Center(
child: Column(
children: [
_changeAvatarButton(context),
SizedBox(height: 15),
_usernameTile(),
SizedBox(height: 5),
_cityTile(),
SizedBox(height: 60),
],
),
),
);
// });
}
// Profile avatar
Widget _avatar() {
return CircleAvatar(
radius: 83,
backgroundColor: orange,
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 80,
child: Icon(personIcon, size: 60, color: orange),
),
);
}
Widget _changeAvatarButton(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 83,
backgroundColor: orange,
child: _image == null
? _avatar()
: ClipRRect(
borderRadius: BorderRadius.circular(83),
child: Image.file(
_image!,
height: 160,
// Change the size up or down accordingly border radius
width: 160,
// Change the size up or down accordingly border radius
fit: BoxFit.cover,
)),
),
CustomButtonText(
onPressed: () {
_showPicker(context);
},
title: changePhoto,
textColor: teal),
],
);
}
File? _image;
final picker = ImagePicker();
Future getImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.gallery, maxWidth: 1800, maxHeight: 1800);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print(getImageText);
}
});
}
Future getCameraImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 1800,
maxHeight: 1800,
);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print(getImageText);
}
});
}
void _showPicker(BuildContext context) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(photoIcon),
title: Text(showPickerPhoto),
onTap: () async {
await getImage();
Navigator.of(context).pop();
}),
ListTile(
leading: Icon(cameraIcon),
title: Text(showPickerCamera),
onTap: () async {
await getCameraImage();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
Widget _usernameTile() {
return StreamBuilder(
stream: bloc.name,
builder: (context, snapshot) {
return CustomTextField(
title: 'Name',
obscureText: false,
colour: Colors.black,
keyboardType: TextInputType.name,
labelText: labelTextUsername,
onChanged: bloc.changeName,
errorText: snapshot.error != null ? 'invalid name' : null
// onChanged: (newValue) {
// bloc.changeName(newValue);
// },
);
});
}
Widget _cityTile() {
return StreamBuilder(
stream: bloc.city,
builder: (context, snapshot) {
return CustomTextField(
title: 'City',
obscureText: false,
colour: Colors.black,
keyboardType: TextInputType.name,
labelText: labelTextCity,
onChanged: bloc.changeCity,
errorText: snapshot.error != null ? 'invalid city' : null
);
});}
}
Validators looks in this way:
class Validators {
static final RegExp _nameRegExp = RegExp(
r'^(?=.*[a-z])[A-Za-z ]{3,}$',
);
final validateName =
StreamTransformer<String, String>.fromHandlers(handleData: (name, sink) {
if (name.contains(_nameRegExp)) {
sink.add(name);
} else {
sink.addError('Enter a valid name');
}
});
static final RegExp _cityRegExp = RegExp(
r'^[a-zA-Z]+(?:[\s-][a-zA-Z]+)*$',
);
final validateCity =
StreamTransformer<String, String>.fromHandlers(handleData: (city, sink) {
if (city.contains(_cityRegExp)) {
sink.add(city);
} else {
sink.addError('Enter a valid city');
}
});
static final RegExp _avatarRegExp = RegExp(
r'/.*\.(gif|jpe?g|bmp|png)$/igm',
);
final validateAvatar =
StreamTransformer<String, String>.fromHandlers(handleData: (avatar, sink) {
if (avatar.contains(_avatarRegExp)) {
sink.add(avatar);
} else {
sink.addError('Enter a valid avatar photo');
}
});
}
and Bloc:
import 'dart:async';
import 'dart:io';
import 'validators.dart';
class Bloc extends Validators {
//instances
//
final _avatarPath = StreamController<File>();
final _name = StreamController<String>();
final _city = StreamController<String>();
//add data stream
Stream<File> get avatarPath => _avatarPath.stream;
Stream<String> get name => _name.stream.transform(validateName);
Stream<String> get city => _city.stream.transform(validateCity);
// change data
Function(File) get changeAvatarPath => _avatarPath.sink.add;
Function(String) get changeName => _name.sink.add;
Function(String) get changeCity => _city.sink.add;
//for cleanup
void dispose() {
_avatarPath.close();
_name.close();
_city.close();
}
}
// bloc.changeName---> bloc.nameController.sin.add
final bloc = new Bloc();

Flutter : How to get information about which picture in the grid has been selected?

How to get information about which picture in the grid has been selected in flutter. Please check my code!
I really need an answer to this. Please help me. I am looking forward to hearing from all of you.
Getting image and put it into a grid.
ImageEvalation.dart
class ImageEvaluation extends StatefulWidget {
#override
_ImageEvaluationState createState() => _ImageEvaluationState();
}
class _ImageEvaluationState extends State<ImageEvaluation> {
File _selectedFile;
bool _inProcess = false;
String colorCode = '#33695d';
getImage(ImageSource source, BuildContext context) async {
this.setState(() {
_inProcess = true;
});
// File image = await ImagePicker.pickImage(source: source);
final _picker = ImagePicker();
PickedFile image = await _picker.getImage(source: source);
if (image != null) {
// Remove crop attribute if we don't want to resize the image
File cropped = await ImageCropper.cropImage(
sourcePath: image.path,
aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1),
compressQuality: 100, // 100 means no compression
maxWidth: 700,
maxHeight: 700,
compressFormat: ImageCompressFormat.jpg,
androidUiSettings: AndroidUiSettings(
toolbarColor: HexColor(colorCode),
toolbarTitle: "RPS Cropper",
statusBarColor: HexColor(colorCode),
backgroundColor: Colors.white,
//toolbarWidgetColor: HexColor(colorCode),
activeControlsWidgetColor: HexColor(colorCode),
//dimmedLayerColor: HexColor(colorCode),
cropFrameColor: HexColor(colorCode),
cropGridColor: HexColor(colorCode),
),
);
this.setState(() {
_selectedFile = cropped;
_inProcess = false;
//_showDelete = true;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UploadScreen(
image: _selectedFile,
),
),
);
} else {
this.setState(() {
_inProcess = false;
});
}
}
#override
Widget build(BuildContext context) {
return _inProcess
? Loading()
: Scaffold(
body: StreamProvider<List<ImageProperty>>.value(
value: User_DatabaseService().pictureData,
child: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Text('GridView'),
PictureLinkGrid(),
Text('Image Evulation'),
MaterialButton(
onPressed: () {
getImage(ImageSource.camera, context);
},
color: Colors.deepOrange,
child: Text(
'NEXT',
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
),
);
}
}
Make a grid for my images.
PictureGrid.dart
class PictureLinkGrid extends StatefulWidget {
#override
_PictureLinkGridState createState() => _PictureLinkGridState();
}
class _PictureLinkGridState extends State<PictureLinkGrid> {
#override
Widget build(BuildContext context) {
final pictureData = Provider.of<List<ImageProperty>>(context) ?? [];
final neededPicture = [];
final demoPicture = [];
int count = 0;
// get Demo Picture
pictureData.forEach((picture) {
if (picture.title.contains('demo')) {
demoPicture.add(picture);
}
});
// get Needed Picture
pictureData.forEach((picture) {
if (picture.display_count < 10 && !picture.title.contains('demo')) {
print('${picture.title} is NOT null');
neededPicture.add(picture);
} else {
print('${picture.title} is null');
}
});
// fill in the empty picture
count = 0;
while (neededPicture.length < 9) {
neededPicture.add(demoPicture[count]);
count++;
}
return GridView.builder(
//itemCount: neededPicture.length,
itemCount: neededPicture.length,
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
print(
'Picture title in picturelink grid: ${neededPicture[index].title}');
return TouchableWebImageCard(imagePath: neededPicture[index].url);
});
}
}
Make ImageCard which can be clicked and unchecked.
TouchableWebImageCard.dart
class TouchableWebImageCard extends StatefulWidget {
String imagePath;
TouchableWebImageCard({#required this.imagePath});
//
#override
_TouchableWebImageCardState createState() =>
_TouchableWebImageCardState(imagePath);
}
class _TouchableWebImageCardState extends State<TouchableWebImageCard> {
// To pass parameters
double width;
double height;
String imagePath;
_TouchableWebImageCardState(this.imagePath);
//
bool isChecked = false;
double sigmaX = 0.0;
double sigmaY = 0.0;
double showBorder = 0;
//
checkIcon() {
return isChecked
? Center(
child: Icon(
Icons.check_circle,
color: Colors.white,
size: 50,
),
)
: Container();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Center(
child: SpinKitCircle(
color: HexColor('#33695d'),
size: 50,
),
),
Center(
child: InkWell(
child: Stack(
children: <Widget>[
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: imagePath,
),
checkIcon(),
],
),
onTap: () {
print('Image Path: $imagePath');
if (isChecked != true) {
setState(
() {
showBorder = 4.0;
isChecked = !isChecked;
},
);
} else {
setState(
() {
showBorder = 0.0;
isChecked = !isChecked;
},
);
}
},
),
),
],
);
}
}
In your TouchableWebImageCard constructor add another variable int _index;
So will know which image you have selected.
Also, the "right" way to make a constructor is:
class TouchableWebImageCard extends StatefulWidget {
TouchableWebImageCard({#required this.imagePath, this._index});
String imagePath;
int _index;

Pagination for Firestore animated list flutter

I'm making a chat app that messages should be shown on screen with nice animation and my backend is Firestore, so I decided to use this (https://pub.dev/packages/firestore_ui) plugin for animating messages.
Now I want to implement pagination to prevent expensive works and bills.
Is there any way?
How should I implement it?
main problem is making a firestore animated list with pagination,
It's easy to make simple ListView with pagination.
as you can see in below code, this plugin uses Query of snapShots to show incoming messages (documents) with animation:
FirestoreAnimatedList(
query: query,
itemBuilder: (
BuildContext context,
DocumentSnapshot snapshot,
Animation<double> animation,
int index,
) => FadeTransition(
opacity: animation,
child: MessageListTile(
index: index,
document: snapshot,
onTap: _removeMessage,
),
),
);
if we want to use AnimatedList widget instead, we will have problem because we should track realtime messages(documents) that are adding to our collection.
I put together an example for you: https://gist.github.com/slightfoot/d936391bfb77a5301335c12e3e8861de
// MIT License
//
// Copyright (c) 2020 Simon Lightfoot
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show ScrollDirection;
import 'package:provider/provider.dart';
///
/// Firestore Chat List Example - by Simon Lightfoot
///
/// Setup instructions:
///
/// 1. Create project on console.firebase.google.com.
/// 2. Add firebase_auth package to your pubspec.yaml.
/// 3. Add cloud_firestore package to your pubspec.yaml.
/// 4. Follow the steps to add firebase to your application on Android/iOS.
/// 5. Go to the authentication section of the firebase console and enable
/// anonymous auth.
///
/// Now run the example on two or more devices and start chatting.
///
///
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final user = await FirebaseAuth.instance.currentUser();
runApp(ExampleChatApp(user: user));
}
class ExampleChatApp extends StatefulWidget {
const ExampleChatApp({
Key key,
this.user,
}) : super(key: key);
final FirebaseUser user;
static Future<FirebaseUser> signIn(BuildContext context, String displayName) {
final state = context.findAncestorStateOfType<_ExampleChatAppState>();
return state.signIn(displayName);
}
static Future<void> postMessage(ChatMessage message) async {
await Firestore.instance
.collection('messages')
.document()
.setData(message.toJson());
}
static Future<void> signOut(BuildContext context) {
final state = context.findAncestorStateOfType<_ExampleChatAppState>();
return state.signOut();
}
#override
_ExampleChatAppState createState() => _ExampleChatAppState();
}
class _ExampleChatAppState extends State<ExampleChatApp> {
StreamSubscription<FirebaseUser> _userSub;
FirebaseUser _user;
Future<FirebaseUser> signIn(String displayName) async {
final result = await FirebaseAuth.instance.signInAnonymously();
await result.user.updateProfile(
UserUpdateInfo()..displayName = displayName,
);
final user = await FirebaseAuth.instance.currentUser();
setState(() => _user = user);
return user;
}
Future<void> signOut() {
return FirebaseAuth.instance.signOut();
}
#override
void initState() {
super.initState();
_user = widget.user;
_userSub = FirebaseAuth.instance.onAuthStateChanged.listen((user) {
print('changed ${user?.uid} -> ${user?.displayName}');
setState(() => _user = user);
});
}
#override
void dispose() {
_userSub.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Provider<FirebaseUser>.value(
value: _user,
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Firestore Chat List',
home: _user == null ? LoginScreen() : ChatScreen(),
),
);
}
}
class LoginScreen extends StatefulWidget {
static Route<dynamic> route() {
return MaterialPageRoute(
builder: (BuildContext context) {
return LoginScreen();
},
);
}
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController _displayName;
bool _loading = false;
#override
void initState() {
super.initState();
_displayName = TextEditingController();
}
#override
void dispose() {
_displayName.dispose();
super.dispose();
}
Future<void> _onSubmitPressed() async {
setState(() => _loading = true);
try {
final user = await ExampleChatApp.signIn(context, _displayName.text);
if (mounted) {
await ExampleChatApp.postMessage(
ChatMessage.notice(user, 'has entered the chat'));
Navigator.of(context).pushReplacement(ChatScreen.route());
}
} finally {
if (mounted) {
setState(() => _loading = false);
}
}
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Firestore Chat List'),
),
body: SizedBox.expand(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Login',
style: theme.textTheme.headline4,
textAlign: TextAlign.center,
),
SizedBox(height: 32.0),
if (_loading)
CircularProgressIndicator()
else ...[
TextField(
controller: _displayName,
decoration: InputDecoration(
hintText: 'Display Name',
border: OutlineInputBorder(),
isDense: true,
),
onSubmitted: (_) => _onSubmitPressed(),
textInputAction: TextInputAction.go,
),
SizedBox(height: 12.0),
RaisedButton(
onPressed: () => _onSubmitPressed(),
child: Text('ENTER CHAT'),
),
],
],
),
),
),
);
}
}
class ChatScreen extends StatelessWidget {
static Route<dynamic> route() {
return MaterialPageRoute(
builder: (BuildContext context) {
return ChatScreen();
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Firestore Chat List'),
actions: [
IconButton(
onPressed: () async {
final user = Provider.of<FirebaseUser>(context, listen: false);
ExampleChatApp.postMessage(
ChatMessage.notice(user, 'has left the chat.'));
Navigator.of(context).pushReplacement(LoginScreen.route());
await ExampleChatApp.signOut(context);
},
icon: Icon(Icons.exit_to_app),
),
],
),
body: Column(
children: [
Expanded(
child: FirestoreChatList(
listenBuilder: () {
return Firestore.instance
.collection('messages')
.orderBy('posted', descending: true);
},
pagedBuilder: () {
return Firestore.instance
.collection('messages')
.orderBy('posted', descending: true)
.limit(15);
},
itemBuilder: (BuildContext context, int index,
DocumentSnapshot document, Animation<double> animation) {
final message = ChatMessage.fromDoc(document);
return SizeTransition(
key: Key('message-${document.documentID}'),
axis: Axis.vertical,
axisAlignment: -1.0,
sizeFactor: animation,
child: Builder(
builder: (BuildContext context) {
switch (message.type) {
case ChatMessageType.notice:
return ChatMessageNotice(message: message);
case ChatMessageType.text:
return ChatMessageBubble(message: message);
}
throw StateError('Bad message type');
},
),
);
},
),
),
SendMessagePanel(),
],
),
);
}
}
class ChatMessageNotice extends StatelessWidget {
const ChatMessageNotice({
Key key,
#required this.message,
}) : super(key: key);
final ChatMessage message;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(24.0),
alignment: Alignment.center,
child: Text(
'${message.displayName} ${message.message}',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey.shade700,
fontStyle: FontStyle.italic,
),
),
);
}
}
class ChatMessageBubble extends StatelessWidget {
const ChatMessageBubble({
Key key,
#required this.message,
}) : super(key: key);
final ChatMessage message;
MaterialColor _calculateUserColor(String uid) {
final hash = uid.codeUnits.fold(0, (prev, el) => prev + el);
return Colors.primaries[hash % Colors.primaries.length];
}
#override
Widget build(BuildContext context) {
final isMine = message.isMine(context);
return Container(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
width: double.infinity,
child: Column(
crossAxisAlignment:
isMine ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
FractionallySizedBox(
widthFactor: 0.6,
child: Container(
decoration: BoxDecoration(
color: _calculateUserColor(message.uid).shade200,
borderRadius: isMine
? const BorderRadius.only(
topLeft: Radius.circular(24.0),
topRight: Radius.circular(24.0),
bottomLeft: Radius.circular(24.0),
)
: const BorderRadius.only(
topLeft: Radius.circular(24.0),
topRight: Radius.circular(24.0),
bottomRight: Radius.circular(24.0),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (message.displayName?.isNotEmpty ?? false) ...[
const SizedBox(width: 8.0),
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _calculateUserColor(message.uid),
),
padding: EdgeInsets.all(8.0),
child: Text(
message.displayName.substring(0, 1),
style: TextStyle(
color: Colors.white,
fontSize: 24.0,
),
),
),
],
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(message.message),
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(
message.infoText(context),
style: TextStyle(
fontSize: 12.0,
color: Colors.grey.shade600,
),
),
),
],
),
);
}
}
class SendMessagePanel extends StatefulWidget {
#override
_SendMessagePanelState createState() => _SendMessagePanelState();
}
class _SendMessagePanelState extends State<SendMessagePanel> {
final _controller = TextEditingController();
FirebaseUser _user;
#override
void didChangeDependencies() {
super.didChangeDependencies();
_user = Provider.of<FirebaseUser>(context);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
void _onSubmitPressed() {
if (_controller.text.isEmpty) {
return;
}
ExampleChatApp.postMessage(ChatMessage.text(_user, _controller.text));
_controller.clear();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.grey.shade200,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
offset: Offset(0.0, -3.0),
blurRadius: 4.0,
spreadRadius: 3.0,
)
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 160.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
filled: true,
fillColor: Colors.grey.shade300,
isDense: true,
),
onSubmitted: (_) => _onSubmitPressed(),
maxLines: null,
textInputAction: TextInputAction.send,
),
),
),
IconButton(
onPressed: () => _onSubmitPressed(),
icon: Icon(Icons.send),
),
],
),
);
}
}
enum ChatMessageType {
notice,
text,
}
class ChatMessage {
const ChatMessage._({
this.type,
this.posted,
this.message = '',
this.uid,
this.displayName,
this.photoUrl,
}) : assert(type != null && posted != null);
final ChatMessageType type;
final DateTime posted;
final String message;
final String uid;
final String displayName;
final String photoUrl;
String infoText(BuildContext context) {
final timeOfDay = TimeOfDay.fromDateTime(posted);
final localizations = MaterialLocalizations.of(context);
final date = localizations.formatShortDate(posted);
final time = localizations.formatTimeOfDay(timeOfDay);
return '$date at $time from $displayName';
}
bool isMine(BuildContext context) {
final user = Provider.of<FirebaseUser>(context);
return uid == user?.uid;
}
factory ChatMessage.notice(FirebaseUser user, String message) {
return ChatMessage._(
type: ChatMessageType.notice,
posted: DateTime.now().toUtc(),
message: message,
uid: user.uid,
displayName: user.displayName,
photoUrl: user.photoUrl,
);
}
factory ChatMessage.text(FirebaseUser user, String message) {
return ChatMessage._(
type: ChatMessageType.text,
posted: DateTime.now().toUtc(),
message: message,
uid: user.uid,
displayName: user.displayName,
photoUrl: user.photoUrl,
);
}
factory ChatMessage.fromDoc(DocumentSnapshot doc) {
return ChatMessage._(
type: ChatMessageType.values[doc['type'] as int],
posted: (doc['posted'] as Timestamp).toDate(),
message: doc['message'] as String,
uid: doc['user']['uid'] as String,
displayName: doc['user']['displayName'] as String,
photoUrl: doc['user']['photoUrl'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'type': type.index,
'posted': Timestamp.fromDate(posted),
'message': message,
'user': {
'uid': uid,
'displayName': displayName,
'photoUrl': photoUrl,
},
};
}
}
// ---- CHAT LIST IMPLEMENTATION ----
typedef Query FirestoreChatListQueryBuilder();
typedef Widget FirestoreChatListItemBuilder(
BuildContext context,
int index,
DocumentSnapshot document,
Animation<double> animation,
);
typedef Widget FirestoreChatListLoaderBuilder(
BuildContext context,
int index,
Animation<double> animation,
);
class FirestoreChatList extends StatefulWidget {
const FirestoreChatList({
Key key,
this.controller,
#required this.listenBuilder,
#required this.pagedBuilder,
#required this.itemBuilder,
this.loaderBuilder = defaultLoaderBuilder,
this.scrollDirection = Axis.vertical,
this.reverse = true,
this.primary,
this.physics,
this.shrinkWrap = false,
this.initialAnimate = false,
this.padding,
this.duration = const Duration(milliseconds: 300),
}) : super(key: key);
final FirestoreChatListQueryBuilder listenBuilder;
final FirestoreChatListQueryBuilder pagedBuilder;
final FirestoreChatListItemBuilder itemBuilder;
final FirestoreChatListLoaderBuilder loaderBuilder;
final ScrollController controller;
final Axis scrollDirection;
final bool reverse;
final bool primary;
final ScrollPhysics physics;
final bool shrinkWrap;
final bool initialAnimate;
final EdgeInsetsGeometry padding;
final Duration duration;
static Widget defaultLoaderBuilder(
BuildContext context, int index, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: Container(
padding: EdgeInsets.all(32.0),
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
#override
_FirestoreChatListState createState() => _FirestoreChatListState();
}
class _FirestoreChatListState extends State<FirestoreChatList> {
final _animatedListKey = GlobalKey<AnimatedListState>();
final _dataListen = List<DocumentSnapshot>();
final _dataPaged = List<DocumentSnapshot>();
Future _pageRequest;
StreamSubscription<QuerySnapshot> _listenSub;
ScrollController _controller;
ScrollController get controller =>
widget.controller ?? (_controller ??= ScrollController());
#override
void initState() {
super.initState();
controller.addListener(_onScrollChanged);
_requestNextPage();
}
#override
void dispose() {
controller.removeListener(_onScrollChanged);
_controller?.dispose();
_listenSub?.cancel();
super.dispose();
}
void _onScrollChanged() {
if (!controller.hasClients) {
return;
}
final position = controller.position;
if ((position.pixels >=
(position.maxScrollExtent - position.viewportDimension)) &&
position.userScrollDirection == ScrollDirection.reverse) {
_requestNextPage();
}
}
void _requestNextPage() {
_pageRequest ??= () async {
final loaderIndex = _addLoader();
// await Future.delayed(const Duration(seconds: 3));
var pagedQuery = widget.pagedBuilder();
if (_dataPaged.isNotEmpty) {
pagedQuery = pagedQuery.startAfterDocument(_dataPaged.last);
}
final snapshot = await pagedQuery.getDocuments();
if (!mounted) {
return;
}
final insertIndex = _dataListen.length + _dataPaged.length;
_dataPaged.addAll(snapshot.documents);
_removeLoader(loaderIndex);
for (int i = 0; i < snapshot.documents.length; i++) {
_animateAdded(insertIndex + i);
}
if (_listenSub == null) {
var listenQuery = widget.listenBuilder();
if (_dataPaged.isNotEmpty) {
listenQuery = listenQuery.endBeforeDocument(_dataPaged.first);
}
_listenSub = listenQuery.snapshots().listen(_onListenChanged);
}
_pageRequest = null;
}();
}
void _onListenChanged(QuerySnapshot snapshot) {
for (final change in snapshot.documentChanges) {
switch (change.type) {
case DocumentChangeType.added:
_dataListen.insert(change.newIndex, change.document);
_animateAdded(change.newIndex);
break;
case DocumentChangeType.modified:
if (change.oldIndex == change.newIndex) {
_dataListen.removeAt(change.oldIndex);
_dataListen.insert(change.newIndex, change.document);
setState(() {});
} else {
final oldDoc = _dataListen.removeAt(change.oldIndex);
_animateRemoved(change.oldIndex, oldDoc);
_dataListen.insert(change.newIndex, change.document);
_animateAdded(change.newIndex);
}
break;
case DocumentChangeType.removed:
final oldDoc = _dataListen.removeAt(change.oldIndex);
_animateRemoved(change.oldIndex, oldDoc);
break;
}
}
}
int _addLoader() {
final index = _dataListen.length + _dataPaged.length;
_animatedListKey?.currentState
?.insertItem(index, duration: widget.duration);
return index;
}
void _removeLoader(int index) {
_animatedListKey?.currentState?.removeItem(
index,
(BuildContext context, Animation<double> animation) {
return widget.loaderBuilder(context, index, animation);
},
duration: widget.duration,
);
}
void _animateAdded(int index) {
final animatedListState = _animatedListKey.currentState;
if (animatedListState != null) {
animatedListState.insertItem(index, duration: widget.duration);
} else {
setState(() {});
}
}
void _animateRemoved(int index, DocumentSnapshot old) {
final animatedListState = _animatedListKey.currentState;
if (animatedListState != null) {
animatedListState.removeItem(
index,
(BuildContext context, Animation<double> animation) {
return widget.itemBuilder(context, index, old, animation);
},
duration: widget.duration,
);
} else {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
if (_dataListen.length == 0 &&
_dataPaged.length == 0 &&
!widget.initialAnimate) {
return SizedBox();
}
return AnimatedList(
key: _animatedListKey,
controller: controller,
scrollDirection: widget.scrollDirection,
reverse: widget.reverse,
primary: widget.primary,
physics: widget.physics,
shrinkWrap: widget.shrinkWrap,
padding: widget.padding ?? MediaQuery.of(context).padding,
initialItemCount: _dataListen.length + _dataPaged.length,
itemBuilder: (
BuildContext context,
int index,
Animation<double> animation,
) {
if (index < _dataListen.length) {
return widget.itemBuilder(
context,
index,
_dataListen[index],
animation,
);
} else {
final pagedIndex = index - _dataListen.length;
if (pagedIndex < _dataPaged.length) {
return widget.itemBuilder(
context, index, _dataPaged[pagedIndex], animation);
} else {
return widget.loaderBuilder(
context,
pagedIndex,
AlwaysStoppedAnimation<double>(1.0),
);
}
}
},
);
}
}
you can check this github project by simplesoft-duongdt3;
TLDR this is how to go about it
StreamController<List<DocumentSnapshot>> _streamController =
StreamController<List<DocumentSnapshot>>();
List<DocumentSnapshot> _products = [];
bool _isRequesting = false;
bool _isFinish = false;
void onChangeData(List<DocumentChange> documentChanges) {
var isChange = false;
documentChanges.forEach((productChange) {
print(
"productChange ${productChange.type.toString()} ${productChange.newIndex} ${productChange.oldIndex} ${productChange.document}");
if (productChange.type == DocumentChangeType.removed) {
_products.removeWhere((product) {
return productChange.document.documentID == product.documentID;
});
isChange = true;
} else {
if (productChange.type == DocumentChangeType.modified) {
int indexWhere = _products.indexWhere((product) {
return productChange.document.documentID == product.documentID;
});
if (indexWhere >= 0) {
_products[indexWhere] = productChange.document;
}
isChange = true;
}
}
});
if(isChange) {
_streamController.add(_products);
}
}
#override
void initState() {
Firestore.instance
.collection('products')
.snapshots()
.listen((data) => onChangeData(data.documentChanges));
requestNextPage();
super.initState();
}
#override
void dispose() {
_streamController.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
if (scrollInfo.metrics.maxScrollExtent == scrollInfo.metrics.pixels) {
requestNextPage();
}
return true;
},
child: StreamBuilder<List<DocumentSnapshot>>(
stream: _streamController.stream,
builder: (BuildContext context,
AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
log("Items: " + snapshot.data.length.toString());
return //your grid here
ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.symmetric(vertical: 32),
child: new ListTile(
title: new Text(snapshot.data[index]['name']),
subtitle: new Text(snapshot.data[index]['description']),
),
),
);
}
},
));
}
void requestNextPage() async {
if (!_isRequesting && !_isFinish) {
QuerySnapshot querySnapshot;
_isRequesting = true;
if (_products.isEmpty) {
querySnapshot = await Firestore.instance
.collection('products')
.orderBy('index')
.limit(5)
.getDocuments();
} else {
querySnapshot = await Firestore.instance
.collection('products')
.orderBy('index')
.startAfterDocument(_products[_products.length - 1])
.limit(5)
.getDocuments();
}
if (querySnapshot != null) {
int oldSize = _products.length;
_products.addAll(querySnapshot.documents);
int newSize = _products.length;
if (oldSize != newSize) {
_streamController.add(_products);
} else {
_isFinish = true;
}
}
_isRequesting = false;
}
}

Flutter dont reload a image when i take a picture

i'm studying flutter and im trying to create a person register. In this page i hava a normal register with basic data and person photo.
But im having some issue with update a Image, when i take the picture the component Image dont change to taked image;
I tried find some controller to Image or Image Provider but unsuccessful.
This is my code:
class _RegisterForm extends State<RegisterForm> {
final TextEditingController _textEditingControllerPassword =
new TextEditingController();
final TextEditingController _textEditingControllerComparePassword =
new TextEditingController();
final TextEditingController _textEditingControllerEmail =
new TextEditingController();
final TextEditingController _textEditingControllerFullName =
new TextEditingController();
final _formKey = GlobalKey<FormState>();
User _user = null;
Image _image = null;
#override
void setState(VoidCallback fn) {
super.initState();
this._user = new User(
_textEditingControllerPassword.text,
_textEditingControllerFullName.text,
_textEditingControllerEmail.text,
_textEditingControllerComparePassword.text,
_image,
);
this.build(context);
}
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.fromLTRB(23, 0, 23, 0),
child: Column(children: <Widget>[
GestureDetector(
child: CircleAvatarImage(_image),
onTap: getImage,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Tire sua foto!"),
),
InputString(
"Como gostaria ",
hint: "Marianx Silva",
maxLenght: 100,
controller: this._textEditingControllerFullName,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
InputString(
"E-mail",
maxLenght: 100,
controller: this._textEditingControllerEmail,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
InputString(
"Senha",
controller: this._textEditingControllerPassword,
maxLenght: 12,
obscureText: true,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
InputString(
"Confime a senha",
controller: this._textEditingControllerComparePassword,
maxLenght: 12,
obscureText: true,
onChanged: (context) => {
setState(() {
_user = null;
}),
},
),
RegisterUserInFirebaseButton(
"Continuar",
_formKey,
_user,
// edgeInsets: EdgeInsets.fromLTRB(0, 40, 0, 0),
),
]),
));
}
Future getImage() async {
File image = await ImagePicker.pickImage(source: ImageSource.camera);
this._image = Image.file(image);
setState(() {
_user = null;
});
}
}
This is my "CircleAvatarImage" component:
import 'package:flutter/material.dart';
const AssetImage _defaultImage = AssetImage("assets/images/default_image.png");
class CircleAvatarImage extends StatefulWidget {
Image image;
CircleAvatarImage(this.image);
#override
State<StatefulWidget> createState() {
return __CircleAvatarImageState();
}
}
class __CircleAvatarImageState extends State<CircleAvatarImage> {
AnimationController _controller;
#override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 62,
backgroundColor: Colors.blue,
child: CircleAvatar(
radius: 60.0,
child: Padding(
padding: const EdgeInsets.only(top: 90),
child: Icon(
Icons.camera_enhance,
color: Colors.white,
),
),
backgroundImage:
widget.image == null ? _defaultImage : widget.image.image,
),
);
}
}
You didn't use setState. So, there's no way Widget would no that it has to udpate. Try :
setState() => this._image = Image.file(image);

how to refresh state on Navigator.Pop or Push in flutter

Here I have two pages first is called BSP_signup_terms page and the second is Bsp_Service_page. when I am on BSP_signup_terms on that page I have to select some checkbox based on the selected checkbox it will show me some data. but problem is that it will show me the complete data but when I get back to the BSP_signup_terms from Bsp_signup_page and I am changing the checkbox and then again when I am pressing next button it will not change the result it same as the previous result.
Here is the Image of Output Page
In this image I've attached both screen output when I am selecting only one checkbox it will render some value in service page and when I am back to the Terms and Condition page and select one more checkbox then it will not updating service page
Here is the code I've tried.
BSP_Signup_Terms_Page
class BspLicensedSignupTermsPage extends StatefulWidget {
static const String routeName = "/bspLicensedSignupTerms";
final BspSignupCommonModel bspSignupCommonModel;
BspLicensedSignupTermsPage({
Key key,
#required this.bspSignupCommonModel,
}) : super(key: key);
#override
_BspLicensedSignupTermsPageState createState() =>
_BspLicensedSignupTermsPageState();
}
class _BspLicensedSignupTermsPageState
extends State<BspLicensedSignupTermsPage> {
#override
void initState() {
super.initState();
}
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _isWalkIn = false;
bool _isHome = false;
bool _isOnDemand = false;
Widget _buildselectcheckbox() {
return Text(
AppConstantsValue.appConst['bsplicensedsignupterms']['selectcheck']
['translation'],
);
}
// Walkin
_onCustomerWalkin(value) {
setState(() {
_isWalkIn = value;
});
}
Widget _buildCustomerWalkIn() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bsplicensedsignupterms']
['CustomerWalkIn']['translation'],
onChanged: (value) {
print(value);
_onCustomerWalkin(value);
},
validate: false,
);
}
// Home
_onCustomerInHome(value) {
setState(() {
_isHome = value;
});
}
Widget _buildCustomerInHome() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bsplicensedsignupterms']
['CustomerInHome']['translation'],
onChanged: (value) {
_onCustomerInHome(value);
},
validate: false,
);
}
Widget _buildCustomerInHomeHelp() {
return Text(
AppConstantsValue.appConst['bsplicensedsignupterms']['businesscheckhelp']
['translation'],
);
}
// On Demand
_onCustomerOnDemand(value) {
setState(() {
_isOnDemand = value;
});
}
Widget _buildBusinessOnDemand() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bsplicensedsignupterms']
['BusinessOnDemand']['translation'],
onChanged: (value) {
_onCustomerOnDemand(value);
},
validate: false,
);
}
Widget _buildBusinessOnDemandHelp() {
return Text(AppConstantsValue.appConst['bsplicensedsignupterms']
['businessprovidehelp']['translation']);
}
#override
Widget build(BuildContext context) {
final appBar = AppBar(
title: Text("Bsp Licensed Signup Terms and Condition"),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
NavigationHelper.navigatetoBack(context);
},
),
centerTitle: true,
);
final bottomNavigationBar = Container(
height: 56,
//margin: EdgeInsets.symmetric(vertical: 24, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.close),
label: Text('Clear'),
color: Colors.redAccent,
textColor: Colors.black,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
_formKey.currentState.reset();
},
),
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Next'),
color: colorStyles["primary"],
textColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
if (_formKey.currentState.validate()) {
if (_isHome == false &&
_isOnDemand == false &&
_isWalkIn == false) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => ShowErrorDialog(
title: Text('Select Service'),
content: Text(
'Please select atleast one service type to proceed next',
),
));
} else {
BspSignupCommonModel model = widget.bspSignupCommonModel;
model.isWalkin = _isWalkIn;
model.isHome = _isHome;
model.isOnDemand = _isOnDemand;
print(model.toJson());
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
BspServicePage(bspSignupCommonModel: model),
),
);
}
}
},
),
],
),
);
return new Scaffold(
appBar: appBar,
bottomNavigationBar: bottomNavigationBar,
body: Container(
height: double.infinity,
width: double.infinity,
child: Stack(
children: <Widget>[
SingleChildScrollView(
child: SafeArea(
child: Form(
autovalidate: true,
key: _formKey,
child: Scrollbar(
child: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: new Container(
decoration: BoxDecoration(
borderRadius: new BorderRadius.circular(25)),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildselectcheckbox(),
_buildCustomerWalkIn(),
_buildCustomerInHome(),
_buildCustomerInHomeHelp(),
_buildBusinessOnDemand(),
_buildBusinessOnDemandHelp(),
],
),
),
),
),
),
),
),
],
),
),
);
}
}
BSP_Service_Page
class BspServicePage extends StatefulWidget {
static const String routeName = "/bspService";
final BspSignupCommonModel bspSignupCommonModel;
BspServicePage({
Key key,
#required this.bspSignupCommonModel,
}) : super(key: key);
#override
_BspServicePageState createState() => _BspServicePageState();
}
class _BspServicePageState extends State<BspServicePage> {
List<int> servicesIds = [];
Map<String, bool> selection = {};
List<BspServices.Service> selectedServices = [];
SearchBarController _controller = new SearchBarController();
String _searchText = '';
bool refreshservices = true;
#override
void initState() {
super.initState();
}
void _showErrorDialog(String message) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => ShowErrorDialog(
title: Text('An Error Occurred!'),
content: Text(message),
),
);
}
void refresh() {
setState(() {
refreshservices = !refreshservices;
});
}
#override
Widget build(BuildContext context) {
var _bspServiceBloc = new BspServiceBloc();
final appBar = SearchBar(
controller: _controller,
onQueryChanged: (String query) {
print('Search Query $query');
setState(() {
_searchText = query;
});
},
defaultBar: AppBar(
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
refresh();
NavigationHelper.navigatetoBack(context);
}),
title: Text('Select Services'),
),
);
final bottomNavigationBar = Container(
height: 56,
// margin: EdgeInsets.symmetric(vertical: 24, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.close),
label: Text('Clear'),
color: Colors.redAccent,
textColor: Colors.black,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
print('reseting the state');
setState(() {
selection = {};
servicesIds = [];
});
},
),
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Next'),
color: colorStyles["primary"],
textColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
BspSignupCommonModel model = widget.bspSignupCommonModel;
model.servicesIds = servicesIds;
model.services = selectedServices;
print('servicesIds at the next button');
print(servicesIds);
print(model.toJson());
if (servicesIds.length == 0) {
_showErrorDialog(
'You need to select at least one service to proceed next!');
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BusinessProfilePage(
bspSignupCommonModel: model,
),
),
);
}
},
),
],
),
);
return new Scaffold(
appBar: appBar,
bottomNavigationBar: bottomNavigationBar,
body: new BspServiceScreen(
bspServiceBloc: _bspServiceBloc,
bspSignupCommonModel: widget.bspSignupCommonModel,
servicesIds: servicesIds,
selection: selection,
searchQuery: _searchText,
selectedServices: selectedServices,
refresh: refresh,
),
);
}
}
Bsp_service_screen
class BspServiceScreen extends StatefulWidget {
final BspServiceBloc _bspServiceBloc;
final String searchQuery;
final List<int> servicesIds;
final Map<String, bool> selection;
final BspSignupCommonModel bspSignupCommonModel;
final List<BspServices.Service> selectedServices;
final Function refresh;
const BspServiceScreen({
Key key,
#required BspServiceBloc bspServiceBloc,
#required this.bspSignupCommonModel,
#required this.servicesIds,
#required this.selection,
#required this.selectedServices,
#required this.refresh,
this.searchQuery,
}) : _bspServiceBloc = bspServiceBloc,
super(key: key);
#override
BspServiceScreenState createState() {
return new BspServiceScreenState(_bspServiceBloc);
}
}
class BspServiceScreenState extends State<BspServiceScreen> {
final BspServiceBloc _bspServiceBloc;
BspServiceScreenState(this._bspServiceBloc);
// Map<String, bool> _selection = {};
#override
void initState() {
super.initState();
bool isHome = widget.bspSignupCommonModel.isHome;
bool isWalkIn = widget.bspSignupCommonModel.isWalkin;
bool isOnDemand = widget.bspSignupCommonModel.isOnDemand;
this._bspServiceBloc.dispatch(LoadBspServiceEvent(
countryId: 1,
isHome: isHome,
isOnDemand: isOnDemand,
isWalkin: isWalkIn,
));
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return BlocBuilder<BspServiceBloc, BspServiceState>(
bloc: widget._bspServiceBloc,
builder: (
BuildContext context,
BspServiceState currentState,
) {
if (currentState is UnBspServiceState) {
return Center(child: CircularProgressIndicator());
}
if (currentState is ErrorBspServiceState) {
return new Container(
child: new Center(
child: new Text(currentState.errorMessage ?? 'Error'),
),
);
}
if (currentState is InBspServiceState) {
// print(
// 'in bsp service state, ${currentState.bspServices.servicesByCountry.length}');
if (currentState.bspServices.servicesByCountry.length == 0) {
return Container(
child: Center(
child: Text("No Services available for this combination"),
),
);
} else {
return new Container(
child:
_renderServices(currentState.bspServices.servicesByCountry),
);
}
}
return Container();
},
);
}
List<ServicesByCountry> finalList = new List();
ListView _renderServices(List<ServicesByCountry> lovCountryServices) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.searchQuery != '') {
finalList.clear();
lovCountryServices.forEach((ServicesByCountry data) {
if (data.name
.toLowerCase()
.contains(widget.searchQuery.toLowerCase())) {
setState(() {
finalList.add(data);
});
} else {
data.services.forEach((ServiceList.Service services) {
if (services.name
.toLowerCase()
.contains(widget.searchQuery.toLowerCase())) {
setState(() {
finalList.add(data);
});
}
});
}
});
} else {
setState(() {
finalList.clear();
finalList.addAll(lovCountryServices);
});
}
});
return ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8.0),
itemCount: finalList.length,
itemBuilder: (BuildContext context, int index) {
ServicesByCountry item = finalList[index];
List itemsList = item.services;
return ExpansionTile(
title: Text(item.name),
children: List.generate(itemsList.length, (i) {
widget.selection[itemsList[i].name] =
widget.selection[itemsList[i].name] ?? itemsList[i].isSelected;
return CheckboxListTile(
title: Text(itemsList[i].name),
value: widget.selection[itemsList[i].name],
onChanged: (val) {
setState(() {
widget.selection[itemsList[i].name] = val;
if (val) {
widget.servicesIds.add(itemsList[i].id);
List<BspServices.Service> services =
widget.selectedServices.where((service) {
return service.mainCategory == item.name;
}).toList();
SubCategory subService = new SubCategory(
id: itemsList[i].id,
name: itemsList[i].name,
);
List<SubCategory> subCategories = [];
if (services.length == 0) {
subCategories.add(subService);
widget.selectedServices.add(
new BspServices.Service(
mainCategory: item.name,
mainCategoryId: item.id,
subCategory: subCategories,
),
);
} else {
print('services in else');
print(services[0].subCategory);
subCategories = services[0].subCategory;
subCategories.add(subService);
}
} else {
widget.servicesIds.removeWhere((service) {
return service == itemsList[i].id;
});
List<BspServices.Service> services =
widget.selectedServices.where((service) {
return service.mainCategory == item.name;
}).toList();
services[0].subCategory.removeWhere((subService) {
return subService.id == itemsList[i].id;
});
}
});
print('widget.servicesIds after set state');
print(widget.servicesIds);
},
);
}),
);
},
);
}
}
You can use setState() after return to the first page:
Navigator.push(context, MaterialPageRoute(builder: (context) => Page2())).then((value) {
setState(() {
// refresh state
});
});
Please try below code:-
First you add one method async method:-
void redirectToNextScreen() async {
final Route route = MaterialPageRoute(
builder: (context) => BspServicePage(bspSignupCommonModel: model));
final result = await Navigator.push(mContext, route);
try {
if (result != null) {
if (result) {
//Return callback here.
}
}
} catch (e) {
print(e.toString());
}
}
Then Next you can call this method in "BSP_Signup_Terms_Page" on Next button Pressed event.
Second you can add below line in "BspServicePage" screen Next and Cancel Events.
Navigator.pop(mContext, true); //true means refresh back page and false means not refresh.