-
Notifications
You must be signed in to change notification settings - Fork 924
/
Copy pathmessage_bubble.dart
147 lines (138 loc) · 5.42 KB
/
message_bubble.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import 'package:flutter/material.dart';
// A MessageBubble for showing a single chat message on the ChatScreen.
class MessageBubble extends StatelessWidget {
// Create a message bubble which is meant to be the first in the sequence.
const MessageBubble.first({
super.key,
required this.userImage,
required this.username,
required this.message,
required this.isMe,
}) : isFirstInSequence = true;
// Create a message bubble that continues the sequence.
const MessageBubble.next({
super.key,
required this.message,
required this.isMe,
}) : isFirstInSequence = false,
userImage = null,
username = null;
// Whether or not this message bubble is the first in a sequence of messages
// from the same user.
// Modifies the message bubble slightly for these different cases - only
// shows user image for the first message from the same user, and changes
// the shape of the bubble for messages thereafter.
final bool isFirstInSequence;
// Image of the user to be displayed next to the bubble.
// Not required if the message is not the first in a sequence.
final String? userImage;
// Username of the user.
// Not required if the message is not the first in a sequence.
final String? username;
final String message;
// Controls how the MessageBubble will be aligned.
final bool isMe;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Stack(
children: [
if (userImage != null)
Positioned(
top: 15,
// Align user image to the right, if the message is from me.
right: isMe ? 0 : null,
child: CircleAvatar(
backgroundImage: NetworkImage(
userImage!,
),
backgroundColor: theme.colorScheme.primary.withAlpha(180),
radius: 23,
),
),
Container(
// Add some margin to the edges of the messages, to allow space for the
// user's image.
margin: const EdgeInsets.symmetric(horizontal: 46),
child: Row(
// The side of the chat screen the message should show at.
mainAxisAlignment:
isMe ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
// First messages in the sequence provide a visual buffer at
// the top.
if (isFirstInSequence) const SizedBox(height: 18),
if (username != null)
Padding(
padding: const EdgeInsets.only(
left: 13,
right: 13,
),
child: Text(
username!,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
),
// The "speech" box surrounding the message.
Container(
decoration: BoxDecoration(
color: isMe
? Colors.grey[300]
: theme.colorScheme.secondary.withAlpha(200),
// Only show the message bubble's "speaking edge" if first in
// the chain.
// Whether the "speaking edge" is on the left or right depends
// on whether or not the message bubble is the current user.
borderRadius: BorderRadius.only(
topLeft: !isMe && isFirstInSequence
? Radius.zero
: const Radius.circular(12),
topRight: isMe && isFirstInSequence
? Radius.zero
: const Radius.circular(12),
bottomLeft: const Radius.circular(12),
bottomRight: const Radius.circular(12),
),
),
// Set some reasonable constraints on the width of the
// message bubble so it can adjust to the amount of text
// it should show.
constraints: const BoxConstraints(maxWidth: 200),
padding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 14,
),
// Margin around the bubble.
margin: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 12,
),
child: Text(
message,
style: TextStyle(
// Add a little line spacing to make the text look nicer
// when multilined.
height: 1.3,
color: isMe
? Colors.black87
: theme.colorScheme.onSecondary,
),
softWrap: true,
),
),
],
),
],
),
),
],
);
}
}