chore: Adjust styles and animations
This commit is contained in:
parent
5c88133691
commit
9724b852bb
5 changed files with 656 additions and 761 deletions
|
|
@ -462,21 +462,18 @@ class ChatController extends State<ChatPageWithRoom>
|
||||||
scrollUpBannerEventId = eventId;
|
scrollUpBannerEventId = eventId;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool firstUpdateReceived = false;
|
||||||
|
|
||||||
void updateView() {
|
void updateView() {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setReadMarker();
|
setReadMarker();
|
||||||
setState(() {});
|
setState(() {
|
||||||
|
firstUpdateReceived = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void>? loadTimelineFuture;
|
Future<void>? loadTimelineFuture;
|
||||||
|
|
||||||
int? animateInEventIndex;
|
|
||||||
|
|
||||||
void onInsert(int i) {
|
|
||||||
// setState will be called by updateView() anyway
|
|
||||||
if (timeline?.allowNewEvent == true) animateInEventIndex = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _getTimeline({String? eventContextId}) async {
|
Future<void> _getTimeline({String? eventContextId}) async {
|
||||||
await Matrix.of(context).client.roomsLoading;
|
await Matrix.of(context).client.roomsLoading;
|
||||||
await Matrix.of(context).client.accountDataLoading;
|
await Matrix.of(context).client.accountDataLoading;
|
||||||
|
|
@ -489,15 +486,11 @@ class ChatController extends State<ChatPageWithRoom>
|
||||||
timeline = await room.getTimeline(
|
timeline = await room.getTimeline(
|
||||||
onUpdate: updateView,
|
onUpdate: updateView,
|
||||||
eventContextId: eventContextId,
|
eventContextId: eventContextId,
|
||||||
onInsert: onInsert,
|
|
||||||
);
|
);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs().w('Unable to load timeline on event ID $eventContextId', e, s);
|
Logs().w('Unable to load timeline on event ID $eventContextId', e, s);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
timeline = await room.getTimeline(
|
timeline = await room.getTimeline(onUpdate: updateView);
|
||||||
onUpdate: updateView,
|
|
||||||
onInsert: onInsert,
|
|
||||||
);
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
if (e is TimeoutException || e is IOException) {
|
if (e is TimeoutException || e is IOException) {
|
||||||
_showScrollUpMaterialBanner(eventContextId!);
|
_showScrollUpMaterialBanner(eventContextId!);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ class ChatEventList extends StatelessWidget {
|
||||||
final events = timeline.events.filterByVisibleInGui(
|
final events = timeline.events.filterByVisibleInGui(
|
||||||
threadId: controller.activeThreadId,
|
threadId: controller.activeThreadId,
|
||||||
);
|
);
|
||||||
final animateInEventIndex = controller.animateInEventIndex;
|
|
||||||
|
|
||||||
// create a map of eventId --> index to greatly improve performance of
|
// create a map of eventId --> index to greatly improve performance of
|
||||||
// ListView's findChildIndexCallback
|
// ListView's findChildIndexCallback
|
||||||
|
|
@ -120,10 +119,7 @@ class ChatEventList extends StatelessWidget {
|
||||||
|
|
||||||
// The message at this index:
|
// The message at this index:
|
||||||
final event = events[i];
|
final event = events[i];
|
||||||
final animateIn =
|
final animateIn = i == 0 && controller.firstUpdateReceived;
|
||||||
animateInEventIndex != null &&
|
|
||||||
timeline.events.length > animateInEventIndex &&
|
|
||||||
event == timeline.events[animateInEventIndex];
|
|
||||||
|
|
||||||
final nextEvent = i + 1 < events.length ? events[i + 1] : null;
|
final nextEvent = i + 1 < events.length ? events[i + 1] : null;
|
||||||
final previousEvent = i > 0 ? events[i - 1] : null;
|
final previousEvent = i > 0 ? events[i - 1] : null;
|
||||||
|
|
@ -139,16 +135,13 @@ class ChatEventList extends StatelessWidget {
|
||||||
!controller.expandedEventIds.contains(event.eventId);
|
!controller.expandedEventIds.contains(event.eventId);
|
||||||
|
|
||||||
return AutoScrollTag(
|
return AutoScrollTag(
|
||||||
key: ValueKey(event.eventId),
|
key: ValueKey(event.transactionId ?? event.eventId),
|
||||||
index: i,
|
index: i,
|
||||||
controller: controller.scrollController,
|
controller: controller.scrollController,
|
||||||
child: Message(
|
child: Message(
|
||||||
event,
|
event,
|
||||||
bigEmojis: controller.bigEmojis,
|
bigEmojis: controller.bigEmojis,
|
||||||
animateIn: animateIn,
|
animateIn: animateIn,
|
||||||
resetAnimateIn: () {
|
|
||||||
controller.animateInEventIndex = null;
|
|
||||||
},
|
|
||||||
onSwipe: () => controller.replyAction(replyTo: event),
|
onSwipe: () => controller.replyAction(replyTo: event),
|
||||||
onInfoTab: controller.showEventInfo,
|
onInfoTab: controller.showEventInfo,
|
||||||
onMention: () => controller.sendController.text +=
|
onMention: () => controller.sendController.text +=
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ class Message extends StatelessWidget {
|
||||||
final Timeline timeline;
|
final Timeline timeline;
|
||||||
final bool highlightMarker;
|
final bool highlightMarker;
|
||||||
final bool animateIn;
|
final bool animateIn;
|
||||||
final void Function()? resetAnimateIn;
|
|
||||||
final bool wallpaperMode;
|
final bool wallpaperMode;
|
||||||
final ScrollController scrollController;
|
final ScrollController scrollController;
|
||||||
final List<Color> colors;
|
final List<Color> colors;
|
||||||
|
|
@ -67,7 +66,6 @@ class Message extends StatelessWidget {
|
||||||
required this.timeline,
|
required this.timeline,
|
||||||
this.highlightMarker = false,
|
this.highlightMarker = false,
|
||||||
this.animateIn = false,
|
this.animateIn = false,
|
||||||
this.resetAnimateIn,
|
|
||||||
this.wallpaperMode = false,
|
this.wallpaperMode = false,
|
||||||
required this.onMention,
|
required this.onMention,
|
||||||
required this.scrollController,
|
required this.scrollController,
|
||||||
|
|
@ -171,9 +169,6 @@ class Message extends StatelessWidget {
|
||||||
: theme.bubbleColor;
|
: theme.bubbleColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
final resetAnimateIn = this.resetAnimateIn;
|
|
||||||
var animateIn = this.animateIn;
|
|
||||||
|
|
||||||
final sentReactions = <String>{};
|
final sentReactions = <String>{};
|
||||||
if (singleSelected) {
|
if (singleSelected) {
|
||||||
sentReactions.addAll(
|
sentReactions.addAll(
|
||||||
|
|
@ -209,7 +204,9 @@ class Message extends StatelessWidget {
|
||||||
final enterThread = this.enterThread;
|
final enterThread = this.enterThread;
|
||||||
final sender = event.senderFromMemoryOrFallback;
|
final sender = event.senderFromMemoryOrFallback;
|
||||||
|
|
||||||
return Center(
|
return _AnimateIn(
|
||||||
|
animateIn: animateIn,
|
||||||
|
child: Center(
|
||||||
child: Swipeable(
|
child: Swipeable(
|
||||||
key: ValueKey(event.eventId),
|
key: ValueKey(event.eventId),
|
||||||
background: const Padding(
|
background: const Padding(
|
||||||
|
|
@ -265,24 +262,7 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
StatefulBuilder(
|
Stack(
|
||||||
builder: (context, setState) {
|
|
||||||
if (animateIn && resetAnimateIn != null) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
|
||||||
animateIn = false;
|
|
||||||
setState(resetAnimateIn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return AnimatedSize(
|
|
||||||
duration: FluffyThemes.animationDuration,
|
|
||||||
curve: FluffyThemes.animationCurve,
|
|
||||||
clipBehavior: Clip.none,
|
|
||||||
alignment: ownMessage
|
|
||||||
? Alignment.bottomRight
|
|
||||||
: Alignment.bottomLeft,
|
|
||||||
child: animateIn
|
|
||||||
? const SizedBox(height: 0, width: double.infinity)
|
|
||||||
: Stack(
|
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
Positioned(
|
Positioned(
|
||||||
|
|
@ -291,13 +271,9 @@ class Message extends StatelessWidget {
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
hoverColor: longPressSelect
|
hoverColor: longPressSelect ? Colors.transparent : null,
|
||||||
? Colors.transparent
|
|
||||||
: null,
|
|
||||||
enableFeedback: !selected,
|
enableFeedback: !selected,
|
||||||
onTap: longPressSelect
|
onTap: longPressSelect ? null : () => onSelect(event),
|
||||||
? null
|
|
||||||
: () => onSelect(event),
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
AppConfig.borderRadius / 2,
|
AppConfig.borderRadius / 2,
|
||||||
),
|
),
|
||||||
|
|
@ -306,8 +282,9 @@ class Message extends StatelessWidget {
|
||||||
AppConfig.borderRadius / 2,
|
AppConfig.borderRadius / 2,
|
||||||
),
|
),
|
||||||
color: selected || highlightMarker
|
color: selected || highlightMarker
|
||||||
? theme.colorScheme.secondaryContainer
|
? theme.colorScheme.secondaryContainer.withAlpha(
|
||||||
.withAlpha(128)
|
128,
|
||||||
|
)
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -338,12 +315,8 @@ class Message extends StatelessWidget {
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
height: 16,
|
height: 16,
|
||||||
child:
|
child: event.status == EventStatus.error
|
||||||
event.status == EventStatus.error
|
? const Icon(Icons.error, color: Colors.red)
|
||||||
? const Icon(
|
|
||||||
Icons.error,
|
|
||||||
color: Colors.red,
|
|
||||||
)
|
|
||||||
: event.fileSendingStatus != null
|
: event.fileSendingStatus != null
|
||||||
? const CircularProgressIndicator.adaptive(
|
? const CircularProgressIndicator.adaptive(
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
|
|
@ -360,8 +333,7 @@ class Message extends StatelessWidget {
|
||||||
return Avatar(
|
return Avatar(
|
||||||
mxContent: user.avatarUrl,
|
mxContent: user.avatarUrl,
|
||||||
name: user.calcDisplayname(),
|
name: user.calcDisplayname(),
|
||||||
onTap: () =>
|
onTap: () => showMemberActionsPopupMenu(
|
||||||
showMemberActionsPopupMenu(
|
|
||||||
context: context,
|
context: context,
|
||||||
user: user,
|
user: user,
|
||||||
onMention: onMention,
|
onMention: onMention,
|
||||||
|
|
@ -384,22 +356,17 @@ class Message extends StatelessWidget {
|
||||||
left: 8.0,
|
left: 8.0,
|
||||||
bottom: 4,
|
bottom: 4,
|
||||||
),
|
),
|
||||||
child:
|
child: ownMessage || event.room.isDirectChat
|
||||||
ownMessage ||
|
|
||||||
event.room.isDirectChat
|
|
||||||
? const SizedBox(height: 12)
|
? const SizedBox(height: 12)
|
||||||
: Row(
|
: Row(
|
||||||
children: [
|
children: [
|
||||||
if (sender.powerLevel >=
|
if (sender.powerLevel >= 50)
|
||||||
50)
|
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(
|
|
||||||
right: 2.0,
|
right: 2.0,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
sender.powerLevel >=
|
sender.powerLevel >= 100
|
||||||
100
|
|
||||||
? Icons
|
? Icons
|
||||||
.admin_panel_settings
|
.admin_panel_settings
|
||||||
: Icons
|
: Icons
|
||||||
|
|
@ -412,31 +379,25 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FutureBuilder<User?>(
|
child: FutureBuilder<User?>(
|
||||||
future: event
|
future: event.fetchSenderUser(),
|
||||||
.fetchSenderUser(),
|
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final displayname =
|
final displayname =
|
||||||
snapshot.data
|
snapshot.data
|
||||||
?.calcDisplayname() ??
|
?.calcDisplayname() ??
|
||||||
sender
|
sender.calcDisplayname();
|
||||||
.calcDisplayname();
|
|
||||||
return Text(
|
return Text(
|
||||||
displayname,
|
displayname,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight:
|
fontWeight:
|
||||||
FontWeight
|
FontWeight.bold,
|
||||||
.bold,
|
|
||||||
color:
|
color:
|
||||||
(theme.brightness ==
|
(theme.brightness ==
|
||||||
Brightness
|
Brightness.light
|
||||||
.light
|
? displayname.color
|
||||||
? displayname
|
|
||||||
.color
|
|
||||||
: displayname
|
: displayname
|
||||||
.lightColorText),
|
.lightColorText),
|
||||||
shadows:
|
shadows: !wallpaperMode
|
||||||
!wallpaperMode
|
|
||||||
? null
|
? null
|
||||||
: [
|
: [
|
||||||
const Shadow(
|
const Shadow(
|
||||||
|
|
@ -444,17 +405,15 @@ class Message extends StatelessWidget {
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
),
|
),
|
||||||
blurRadius:
|
blurRadius: 3,
|
||||||
3,
|
color: Colors
|
||||||
color:
|
.black,
|
||||||
Colors.black,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow:
|
overflow:
|
||||||
TextOverflow
|
TextOverflow.ellipsis,
|
||||||
.ellipsis,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -464,9 +423,7 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(left: 8),
|
||||||
left: 8,
|
|
||||||
),
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onLongPress: longPressSelect
|
onLongPress: longPressSelect
|
||||||
? null
|
? null
|
||||||
|
|
@ -474,19 +431,6 @@ class Message extends StatelessWidget {
|
||||||
HapticFeedback.heavyImpact();
|
HapticFeedback.heavyImpact();
|
||||||
onSelect(event);
|
onSelect(event);
|
||||||
},
|
},
|
||||||
child: AnimatedOpacity(
|
|
||||||
opacity: animateIn
|
|
||||||
? 0
|
|
||||||
: event.messageType ==
|
|
||||||
MessageTypes
|
|
||||||
.BadEncrypted ||
|
|
||||||
event.status.isSending
|
|
||||||
? 0.5
|
|
||||||
: 1,
|
|
||||||
duration: FluffyThemes
|
|
||||||
.animationDuration,
|
|
||||||
curve:
|
|
||||||
FluffyThemes.animationCurve,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: noBubble
|
color: noBubble
|
||||||
|
|
@ -500,69 +444,49 @@ class Message extends StatelessWidget {
|
||||||
ignore:
|
ignore:
|
||||||
noBubble ||
|
noBubble ||
|
||||||
!ownMessage ||
|
!ownMessage ||
|
||||||
MediaQuery.highContrastOf(
|
MediaQuery.highContrastOf(context),
|
||||||
context,
|
scrollController: scrollController,
|
||||||
),
|
|
||||||
scrollController:
|
|
||||||
scrollController,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.circular(
|
||||||
BorderRadius.circular(
|
AppConfig.borderRadius,
|
||||||
AppConfig
|
|
||||||
.borderRadius,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
constraints:
|
constraints: const BoxConstraints(
|
||||||
const BoxConstraints(
|
|
||||||
maxWidth:
|
maxWidth:
|
||||||
FluffyThemes
|
FluffyThemes.columnWidth * 1.5,
|
||||||
.columnWidth *
|
|
||||||
1.5,
|
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: .min,
|
mainAxisSize: .min,
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment
|
CrossAxisAlignment.start,
|
||||||
.start,
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (event.inReplyToEventId(
|
if (event.inReplyToEventId(
|
||||||
includingFallback:
|
includingFallback: false,
|
||||||
false,
|
|
||||||
) !=
|
) !=
|
||||||
null)
|
null)
|
||||||
FutureBuilder<Event?>(
|
FutureBuilder<Event?>(
|
||||||
future: event
|
future: event.getReplyEvent(
|
||||||
.getReplyEvent(
|
|
||||||
timeline,
|
timeline,
|
||||||
),
|
),
|
||||||
builder:
|
builder: (BuildContext context, snapshot) {
|
||||||
(
|
|
||||||
BuildContext
|
|
||||||
context,
|
|
||||||
snapshot,
|
|
||||||
) {
|
|
||||||
final replyEvent =
|
final replyEvent =
|
||||||
snapshot
|
snapshot.hasData
|
||||||
.hasData
|
? snapshot.data!
|
||||||
? snapshot
|
|
||||||
.data!
|
|
||||||
: Event(
|
: Event(
|
||||||
eventId:
|
eventId:
|
||||||
event.inReplyToEventId() ??
|
event
|
||||||
|
.inReplyToEventId() ??
|
||||||
'\$fake_event_id',
|
'\$fake_event_id',
|
||||||
content: {
|
content: {
|
||||||
'msgtype':
|
'msgtype': 'm.text',
|
||||||
'm.text',
|
'body': '...',
|
||||||
'body':
|
|
||||||
'...',
|
|
||||||
},
|
},
|
||||||
senderId:
|
senderId:
|
||||||
event.senderId,
|
event.senderId,
|
||||||
type:
|
type:
|
||||||
'm.room.message',
|
'm.room.message',
|
||||||
room:
|
room: event.room,
|
||||||
event.room,
|
|
||||||
status:
|
status:
|
||||||
EventStatus.sent,
|
EventStatus.sent,
|
||||||
originServerTs:
|
originServerTs:
|
||||||
|
|
@ -571,23 +495,20 @@ class Message extends StatelessWidget {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.only(
|
const EdgeInsets.only(
|
||||||
left:
|
left: 16,
|
||||||
16,
|
right: 16,
|
||||||
right:
|
top: 8,
|
||||||
16,
|
|
||||||
top:
|
|
||||||
8,
|
|
||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors
|
color: Colors.transparent,
|
||||||
.transparent,
|
borderRadius: ReplyContent
|
||||||
borderRadius:
|
|
||||||
ReplyContent
|
|
||||||
.borderRadius,
|
.borderRadius,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius:
|
borderRadius:
|
||||||
ReplyContent.borderRadius,
|
ReplyContent
|
||||||
onTap: () => scrollToEventId(
|
.borderRadius,
|
||||||
|
onTap: () =>
|
||||||
|
scrollToEventId(
|
||||||
replyEvent
|
replyEvent
|
||||||
.eventId,
|
.eventId,
|
||||||
),
|
),
|
||||||
|
|
@ -596,8 +517,7 @@ class Message extends StatelessWidget {
|
||||||
replyEvent,
|
replyEvent,
|
||||||
ownMessage:
|
ownMessage:
|
||||||
ownMessage,
|
ownMessage,
|
||||||
timeline:
|
timeline: timeline,
|
||||||
timeline,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -610,38 +530,30 @@ class Message extends StatelessWidget {
|
||||||
textColor: textColor,
|
textColor: textColor,
|
||||||
linkColor: linkColor,
|
linkColor: linkColor,
|
||||||
onInfoTab: onInfoTab,
|
onInfoTab: onInfoTab,
|
||||||
borderRadius:
|
borderRadius: borderRadius,
|
||||||
borderRadius,
|
|
||||||
timeline: timeline,
|
timeline: timeline,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
bigEmojis: bigEmojis,
|
bigEmojis: bigEmojis,
|
||||||
),
|
),
|
||||||
if (event
|
if (event.hasAggregatedEvents(
|
||||||
.hasAggregatedEvents(
|
|
||||||
timeline,
|
timeline,
|
||||||
RelationshipTypes
|
RelationshipTypes.edit,
|
||||||
.edit,
|
|
||||||
))
|
))
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(
|
|
||||||
bottom: 8.0,
|
bottom: 8.0,
|
||||||
left: 16.0,
|
left: 16.0,
|
||||||
right: 16.0,
|
right: 16.0,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize:
|
mainAxisSize:
|
||||||
MainAxisSize
|
MainAxisSize.min,
|
||||||
.min,
|
|
||||||
spacing: 4.0,
|
spacing: 4.0,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
Icons
|
Icons.edit_outlined,
|
||||||
.edit_outlined,
|
|
||||||
color: textColor
|
color: textColor
|
||||||
.withAlpha(
|
.withAlpha(164),
|
||||||
164,
|
|
||||||
),
|
|
||||||
size: 14,
|
size: 14,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -652,11 +564,8 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: textColor
|
color: textColor
|
||||||
.withAlpha(
|
.withAlpha(164),
|
||||||
164,
|
fontSize: 11,
|
||||||
),
|
|
||||||
fontSize:
|
|
||||||
11,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -669,76 +578,61 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
Align(
|
Align(
|
||||||
alignment: ownMessage
|
alignment: ownMessage
|
||||||
? Alignment.bottomRight
|
? Alignment.bottomRight
|
||||||
: Alignment.bottomLeft,
|
: Alignment.bottomLeft,
|
||||||
child: AnimatedSize(
|
child: AnimatedSize(
|
||||||
duration:
|
duration: FluffyThemes.animationDuration,
|
||||||
FluffyThemes.animationDuration,
|
|
||||||
curve: FluffyThemes.animationCurve,
|
curve: FluffyThemes.animationCurve,
|
||||||
child: showReactionPicker
|
child: showReactionPicker
|
||||||
? Padding(
|
? Padding(
|
||||||
padding:
|
padding: const EdgeInsets.all(4.0),
|
||||||
const EdgeInsets.all(
|
|
||||||
4.0,
|
|
||||||
),
|
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
borderRadius:
|
borderRadius: BorderRadius.circular(
|
||||||
BorderRadius.circular(
|
AppConfig.borderRadius,
|
||||||
AppConfig
|
|
||||||
.borderRadius,
|
|
||||||
),
|
),
|
||||||
shadowColor: theme
|
shadowColor: theme
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.surface
|
.surface
|
||||||
.withAlpha(128),
|
.withAlpha(128),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection:
|
scrollDirection: Axis.horizontal,
|
||||||
Axis.horizontal,
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: .min,
|
mainAxisSize: .min,
|
||||||
children: [
|
children: [
|
||||||
...AppConfig.defaultReactions.map(
|
...AppConfig.defaultReactions.map(
|
||||||
(
|
(emoji) => IconButton(
|
||||||
emoji,
|
padding: EdgeInsets.zero,
|
||||||
) => IconButton(
|
|
||||||
padding:
|
|
||||||
EdgeInsets
|
|
||||||
.zero,
|
|
||||||
icon: Center(
|
icon: Center(
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
opacity:
|
opacity:
|
||||||
sentReactions.contains(
|
sentReactions
|
||||||
|
.contains(
|
||||||
emoji,
|
emoji,
|
||||||
)
|
)
|
||||||
? 0.33
|
? 0.33
|
||||||
: 1,
|
: 1,
|
||||||
child: Text(
|
child: Text(
|
||||||
emoji,
|
emoji,
|
||||||
style: const TextStyle(
|
style:
|
||||||
fontSize:
|
const TextStyle(
|
||||||
20,
|
fontSize: 20,
|
||||||
),
|
),
|
||||||
textAlign:
|
textAlign: TextAlign
|
||||||
TextAlign
|
|
||||||
.center,
|
.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed:
|
onPressed:
|
||||||
sentReactions
|
sentReactions
|
||||||
.contains(
|
.contains(emoji)
|
||||||
emoji,
|
|
||||||
)
|
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
onSelect(
|
onSelect(event);
|
||||||
event,
|
event.room
|
||||||
);
|
.sendReaction(
|
||||||
event.room.sendReaction(
|
|
||||||
event
|
event
|
||||||
.eventId,
|
.eventId,
|
||||||
emoji,
|
emoji,
|
||||||
|
|
@ -756,8 +650,7 @@ class Message extends StatelessWidget {
|
||||||
).customReaction,
|
).customReaction,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final emoji = await showAdaptiveBottomSheet<String>(
|
final emoji = await showAdaptiveBottomSheet<String>(
|
||||||
context:
|
context: context,
|
||||||
context,
|
|
||||||
builder: (context) => Scaffold(
|
builder: (context) => Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
|
|
@ -766,82 +659,94 @@ class Message extends StatelessWidget {
|
||||||
).customReaction,
|
).customReaction,
|
||||||
),
|
),
|
||||||
leading: CloseButton(
|
leading: CloseButton(
|
||||||
onPressed: () => Navigator.of(
|
onPressed: () =>
|
||||||
|
Navigator.of(
|
||||||
context,
|
context,
|
||||||
).pop(null),
|
).pop(null),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: SizedBox(
|
body: SizedBox(
|
||||||
height: double
|
height:
|
||||||
.infinity,
|
double.infinity,
|
||||||
child: EmojiPicker(
|
child: EmojiPicker(
|
||||||
onEmojiSelected:
|
onEmojiSelected:
|
||||||
(
|
(_, emoji) =>
|
||||||
_,
|
|
||||||
emoji,
|
|
||||||
) =>
|
|
||||||
Navigator.of(
|
Navigator.of(
|
||||||
context,
|
context,
|
||||||
).pop(
|
).pop(
|
||||||
emoji.emoji,
|
emoji
|
||||||
|
.emoji,
|
||||||
),
|
),
|
||||||
config: Config(
|
config: Config(
|
||||||
locale: Localizations.localeOf(
|
locale:
|
||||||
|
Localizations.localeOf(
|
||||||
context,
|
context,
|
||||||
),
|
),
|
||||||
emojiViewConfig: const EmojiViewConfig(
|
emojiViewConfig:
|
||||||
|
const EmojiViewConfig(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Colors.transparent,
|
Colors
|
||||||
|
.transparent,
|
||||||
),
|
),
|
||||||
bottomActionBarConfig: const BottomActionBarConfig(
|
bottomActionBarConfig:
|
||||||
|
const BottomActionBarConfig(
|
||||||
enabled:
|
enabled:
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
categoryViewConfig: CategoryViewConfig(
|
categoryViewConfig: CategoryViewConfig(
|
||||||
initCategory:
|
initCategory:
|
||||||
Category.SMILEYS,
|
Category
|
||||||
backspaceColor:
|
.SMILEYS,
|
||||||
theme.colorScheme.primary,
|
backspaceColor: theme
|
||||||
iconColor: theme.colorScheme.primary.withAlpha(
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
iconColor: theme
|
||||||
|
.colorScheme
|
||||||
|
.primary
|
||||||
|
.withAlpha(
|
||||||
128,
|
128,
|
||||||
),
|
),
|
||||||
iconColorSelected:
|
iconColorSelected: theme
|
||||||
theme.colorScheme.primary,
|
.colorScheme
|
||||||
indicatorColor:
|
.primary,
|
||||||
theme.colorScheme.primary,
|
indicatorColor: theme
|
||||||
backgroundColor:
|
.colorScheme
|
||||||
theme.colorScheme.surface,
|
.primary,
|
||||||
|
backgroundColor: theme
|
||||||
|
.colorScheme
|
||||||
|
.surface,
|
||||||
),
|
),
|
||||||
skinToneConfig: SkinToneConfig(
|
skinToneConfig: SkinToneConfig(
|
||||||
dialogBackgroundColor: Color.lerp(
|
dialogBackgroundColor: Color.lerp(
|
||||||
theme.colorScheme.surface,
|
theme
|
||||||
theme.colorScheme.primaryContainer,
|
.colorScheme
|
||||||
|
.surface,
|
||||||
|
theme
|
||||||
|
.colorScheme
|
||||||
|
.primaryContainer,
|
||||||
0.75,
|
0.75,
|
||||||
)!,
|
)!,
|
||||||
indicatorColor:
|
indicatorColor: theme
|
||||||
theme.colorScheme.onSurface,
|
.colorScheme
|
||||||
|
.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (emoji ==
|
if (emoji == null) {
|
||||||
null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sentReactions
|
if (sentReactions
|
||||||
.contains(
|
.contains(emoji)) {
|
||||||
emoji,
|
|
||||||
)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onSelect(event);
|
onSelect(event);
|
||||||
|
|
||||||
await event.room
|
await event.room
|
||||||
.sendReaction(
|
.sendReaction(
|
||||||
event
|
event.eventId,
|
||||||
.eventId,
|
|
||||||
emoji,
|
emoji,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -861,9 +766,6 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
AnimatedSize(
|
AnimatedSize(
|
||||||
duration: FluffyThemes.animationDuration,
|
duration: FluffyThemes.animationDuration,
|
||||||
|
|
@ -959,6 +861,7 @@ class Message extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1033,3 +936,37 @@ class BubblePainter extends CustomPainter {
|
||||||
return scrollable.position != oldScrollable?.position;
|
return scrollable.position != oldScrollable?.position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AnimateIn extends StatefulWidget {
|
||||||
|
final bool animateIn;
|
||||||
|
final Widget child;
|
||||||
|
const _AnimateIn({required this.animateIn, required this.child});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_AnimateIn> createState() => __AnimateInState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __AnimateInState extends State<_AnimateIn> {
|
||||||
|
bool _animationFinished = false;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!widget.animateIn) return widget.child;
|
||||||
|
if (!_animationFinished) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
_animationFinished = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return AnimatedOpacity(
|
||||||
|
duration: FluffyThemes.animationDuration,
|
||||||
|
curve: FluffyThemes.animationCurve,
|
||||||
|
opacity: _animationFinished ? 1 : 0,
|
||||||
|
child: AnimatedSize(
|
||||||
|
duration: FluffyThemes.animationDuration,
|
||||||
|
curve: FluffyThemes.animationCurve,
|
||||||
|
child: _animationFinished ? widget.child : const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
|
||||||
import 'package:fluffychat/config/setting_keys.dart';
|
import 'package:fluffychat/config/setting_keys.dart';
|
||||||
import 'package:fluffychat/utils/account_config.dart';
|
import 'package:fluffychat/utils/account_config.dart';
|
||||||
import 'package:fluffychat/utils/file_selector.dart';
|
import 'package:fluffychat/utils/file_selector.dart';
|
||||||
|
|
@ -111,32 +110,6 @@ class SettingsStyleController extends State<SettingsStyle> {
|
||||||
ThemeMode get currentTheme => ThemeController.of(context).themeMode;
|
ThemeMode get currentTheme => ThemeController.of(context).themeMode;
|
||||||
Color? get currentColor => ThemeController.of(context).primaryColor;
|
Color? get currentColor => ThemeController.of(context).primaryColor;
|
||||||
|
|
||||||
static final List<Color?> customColors = [
|
|
||||||
null,
|
|
||||||
AppConfig.chatColor,
|
|
||||||
Colors.indigo,
|
|
||||||
Colors.blue,
|
|
||||||
Colors.blueAccent,
|
|
||||||
Colors.teal,
|
|
||||||
Colors.tealAccent,
|
|
||||||
Colors.green,
|
|
||||||
Colors.greenAccent,
|
|
||||||
Colors.yellow,
|
|
||||||
Colors.yellowAccent,
|
|
||||||
Colors.orange,
|
|
||||||
Colors.orangeAccent,
|
|
||||||
Colors.red,
|
|
||||||
Colors.redAccent,
|
|
||||||
Colors.pink,
|
|
||||||
Colors.pinkAccent,
|
|
||||||
Colors.purple,
|
|
||||||
Colors.purpleAccent,
|
|
||||||
Colors.blueGrey,
|
|
||||||
Colors.grey,
|
|
||||||
Colors.white,
|
|
||||||
Colors.black,
|
|
||||||
];
|
|
||||||
|
|
||||||
void switchTheme(ThemeMode? newTheme) {
|
void switchTheme(ThemeMode? newTheme) {
|
||||||
if (newTheme == null) return;
|
if (newTheme == null) return;
|
||||||
switch (newTheme) {
|
switch (newTheme) {
|
||||||
|
|
|
||||||
|
|
@ -82,14 +82,13 @@ class SettingsStyleView extends StatelessWidget {
|
||||||
Theme.of(context).brightness == Brightness.light
|
Theme.of(context).brightness == Brightness.light
|
||||||
? light?.primary
|
? light?.primary
|
||||||
: dark?.primary;
|
: dark?.primary;
|
||||||
final colors = List<Color?>.from(
|
final colors = [null, AppConfig.chatColor, ...Colors.primaries];
|
||||||
SettingsStyleController.customColors,
|
|
||||||
);
|
|
||||||
if (systemColor == null) {
|
if (systemColor == null) {
|
||||||
colors.remove(null);
|
colors.remove(null);
|
||||||
}
|
}
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 64,
|
maxCrossAxisExtent: 64,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue