feat: Use dynamic gradient for chat bubbles
This commit is contained in:
parent
27a2361ba8
commit
480513c708
2 changed files with 191 additions and 103 deletions
|
|
@ -152,6 +152,7 @@ class ChatEventList extends StatelessWidget {
|
|||
nextEvent: i + 1 < events.length ? events[i + 1] : null,
|
||||
previousEvent: i > 0 ? events[i - 1] : null,
|
||||
wallpaperMode: hasWallpaper,
|
||||
scrollController: controller.scrollController,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ class Message extends StatelessWidget {
|
|||
final bool animateIn;
|
||||
final void Function()? resetAnimateIn;
|
||||
final bool wallpaperMode;
|
||||
final ScrollController scrollController;
|
||||
|
||||
const Message(
|
||||
this.event, {
|
||||
|
|
@ -54,6 +57,7 @@ class Message extends StatelessWidget {
|
|||
this.animateIn = false,
|
||||
this.resetAnimateIn,
|
||||
this.wallpaperMode = false,
|
||||
required this.scrollController,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -323,6 +327,16 @@ class Message extends StatelessWidget {
|
|||
borderRadius: borderRadius,
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: BubbleBackground(
|
||||
colors: [
|
||||
theme.brightness == Brightness.light
|
||||
? theme.colorScheme.tertiary
|
||||
: theme.colorScheme
|
||||
.tertiaryContainer,
|
||||
color,
|
||||
],
|
||||
ignore: noBubble || !ownMessage,
|
||||
scrollController: scrollController,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(
|
||||
|
|
@ -360,7 +374,8 @@ class Message extends StatelessWidget {
|
|||
eventId: event
|
||||
.relationshipEventId!,
|
||||
content: {
|
||||
'msgtype': 'm.text',
|
||||
'msgtype':
|
||||
'm.text',
|
||||
'body': '...',
|
||||
},
|
||||
senderId:
|
||||
|
|
@ -368,8 +383,8 @@ class Message extends StatelessWidget {
|
|||
type:
|
||||
'm.room.message',
|
||||
room: event.room,
|
||||
status:
|
||||
EventStatus.sent,
|
||||
status: EventStatus
|
||||
.sent,
|
||||
originServerTs:
|
||||
DateTime.now(),
|
||||
);
|
||||
|
|
@ -379,7 +394,8 @@ class Message extends StatelessWidget {
|
|||
bottom: 4.0,
|
||||
),
|
||||
child: InkWell(
|
||||
borderRadius: ReplyContent
|
||||
borderRadius:
|
||||
ReplyContent
|
||||
.borderRadius,
|
||||
onTap: () =>
|
||||
scrollToEventId(
|
||||
|
|
@ -410,7 +426,8 @@ class Message extends StatelessWidget {
|
|||
RelationshipTypes.edit,
|
||||
))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
padding:
|
||||
const EdgeInsets.only(
|
||||
top: 4.0,
|
||||
),
|
||||
child: Row(
|
||||
|
|
@ -441,6 +458,7 @@ class Message extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -574,3 +592,72 @@ class Message extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BubbleBackground extends StatelessWidget {
|
||||
const BubbleBackground({
|
||||
super.key,
|
||||
required this.scrollController,
|
||||
required this.colors,
|
||||
required this.ignore,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final ScrollController scrollController;
|
||||
final List<Color> colors;
|
||||
final bool ignore;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (ignore) return child;
|
||||
return CustomPaint(
|
||||
painter: BubblePainter(
|
||||
repaint: scrollController,
|
||||
colors: colors,
|
||||
context: context,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BubblePainter extends CustomPainter {
|
||||
BubblePainter({
|
||||
required this.context,
|
||||
required this.colors,
|
||||
required super.repaint,
|
||||
});
|
||||
|
||||
final BuildContext context;
|
||||
final List<Color> colors;
|
||||
ScrollableState? _scrollable;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final scrollable = _scrollable ??= Scrollable.of(context);
|
||||
final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
|
||||
final scrollableRect = Offset.zero & scrollableBox.size;
|
||||
final bubbleBox = context.findRenderObject() as RenderBox;
|
||||
|
||||
final origin =
|
||||
bubbleBox.localToGlobal(Offset.zero, ancestor: scrollableBox);
|
||||
final paint = Paint()
|
||||
..shader = ui.Gradient.linear(
|
||||
scrollableRect.topCenter,
|
||||
scrollableRect.bottomCenter,
|
||||
colors,
|
||||
[0.0, 1.0],
|
||||
TileMode.clamp,
|
||||
Matrix4.translationValues(-origin.dx, -origin.dy, 0.0).storage,
|
||||
);
|
||||
canvas.drawRect(Offset.zero & size, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(BubblePainter oldDelegate) {
|
||||
final scrollable = Scrollable.of(context);
|
||||
final oldScrollable = _scrollable;
|
||||
_scrollable = scrollable;
|
||||
return scrollable.position != oldScrollable?.position;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue