Last active
April 1, 2022 19:54
-
-
Save jlamimoso/ea09bf631dfbbcdb4d73d1e11d5f0b4a to your computer and use it in GitHub Desktop.
Chat Bubble example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:intl/intl.dart'; | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData( | |
primarySwatch: Colors.blue), | |
debugShowCheckedModeBanner: false, | |
home: const MyWidget(title: 'Chat Demo'), | |
); | |
} | |
} | |
class MyWidget extends StatefulWidget { | |
const MyWidget({Key? key, required this.title}) : super(key: key); | |
final String title; | |
@override | |
_MyWidgetState createState() => _MyWidgetState(); | |
} | |
class _MyWidgetState extends State<MyWidget> { | |
List <Widget> messages = []; | |
void setSampleMessages(messages, now) { | |
messages.add( | |
DateChip( | |
date: DateTime(now.year, now.month, now.day - 2), | |
) | |
); | |
messages.add( | |
Bubble( | |
message: 'message 1111', | |
date: DateTime.parse("2022-03-30 13:27:03"), | |
delivered: true, | |
isMe: false, | |
) | |
); | |
messages.add( | |
Bubble( | |
message: 'answser message 1111', | |
date: DateTime.parse("2022-03-30 13:29:33"), | |
delivered: true, | |
isMe: true, | |
seen: true, | |
) | |
); | |
messages.add( | |
DateChip( | |
date: DateTime(now.year, now.month, now.day - 1), | |
) | |
); | |
messages.add( | |
Bubble( | |
message: 'message 2222 2222', | |
date: DateTime.parse("2022-03-31 09:02:09"), | |
delivered: true, | |
isMe: false, | |
) | |
); | |
messages.add( | |
Bubble( | |
message: 'answser message 2222 2222', | |
date: DateTime.parse("2022-03-31 09:37:23"), | |
delivered: true, | |
isMe: true, | |
seen: true, | |
) | |
); | |
messages.add( | |
DateChip( | |
date: DateTime(now.year, now.month, now.day), | |
) | |
); | |
messages.add( | |
Bubble( | |
message: 'message 3333 3333 3333 3333333333 3333 3333 33', | |
date: DateTime.parse("2022-03-31 09:02:09"), | |
delivered: true, | |
isMe: false, | |
) | |
); | |
messages.add( | |
Bubble( | |
message: 'answser message 3333 3333 3333 3333333333 3333 3333 33', | |
date: DateTime.parse("2022-03-31 09:37:23"), | |
delivered: true, | |
isMe: true, | |
seen: true, | |
) | |
); | |
} | |
@override | |
Widget build(BuildContext context) { | |
setSampleMessages(messages, DateTime.now()); | |
return Scaffold( | |
backgroundColor: Colors.blueGrey.shade50, | |
appBar: AppBar( | |
backgroundColor: const Color.fromRGBO(11, 80, 31, 1.0), | |
elevation: .9, | |
title: Text( | |
widget.title, | |
style: const TextStyle(color: Colors.white), | |
), | |
leading: IconButton( | |
icon: const Icon( | |
Icons.arrow_back_ios, | |
color: Colors.white, | |
), | |
onPressed: () {}, | |
), | |
actions: <Widget>[ | |
IconButton( | |
icon: const Icon( | |
Icons.videocam, | |
color: Colors.white, | |
), | |
onPressed: () {}, | |
), | |
IconButton( | |
icon: const Icon( | |
Icons.call, | |
color: Colors.white, | |
), | |
onPressed: () {}, | |
), | |
IconButton( | |
icon: const Icon( | |
Icons.more_vert, | |
color: Colors.white, | |
), | |
onPressed: () {}, | |
) | |
], | |
), | |
body: Padding( | |
padding: const EdgeInsets.all(10.0), | |
child: ListView.separated( | |
itemBuilder: (context, index) { | |
return messages[index]; | |
}, | |
separatorBuilder: (context, index) { | |
return const SizedBox(height: 1); | |
}, | |
itemCount: messages.length, | |
), | |
), | |
); | |
} | |
} | |
class Bubble extends StatelessWidget { | |
const Bubble({required this.message, required this.date, required this.delivered, | |
this.seen = false, required this.isMe}); | |
final String message; | |
final DateTime date; | |
final bool delivered, isMe, seen; | |
@override | |
Widget build(BuildContext context) { | |
final time = '${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; | |
final bg = isMe ? Colors.greenAccent.shade100 : Colors.white; | |
final align = isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start; | |
final icon = delivered ? Icons.done_all : Icons.done; | |
final margin = isMe ? const EdgeInsets.fromLTRB(40, 4, 4, 4) : const EdgeInsets.fromLTRB(4, 4, 40, 4); | |
final color = seen ? Colors.lightBlue : Colors.black38; | |
final radius = isMe | |
? const BorderRadius.only( | |
topLeft: Radius.circular(20.0), | |
bottomLeft: Radius.circular(20.0), | |
bottomRight: Radius.circular(20), | |
) | |
: const BorderRadius.only( | |
topRight: Radius.circular(20.0), | |
bottomLeft: Radius.circular(20.0), | |
bottomRight: Radius.circular(20.0), | |
); | |
return Column( | |
crossAxisAlignment: align, | |
children: <Widget>[ | |
Container( | |
//margin: const EdgeInsets.all(3.0), | |
margin: margin, | |
padding: const EdgeInsets.all(8.0), | |
decoration: BoxDecoration( | |
boxShadow: [ | |
BoxShadow( | |
blurRadius: .5, | |
spreadRadius: 1.0, | |
color: Colors.black.withOpacity(.12) | |
) | |
], | |
color: bg, | |
borderRadius: radius, | |
), | |
child: Stack( | |
children: <Widget>[ | |
Padding( | |
padding: const EdgeInsets.fromLTRB(2, 2, 4, 2), | |
child: Text.rich( | |
TextSpan( | |
children: [ | |
TextSpan( | |
text: message, | |
style: const TextStyle(fontSize: 16)), | |
const WidgetSpan( | |
child: SizedBox( | |
width: 50, | |
child: Text(' '), | |
), | |
), | |
// TextSpan(text: ' '), | |
] | |
), | |
), | |
), | |
Positioned( | |
right: 1, | |
bottom: -2, | |
child: Text.rich( | |
TextSpan( | |
children: [ | |
TextSpan( | |
text: time, | |
style: const TextStyle( | |
color: Colors.black38, | |
fontSize: 12.0, | |
) | |
), | |
const WidgetSpan( | |
child: SizedBox(width: 1), | |
), | |
WidgetSpan( | |
child: Icon( | |
icon, | |
size:15, | |
color: color, | |
), | |
), | |
], | |
), | |
), | |
), | |
], | |
), | |
), | |
], | |
); | |
} | |
} | |
class DateChip extends StatelessWidget { | |
final DateTime date; | |
final Color color; | |
const DateChip({ | |
Key? key, | |
required this.date, | |
this.color = Colors.white, // const Color(0xffffffff), | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: [ | |
Container( | |
decoration: BoxDecoration( | |
borderRadius: const BorderRadius.all(Radius.circular(6)), | |
color: color, | |
), | |
margin: const EdgeInsets.all(6), | |
child: Padding( | |
padding: const EdgeInsets.all(5.0), | |
child: Text( | |
Algo.dateChipText(date), | |
), | |
), | |
), ] | |
); | |
} | |
} | |
///all the algorithms of the plugin | |
///[dateChipText] to get the text which is need to show on the [DateChip] | |
abstract class Algo { | |
Algo._(); | |
static String dateChipText(final DateTime date) { | |
final dateChipText = DateChipText(date); | |
return dateChipText.getText(); | |
} | |
} | |
///initial formatter to find the date txt | |
final DateFormat _formatter = DateFormat('yyyy-MM-dd'); | |
///[DateChipText] class included with algorithms which are need to implement [DateChip] | |
///[date] parameter is required | |
/// | |
class DateChipText { | |
final DateTime date; | |
DateChipText(this.date); | |
///generate and return [DateChip] string | |
/// | |
/// | |
String getText() { | |
final now = DateTime.now(); | |
if (_formatter.format(now) == _formatter.format(date)) { | |
return 'Today'; | |
} else if (_formatter | |
.format(DateTime(now.year, now.month, now.day - 1)) == | |
_formatter.format(date)) { | |
return 'Yesterday'; | |
} else { | |
return '${DateFormat('d').format(date)} ${DateFormat('MMMM').format(date)} of ${DateFormat('y').format(date)}'; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment