Skip to content

Instantly share code, notes, and snippets.

@Elvecent
Last active February 2, 2023 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Elvecent/d4808e6556e6de67aed892d99cd1db08 to your computer and use it in GitHub Desktop.
Save Elvecent/d4808e6556e6de67aed892d99cd1db08 to your computer and use it in GitHub Desktop.
Dart/Flutter dialog imitation with streams
import 'package:flutter/material.dart';
import 'func.dart';
class Message {
Message(this.text, this.isMe);
String text;
bool isMe;
}
class Bubble extends StatelessWidget {
Bubble({this.message, this.isMe});
final String message;
final bool isMe;
@override
Widget build(BuildContext context) {
final bg = isMe ? Colors.lightBlue : Colors.greenAccent.shade200;
final align = isMe ? CrossAxisAlignment.start : CrossAxisAlignment.end;
final radius = BorderRadius.only(
topRight: Radius.circular(isMe ? 5.0 : 0),
topLeft: Radius.circular(isMe ? 0 : 5.0),
bottomLeft: Radius.circular(isMe ? 10.0 : 5.0),
bottomRight: Radius.circular(5.0),
);
return Column(
crossAxisAlignment: align,
children: <Widget>[
Container(
margin: const EdgeInsets.all(3.0),
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: bg,
borderRadius: radius,
),
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 48.0),
child: Text(
message,
style: TextStyle(
fontSize: 20.0,
),
)),
],
))
],
);
}
}
class Dialogue extends StatelessWidget {
Dialogue({this.messages});
final Stream<Message> messages;
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: aggregate(messages),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text("Dialogue stream failure :(");
} else {
final msgs = snapshot.data as List<Message>;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: msgs
.map((msg) => Bubble(
message: msg.text,
isMe: msg.isMe,
))
.toList());
}
},
);
}
}
// Miscellanious utilities
import 'dart:async';
Stream<List<T>> aggregate<T>(Stream<T> s) async* {
List<T> res = [];
await for (T item in s) {
res.add(item);
yield res;
}
}
Stream<T> fromIterableDelayed<T>(Iterable<T> i, Duration delay) async* {
for (T item in i) {
await Future.delayed(delay);
yield item;
}
}
import 'package:flutter/material.dart';
import 'bubble.dart';
import 'func.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter (title)',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
backgroundColor: Colors.blueGrey.shade50,
body: Padding(
padding: EdgeInsets.only(
top: 10.0,
),
child: Dialogue(
messages: fromIterableDelayed([
Message("Hi!", true),
Message("My name is", true),
Message("What?", false),
Message("My name is", true),
Message("Who?", false),
Message("My name is", true),
Message("chka-chka Stream Shady!", true),
], Duration(milliseconds: 1500))))));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment