feat: Directing to click messages with shimmer (#5106)
This commit is contained in:
parent
af395d0aeb
commit
832533b4f7
6 changed files with 275 additions and 225 deletions
|
|
@ -1997,6 +1997,17 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
bool get _isToolbarOpen =>
|
||||
MatrixState.pAnyState.isOverlayOpen(RegExp(r'^message_toolbar_overlay$'));
|
||||
|
||||
bool showMessageShimmer(Event event) {
|
||||
if (event.type != EventTypes.Message) return false;
|
||||
if (event.messageType == MessageTypes.Text) {
|
||||
return !InstructionsEnum.clickTextMessages.isToggledOff;
|
||||
}
|
||||
if (event.messageType == MessageTypes.Audio) {
|
||||
return !InstructionsEnum.clickAudioMessages.isToggledOff;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void showToolbar(
|
||||
Event event, {
|
||||
PangeaMessageEvent? pangeaMessageEvent,
|
||||
|
|
@ -2060,6 +2071,14 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
|
||||
// you've clicked a message so lets turn this off
|
||||
InstructionsEnum.clickMessage.setToggledOff(true);
|
||||
if (event.messageType == MessageTypes.Text &&
|
||||
!InstructionsEnum.clickTextMessages.isToggledOff) {
|
||||
InstructionsEnum.clickTextMessages.setToggledOff(true);
|
||||
}
|
||||
if (event.messageType == MessageTypes.Audio &&
|
||||
!InstructionsEnum.clickAudioMessages.isToggledOff) {
|
||||
InstructionsEnum.clickAudioMessages.setToggledOff(true);
|
||||
}
|
||||
|
||||
if (!kIsWeb) {
|
||||
HapticFeedback.mediumImpact();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class AudioPlayerWidget extends StatefulWidget {
|
|||
final String senderId;
|
||||
final PangeaAudioFile? matrixFile;
|
||||
final bool autoplay;
|
||||
final bool enableClicks;
|
||||
// Pangea#
|
||||
|
||||
static const int wavesCount = 40;
|
||||
|
|
@ -49,6 +50,7 @@ class AudioPlayerWidget extends StatefulWidget {
|
|||
required this.senderId,
|
||||
this.matrixFile,
|
||||
this.autoplay = false,
|
||||
this.enableClicks = true,
|
||||
// Pangea#
|
||||
super.key,
|
||||
});
|
||||
|
|
@ -564,13 +566,25 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
|
|||
: Colors.transparent,
|
||||
max: maxPosition,
|
||||
value: currentPosition,
|
||||
onChanged: (position) => audioPlayer == null
|
||||
? _onButtonTap()
|
||||
: audioPlayer.seek(
|
||||
Duration(
|
||||
milliseconds: position.round(),
|
||||
),
|
||||
),
|
||||
// #Pangea
|
||||
onChanged: !widget.enableClicks
|
||||
? null
|
||||
: (position) => audioPlayer == null
|
||||
? _onButtonTap()
|
||||
: audioPlayer.seek(
|
||||
Duration(
|
||||
milliseconds:
|
||||
position.round(),
|
||||
),
|
||||
),
|
||||
// onChanged: (position) => audioPlayer == null
|
||||
// ? _onButtonTap()
|
||||
// : audioPlayer.seek(
|
||||
// Duration(
|
||||
// milliseconds: position.round(),
|
||||
// ),
|
||||
// ),
|
||||
// Pangea#
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -605,7 +619,7 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
|
|||
child: InkWell(
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
onTap: _toggleSpeed,
|
||||
onTap: !widget.enableClicks ? null : _toggleSpeed,
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 20,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import 'package:fluffychat/pangea/activity_sessions/activity_summary_widget.dart
|
|||
import 'package:fluffychat/pangea/chat/extensions/custom_room_display_extension.dart';
|
||||
import 'package:fluffychat/pangea/chat/widgets/request_regeneration_button.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/pressable_button.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/shimmer_background.dart';
|
||||
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/utils/date_time_extension.dart';
|
||||
|
|
@ -585,235 +586,241 @@ class Message extends StatelessWidget {
|
|||
child: ValueListenableBuilder(
|
||||
valueListenable: controller
|
||||
.depressMessageButton,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: noBubble
|
||||
? Colors.transparent
|
||||
: color,
|
||||
borderRadius:
|
||||
borderRadius,
|
||||
// #Pangea
|
||||
child: ShimmerBackground(
|
||||
enabled: controller
|
||||
.showMessageShimmer(
|
||||
event,
|
||||
),
|
||||
clipBehavior:
|
||||
Clip.antiAlias,
|
||||
// #Pangea
|
||||
child:
|
||||
CompositedTransformTarget(
|
||||
link: MatrixState
|
||||
.pAnyState
|
||||
.layerLinkAndKey(
|
||||
event.eventId,
|
||||
)
|
||||
.link,
|
||||
// child: BubbleBackground(
|
||||
// colors: colors,
|
||||
// ignore: noBubble || !ownMessage,
|
||||
// scrollController: scrollController,
|
||||
// Pangea#
|
||||
child: Container(
|
||||
// #Pangea
|
||||
key: MatrixState
|
||||
// Pangea#
|
||||
child: Container(
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
color: noBubble
|
||||
? Colors
|
||||
.transparent
|
||||
: color,
|
||||
borderRadius:
|
||||
borderRadius,
|
||||
),
|
||||
clipBehavior:
|
||||
Clip.antiAlias,
|
||||
// #Pangea
|
||||
child:
|
||||
CompositedTransformTarget(
|
||||
link: MatrixState
|
||||
.pAnyState
|
||||
.layerLinkAndKey(
|
||||
event.eventId,
|
||||
)
|
||||
.key,
|
||||
.link,
|
||||
// child: BubbleBackground(
|
||||
// colors: colors,
|
||||
// ignore: noBubble || !ownMessage,
|
||||
// scrollController: scrollController,
|
||||
// Pangea#
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(
|
||||
AppConfig
|
||||
.borderRadius,
|
||||
child: Container(
|
||||
// #Pangea
|
||||
key: MatrixState
|
||||
.pAnyState
|
||||
.layerLinkAndKey(
|
||||
event.eventId,
|
||||
)
|
||||
.key,
|
||||
// Pangea#
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(
|
||||
AppConfig
|
||||
.borderRadius,
|
||||
),
|
||||
),
|
||||
),
|
||||
constraints:
|
||||
const BoxConstraints(
|
||||
maxWidth: FluffyThemes
|
||||
.columnWidth *
|
||||
1.5,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize:
|
||||
MainAxisSize
|
||||
.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment
|
||||
.start,
|
||||
children: <Widget>[
|
||||
if ({
|
||||
RelationshipTypes
|
||||
.reply,
|
||||
RelationshipTypes
|
||||
.thread,
|
||||
}.contains(
|
||||
event
|
||||
.relationshipType,
|
||||
))
|
||||
FutureBuilder<
|
||||
Event?>(
|
||||
future: event
|
||||
.getReplyEvent(
|
||||
timeline,
|
||||
),
|
||||
builder: (
|
||||
BuildContext
|
||||
context,
|
||||
snapshot,
|
||||
) {
|
||||
final replyEvent = snapshot
|
||||
.hasData
|
||||
? snapshot
|
||||
.data!
|
||||
: Event(
|
||||
eventId:
|
||||
event.relationshipEventId!,
|
||||
content: {
|
||||
'msgtype': 'm.text',
|
||||
'body': '...',
|
||||
},
|
||||
// #Pangea
|
||||
// senderId: event
|
||||
// .senderId,
|
||||
senderId:
|
||||
"",
|
||||
// Pangea#
|
||||
type:
|
||||
'm.room.message',
|
||||
room:
|
||||
event.room,
|
||||
status:
|
||||
EventStatus.sent,
|
||||
originServerTs:
|
||||
DateTime.now(),
|
||||
);
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets
|
||||
.only(
|
||||
left:
|
||||
16,
|
||||
right:
|
||||
16,
|
||||
top: 8,
|
||||
),
|
||||
child:
|
||||
Material(
|
||||
color: Colors
|
||||
.transparent,
|
||||
borderRadius:
|
||||
ReplyContent.borderRadius,
|
||||
constraints:
|
||||
const BoxConstraints(
|
||||
maxWidth: FluffyThemes
|
||||
.columnWidth *
|
||||
1.5,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize:
|
||||
MainAxisSize
|
||||
.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment
|
||||
.start,
|
||||
children: <Widget>[
|
||||
if ({
|
||||
RelationshipTypes
|
||||
.reply,
|
||||
RelationshipTypes
|
||||
.thread,
|
||||
}.contains(
|
||||
event
|
||||
.relationshipType,
|
||||
))
|
||||
FutureBuilder<
|
||||
Event?>(
|
||||
future: event
|
||||
.getReplyEvent(
|
||||
timeline,
|
||||
),
|
||||
builder: (
|
||||
BuildContext
|
||||
context,
|
||||
snapshot,
|
||||
) {
|
||||
final replyEvent = snapshot
|
||||
.hasData
|
||||
? snapshot
|
||||
.data!
|
||||
: Event(
|
||||
eventId: event.relationshipEventId!,
|
||||
content: {
|
||||
'msgtype': 'm.text',
|
||||
'body': '...',
|
||||
},
|
||||
// #Pangea
|
||||
// senderId: event
|
||||
// .senderId,
|
||||
senderId: "",
|
||||
// Pangea#
|
||||
type: 'm.room.message',
|
||||
room: event.room,
|
||||
status: EventStatus.sent,
|
||||
originServerTs: DateTime.now(),
|
||||
);
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(
|
||||
left:
|
||||
16,
|
||||
right:
|
||||
16,
|
||||
top:
|
||||
8,
|
||||
),
|
||||
child:
|
||||
InkWell(
|
||||
Material(
|
||||
color:
|
||||
Colors.transparent,
|
||||
borderRadius:
|
||||
ReplyContent.borderRadius,
|
||||
onTap: () =>
|
||||
scrollToEventId(
|
||||
replyEvent.eventId,
|
||||
),
|
||||
child:
|
||||
AbsorbPointer(
|
||||
InkWell(
|
||||
borderRadius:
|
||||
ReplyContent.borderRadius,
|
||||
onTap: () =>
|
||||
scrollToEventId(
|
||||
replyEvent.eventId,
|
||||
),
|
||||
child:
|
||||
ReplyContent(
|
||||
replyEvent,
|
||||
ownMessage: ownMessage,
|
||||
timeline: timeline,
|
||||
AbsorbPointer(
|
||||
child: ReplyContent(
|
||||
replyEvent,
|
||||
ownMessage: ownMessage,
|
||||
timeline: timeline,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
MessageContent(
|
||||
displayEvent,
|
||||
textColor:
|
||||
textColor,
|
||||
linkColor:
|
||||
linkColor,
|
||||
onInfoTab:
|
||||
onInfoTab,
|
||||
borderRadius:
|
||||
borderRadius,
|
||||
timeline:
|
||||
timeline,
|
||||
selected:
|
||||
selected,
|
||||
// #Pangea
|
||||
pangeaMessageEvent:
|
||||
pangeaMessageEvent,
|
||||
controller:
|
||||
controller,
|
||||
nextEvent:
|
||||
nextEvent,
|
||||
prevEvent:
|
||||
previousEvent,
|
||||
// Pangea#
|
||||
),
|
||||
if (event
|
||||
.hasAggregatedEvents(
|
||||
timeline,
|
||||
RelationshipTypes
|
||||
.edit,
|
||||
))
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets
|
||||
.only(
|
||||
bottom: 8.0,
|
||||
left: 16.0,
|
||||
right: 16.0,
|
||||
);
|
||||
},
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize
|
||||
.min,
|
||||
spacing:
|
||||
4.0,
|
||||
children: [
|
||||
Icon(
|
||||
Icons
|
||||
.edit_outlined,
|
||||
color: textColor
|
||||
.withAlpha(
|
||||
164,
|
||||
),
|
||||
size:
|
||||
14,
|
||||
),
|
||||
Text(
|
||||
displayEvent
|
||||
.originServerTs
|
||||
.localizedTimeShort(
|
||||
context,
|
||||
),
|
||||
style:
|
||||
TextStyle(
|
||||
MessageContent(
|
||||
displayEvent,
|
||||
textColor:
|
||||
textColor,
|
||||
linkColor:
|
||||
linkColor,
|
||||
onInfoTab:
|
||||
onInfoTab,
|
||||
borderRadius:
|
||||
borderRadius,
|
||||
timeline:
|
||||
timeline,
|
||||
selected:
|
||||
selected,
|
||||
// #Pangea
|
||||
pangeaMessageEvent:
|
||||
pangeaMessageEvent,
|
||||
controller:
|
||||
controller,
|
||||
nextEvent:
|
||||
nextEvent,
|
||||
prevEvent:
|
||||
previousEvent,
|
||||
// Pangea#
|
||||
),
|
||||
if (event
|
||||
.hasAggregatedEvents(
|
||||
timeline,
|
||||
RelationshipTypes
|
||||
.edit,
|
||||
))
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets
|
||||
.only(
|
||||
bottom:
|
||||
8.0,
|
||||
left:
|
||||
16.0,
|
||||
right:
|
||||
16.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize
|
||||
.min,
|
||||
spacing:
|
||||
4.0,
|
||||
children: [
|
||||
Icon(
|
||||
Icons
|
||||
.edit_outlined,
|
||||
color:
|
||||
textColor.withAlpha(
|
||||
164,
|
||||
),
|
||||
fontSize:
|
||||
11,
|
||||
size:
|
||||
14,
|
||||
),
|
||||
),
|
||||
],
|
||||
Text(
|
||||
displayEvent
|
||||
.originServerTs
|
||||
.localizedTimeShort(
|
||||
context,
|
||||
),
|
||||
style:
|
||||
TextStyle(
|
||||
color:
|
||||
textColor.withAlpha(
|
||||
164,
|
||||
),
|
||||
fontSize:
|
||||
11,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
// #Pangea
|
||||
else if (canRefresh)
|
||||
RequestRegenerationButton(
|
||||
textColor:
|
||||
textColor,
|
||||
onPressed: () =>
|
||||
controller
|
||||
.requestRegeneration(
|
||||
event
|
||||
.eventId,
|
||||
),
|
||||
),
|
||||
)
|
||||
// #Pangea
|
||||
else if (canRefresh)
|
||||
RequestRegenerationButton(
|
||||
textColor:
|
||||
textColor,
|
||||
onPressed: () =>
|
||||
controller
|
||||
.requestRegeneration(
|
||||
event
|
||||
.eventId,
|
||||
),
|
||||
),
|
||||
// Pangea#
|
||||
],
|
||||
// Pangea#
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ class MessageContent extends StatelessWidget {
|
|||
roomId: event.room.id,
|
||||
senderId: event.senderId,
|
||||
autoplay: overlayController != null && isTransitionAnimation,
|
||||
enableClicks: overlayController != null,
|
||||
// Pangea#
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,19 @@ class ShimmerBackground extends StatelessWidget {
|
|||
child,
|
||||
if (enabled)
|
||||
Positioned.fill(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
child: Shimmer.fromColors(
|
||||
baseColor: shimmerColor.withValues(alpha: 0.1),
|
||||
highlightColor: shimmerColor.withValues(alpha: 0.6),
|
||||
direction: ShimmerDirection.ltr,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: shimmerColor.withValues(alpha: 0.3),
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
child: IgnorePointer(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
child: Shimmer.fromColors(
|
||||
baseColor: shimmerColor.withValues(alpha: 0.1),
|
||||
highlightColor: shimmerColor.withValues(alpha: 0.6),
|
||||
direction: ShimmerDirection.ltr,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: shimmerColor.withValues(alpha: 0.3),
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ enum InstructionsEnum {
|
|||
setLemmaEmoji,
|
||||
disableLanguageTools,
|
||||
selectMeaning,
|
||||
clickTextMessages,
|
||||
clickAudioMessages,
|
||||
}
|
||||
|
||||
extension InstructionsEnumExtension on InstructionsEnum {
|
||||
|
|
@ -63,6 +65,8 @@ extension InstructionsEnumExtension on InstructionsEnum {
|
|||
case InstructionsEnum.noSavedActivitiesYet:
|
||||
case InstructionsEnum.setLemmaEmoji:
|
||||
case InstructionsEnum.disableLanguageTools:
|
||||
case InstructionsEnum.clickTextMessages:
|
||||
case InstructionsEnum.clickAudioMessages:
|
||||
ErrorHandler.logError(
|
||||
e: Exception("No title for this instruction"),
|
||||
m: 'InstructionsEnumExtension.title',
|
||||
|
|
@ -124,6 +128,8 @@ extension InstructionsEnumExtension on InstructionsEnum {
|
|||
case InstructionsEnum.noSavedActivitiesYet:
|
||||
return l10n.noSavedActivitiesYet;
|
||||
case InstructionsEnum.setLemmaEmoji:
|
||||
case InstructionsEnum.clickTextMessages:
|
||||
case InstructionsEnum.clickAudioMessages:
|
||||
return "";
|
||||
case InstructionsEnum.disableLanguageTools:
|
||||
return l10n.disableLanguageToolsDesc;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue