Live Chat With Pusher Using Provider
Learn how to setup a real-time messaging Flutter App using Pusher API and a Go backend deployed as a containerised web service to GCP Cloud Run. By Wilberforce Uwadiegwu.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Live Chat With Pusher Using Provider
30 mins
- Getting Started
- Setting up and Deploying the Back end
- Setting up Pusher
- Setting up Firebase
- Setting up GCP
- Deploying the Go Service
- Sending and Receiving Messages
- Configuring Pusher
- Receiving Messages
- Sending Messages
- Implementing UI
- Building the Messages Screen
- Adding An Input Field
- Adding the Messages View
- Building the Message Widget
- Supporting Images
- Displaying Images
- Where to Go From Here
Displaying Images
You have to show the user the images they chose and also allow them to remove them. So, head over to messages_screen.dart and import 'dart:io'
and 'package:image_picker/image_picker.dart'
. Afterward, create a stateless widget below _InputWidget
. This widget will render a single image.
class _ImageWidget extends StatelessWidget {
final XFile file;
final VoidCallback onRemove;
final double size;
const _ImageWidget({
Key? key,
required this.onRemove,
required this.file,
required this.size,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}
Since the images it'll display are local files from the image picker, you don't need to handle image URLs like you did for MessageWidget. Replace the build()
of _ImageWidget with:
Widget build(BuildContext context) {
final imageSize = size - 15;
return Padding(
padding: const EdgeInsets.only(left: 5, right: 10),
child: SizedBox(
height: size,
width: size,
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned(
top: 15,
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(file.path),
width: imageSize,
height: imageSize,
fit: BoxFit.cover,
),
),
),
Positioned(
top: -10,
right: -10,
child: IconButton(
onPressed: onRemove,
icon: const Icon(Icons.cancel),
),
)
],
),
),
);
}
This will display an image with round edges, with an "x" icon at the top-right.
Next, declare a variable inside build()
of _InputWidget
, above the return statement.
Widget build(BuildContext context) {
final imageSize = MediaQuery.of(context).size.width * 0.21;
...
}
Still, in _InputWidget
, wrap the TextField
in a Column
. You'll display a horizontal list of images above the text field like so:
Widget build(BuildContext context) {
...
return Transform.translate(
...
child: SafeArea(
...
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: vm.images.isEmpty ? 0 : imageSize,
child: ListView.builder(
itemCount: vm.images.length,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, i) {
final file = vm.images[i];
return _ImageWidget(
onRemove: () => vm.removeImage(i),
file: file,
size: imageSize,
);
},
),
),
TextField(
...
),
],
),
),
);
}
Add a suffix icon that'll trigger the image picker:
TextField(
...
prefixIcon: IconButton(
onPressed: vm.pickImages,
icon: const Icon(Icons.add),
),
)
Run the app on both devices and send an image from any of them. You will see something like this:
That's all. Great job on completing this tutorial!
Where to Go From Here
The final directory inside the mobile directory contains the full code used in this tutorial, and you can find it in the zipped file you downloaded earlier. You can still download it by clicking Download Materials at the top or bottom of this tutorial.
In this tutorial, you deployed a Golang service on Cloud Run and learned how to use Pusher to implement real-time chat. To make improvements to the memory footprint and performance of the app, one suggestion is to paginate the chat, letting messages load in pages rather than loading all at once. You can improve the app's functionality by adding support for resending messages that failed to send. You could also use AnimatedList instead of ListView to improve the granularity of the entrance of the message widgets. After playing around, remember to delete the project from GCP, so it doesn't incur any charges.
We hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below!