fluffychat merge
This commit is contained in:
commit
3b33e92ffc
5 changed files with 511 additions and 374 deletions
|
|
@ -1432,6 +1432,16 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
return true;
|
||||
}
|
||||
|
||||
bool get canEditSelectedEvents {
|
||||
if (isArchived ||
|
||||
selectedEvents.length != 1 ||
|
||||
!selectedEvents.first.status.isSent) {
|
||||
return false;
|
||||
}
|
||||
return currentRoomBundle
|
||||
.any((cl) => selectedEvents.first.senderId == cl!.userID);
|
||||
}
|
||||
|
||||
void forwardEventsAction() async {
|
||||
if (selectedEvents.isEmpty) return;
|
||||
await showScaffoldDialog(
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class ChatInputRow extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
const height = 48.0;
|
||||
|
||||
if (!controller.room.otherPartyCanReceiveMessages) {
|
||||
|
|
@ -39,238 +40,302 @@ class ChatInputRow extends StatelessWidget {
|
|||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
const SizedBox(width: 4),
|
||||
AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
width: controller.sendController.text.isNotEmpty ? 0 : height,
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: PopupMenuButton<String>(
|
||||
useRootNavigator: true,
|
||||
enabled: !controller.selectMode,
|
||||
icon: const Icon(Icons.add_circle_outline),
|
||||
iconColor: theme.colorScheme.onPrimaryContainer,
|
||||
onSelected: controller.onAddPopupMenuButtonSelected,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||
if (PlatformInfos.isMobile)
|
||||
PopupMenuItem<String>(
|
||||
value: 'location',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.gps_fixed_outlined),
|
||||
children: controller.selectMode
|
||||
? <Widget>[
|
||||
if (controller.selectedEvents
|
||||
.every((event) => event.status == EventStatus.error))
|
||||
SizedBox(
|
||||
height: height,
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: theme.colorScheme.error,
|
||||
),
|
||||
onPressed: controller.deleteErrorEventsAction,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
const Icon(Icons.delete),
|
||||
Text(L10n.of(context).delete),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
SizedBox(
|
||||
height: height,
|
||||
child: TextButton(
|
||||
onPressed: controller.forwardEventsAction,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
const Icon(Icons.keyboard_arrow_left_outlined),
|
||||
Text(L10n.of(context).forward),
|
||||
],
|
||||
),
|
||||
title: Text(L10n.of(context).shareLocation),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'image',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.photo_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).sendImage),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
controller.selectedEvents.length == 1
|
||||
? controller.selectedEvents.first
|
||||
.getDisplayEvent(controller.timeline!)
|
||||
.status
|
||||
.isSent
|
||||
? SizedBox(
|
||||
height: height,
|
||||
child: TextButton(
|
||||
onPressed: controller.replyAction,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(L10n.of(context).reply),
|
||||
const Icon(Icons.keyboard_arrow_right),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: height,
|
||||
child: TextButton(
|
||||
onPressed: controller.sendAgainAction,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(L10n.of(context).tryToSendAgain),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(Icons.send_outlined, size: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
]
|
||||
: <Widget>[
|
||||
const SizedBox(width: 4),
|
||||
AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
width: controller.sendController.text.isNotEmpty ? 0 : height,
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: PopupMenuButton<String>(
|
||||
useRootNavigator: true,
|
||||
icon: const Icon(Icons.add_circle_outline),
|
||||
iconColor: theme.colorScheme.onPrimaryContainer,
|
||||
onSelected: controller.onAddPopupMenuButtonSelected,
|
||||
itemBuilder: (BuildContext context) =>
|
||||
<PopupMenuEntry<String>>[
|
||||
if (PlatformInfos.isMobile)
|
||||
PopupMenuItem<String>(
|
||||
value: 'location',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.gps_fixed_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).shareLocation),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'image',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.photo_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).sendImage),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'video',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.video_camera_back_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).sendVideo),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'file',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.attachment_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).sendFile),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'video',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.video_camera_back_outlined),
|
||||
if (PlatformInfos.isMobile)
|
||||
AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
width: controller.sendController.text.isNotEmpty ? 0 : height,
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: PopupMenuButton(
|
||||
useRootNavigator: true,
|
||||
icon: const Icon(Icons.camera_alt_outlined),
|
||||
onSelected: controller.onAddPopupMenuButtonSelected,
|
||||
iconColor: theme.colorScheme.onPrimaryContainer,
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem<String>(
|
||||
value: 'camera-video',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.videocam_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).recordAVideo),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'camera',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.camera_alt_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).takeAPhoto),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
title: Text(L10n.of(context).sendVideo),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
Container(
|
||||
height: height,
|
||||
width: height,
|
||||
alignment: Alignment.center,
|
||||
child: IconButton(
|
||||
tooltip: L10n.of(context).emojis,
|
||||
color: theme.colorScheme.onPrimaryContainer,
|
||||
icon: PageTransitionSwitcher(
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> primaryAnimation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
return SharedAxisTransition(
|
||||
animation: primaryAnimation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
transitionType: SharedAxisTransitionType.scaled,
|
||||
fillColor: Colors.transparent,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Icon(
|
||||
controller.showEmojiPicker
|
||||
? Icons.keyboard
|
||||
: Icons.add_reaction_outlined,
|
||||
key: ValueKey(controller.showEmojiPicker),
|
||||
),
|
||||
),
|
||||
onPressed: controller.emojiPickerAction,
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'file',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.attachment_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).sendFile),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
if (Matrix.of(context).isMultiAccount &&
|
||||
Matrix.of(context).hasComplexBundles &&
|
||||
Matrix.of(context).currentBundle!.length > 1)
|
||||
Container(
|
||||
width: height,
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
child: _ChatAccountPicker(controller),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 0.0),
|
||||
child: InputBar(
|
||||
room: controller.room,
|
||||
minLines: 1,
|
||||
maxLines: 8,
|
||||
autofocus: !PlatformInfos.isMobile,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textInputAction:
|
||||
AppConfig.sendOnEnter == true && PlatformInfos.isMobile
|
||||
? TextInputAction.send
|
||||
: null,
|
||||
// #Pangea
|
||||
// onSubmitted: controller.onInputBarSubmitted,
|
||||
onSubmitted: (_) =>
|
||||
controller.onInputBarSubmitted(_, context),
|
||||
// Pangea#
|
||||
onSubmitImage: controller.sendImageFromClipBoard,
|
||||
focusNode: controller.inputFocus,
|
||||
controller: controller.sendController,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 6.0,
|
||||
right: 6.0,
|
||||
bottom: 6.0,
|
||||
top: 3.0,
|
||||
),
|
||||
hintText: L10n.of(context).writeAMessage,
|
||||
hintMaxLines: 1,
|
||||
border: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
filled: false,
|
||||
),
|
||||
onChanged: controller.onInputBarChanged,
|
||||
// #Pangea
|
||||
hintText: "",
|
||||
// Pangea#
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: height,
|
||||
width: height,
|
||||
alignment: Alignment.center,
|
||||
child: PlatformInfos.platformCanRecord &&
|
||||
controller.sendController.text.isEmpty
|
||||
? FloatingActionButton.small(
|
||||
tooltip: L10n.of(context).voiceMessage,
|
||||
onPressed: controller.voiceMessageAction,
|
||||
elevation: 0,
|
||||
heroTag: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(height),
|
||||
),
|
||||
backgroundColor: theme.bubbleColor,
|
||||
foregroundColor: theme.onBubbleColor,
|
||||
child: const Icon(Icons.mic_none_outlined),
|
||||
)
|
||||
: FloatingActionButton.small(
|
||||
tooltip: L10n.of(context).send,
|
||||
// #Pangea
|
||||
// onPressed: controller.send,
|
||||
onPressed: () => controller.send(
|
||||
message: controller.sendController.text,
|
||||
),
|
||||
// Pangea#
|
||||
elevation: 0,
|
||||
heroTag: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(height),
|
||||
),
|
||||
backgroundColor: theme.bubbleColor,
|
||||
foregroundColor: theme.onBubbleColor,
|
||||
child: const Icon(Icons.send_outlined),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (PlatformInfos.isMobile)
|
||||
AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
width: controller.sendController.text.isNotEmpty ? 0 : height,
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: PopupMenuButton(
|
||||
enabled: !controller.selectMode,
|
||||
useRootNavigator: true,
|
||||
icon: const Icon(Icons.camera_alt_outlined),
|
||||
onSelected: controller.onAddPopupMenuButtonSelected,
|
||||
iconColor: theme.colorScheme.onPrimaryContainer,
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem<String>(
|
||||
value: 'camera-video',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.videocam_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).recordAVideo),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'camera',
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.colorScheme.onPrimaryContainer,
|
||||
foregroundColor: theme.colorScheme.primaryContainer,
|
||||
child: const Icon(Icons.camera_alt_outlined),
|
||||
),
|
||||
title: Text(L10n.of(context).takeAPhoto),
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: height,
|
||||
width: height,
|
||||
alignment: Alignment.center,
|
||||
child: IconButton(
|
||||
tooltip: L10n.of(context).emojis,
|
||||
color: theme.colorScheme.onPrimaryContainer,
|
||||
icon: PageTransitionSwitcher(
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> primaryAnimation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
return SharedAxisTransition(
|
||||
animation: primaryAnimation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
transitionType: SharedAxisTransitionType.scaled,
|
||||
fillColor: Colors.transparent,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Icon(
|
||||
controller.showEmojiPicker
|
||||
? Icons.keyboard
|
||||
: Icons.add_reaction_outlined,
|
||||
key: ValueKey(controller.showEmojiPicker),
|
||||
),
|
||||
),
|
||||
onPressed:
|
||||
controller.selectMode ? null : controller.emojiPickerAction,
|
||||
),
|
||||
),
|
||||
if (Matrix.of(context).isMultiAccount &&
|
||||
Matrix.of(context).hasComplexBundles &&
|
||||
Matrix.of(context).currentBundle!.length > 1)
|
||||
Container(
|
||||
width: height,
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
child: _ChatAccountPicker(controller),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 0.0),
|
||||
child: InputBar(
|
||||
room: controller.room,
|
||||
minLines: 1,
|
||||
readOnly: controller.selectMode,
|
||||
maxLines: 8,
|
||||
autofocus: !PlatformInfos.isMobile,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textInputAction:
|
||||
AppConfig.sendOnEnter == true && PlatformInfos.isMobile
|
||||
? TextInputAction.send
|
||||
: null,
|
||||
// #Pangea
|
||||
// onSubmitted: controller.onInputBarSubmitted,
|
||||
onSubmitted: (c) => controller.onInputBarSubmitted(c, context),
|
||||
hintText: "",
|
||||
// Pangea#
|
||||
onSubmitImage: controller.sendImageFromClipBoard,
|
||||
focusNode: controller.inputFocus,
|
||||
controller: controller.sendController,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 6.0,
|
||||
right: 6.0,
|
||||
bottom: 6.0,
|
||||
top: 3.0,
|
||||
),
|
||||
hintText: L10n.of(context).writeAMessage,
|
||||
hintMaxLines: 1,
|
||||
border: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
filled: false,
|
||||
),
|
||||
onChanged: controller.onInputBarChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
Opacity(
|
||||
opacity: controller.selectMode ? 0.66 : 1,
|
||||
child: Container(
|
||||
height: height,
|
||||
width: height,
|
||||
alignment: Alignment.center,
|
||||
child: PlatformInfos.platformCanRecord &&
|
||||
controller.sendController.text.isEmpty
|
||||
? FloatingActionButton.small(
|
||||
tooltip: L10n.of(context).voiceMessage,
|
||||
onPressed: controller.selectMode
|
||||
? null
|
||||
: controller.voiceMessageAction,
|
||||
elevation: 0,
|
||||
heroTag: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(height),
|
||||
),
|
||||
backgroundColor: theme.bubbleColor,
|
||||
foregroundColor: theme.onBubbleColor,
|
||||
child: const Icon(Icons.mic_none_outlined),
|
||||
)
|
||||
: FloatingActionButton.small(
|
||||
tooltip: L10n.of(context).send,
|
||||
// #Pangea
|
||||
// onPressed: controller.selectMode ? null : controller.send,
|
||||
onPressed: () {},
|
||||
// Pangea#
|
||||
elevation: 0,
|
||||
heroTag: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(height),
|
||||
),
|
||||
backgroundColor: theme.bubbleColor,
|
||||
foregroundColor: theme.onBubbleColor,
|
||||
child: const Icon(Icons.send_outlined),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@ class ChatView extends StatelessWidget {
|
|||
List<Widget> _appBarActions(BuildContext context) {
|
||||
if (controller.selectMode) {
|
||||
return [
|
||||
if (controller.canEditSelectedEvents)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit_outlined),
|
||||
tooltip: L10n.of(context).edit,
|
||||
onPressed: controller.editSelectedEventAction,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.copy_outlined),
|
||||
tooltip: L10n.of(context).copy,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:ui' as ui;
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:swipe_to_action/swipe_to_action.dart';
|
||||
|
||||
|
|
@ -246,6 +247,12 @@ class Message extends StatelessWidget {
|
|||
final showReceiptsRow =
|
||||
event.hasAggregatedEvents(timeline, RelationshipTypes.reaction);
|
||||
|
||||
// #Pangea
|
||||
// final showReactionPicker =
|
||||
// singleSelected && event.room.canSendDefaultMessages;
|
||||
const showReactionPicker = false;
|
||||
// Pangea#
|
||||
|
||||
return Center(
|
||||
child: Swipeable(
|
||||
key: ValueKey(event.eventId),
|
||||
|
|
@ -328,6 +335,7 @@ class Message extends StatelessWidget {
|
|||
child: animateIn
|
||||
? const SizedBox(height: 0, width: double.infinity)
|
||||
: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned(
|
||||
top: 0,
|
||||
|
|
@ -361,7 +369,7 @@ class Message extends StatelessWidget {
|
|||
mainAxisAlignment: rowMainAxisAlignment,
|
||||
children: [
|
||||
// #Pangea
|
||||
// if (longPressSelect)
|
||||
// if (longPressSelect && !event.redacted)
|
||||
// SizedBox(
|
||||
// height: 32,
|
||||
// width: Avatar.defaultSize,
|
||||
|
|
@ -486,8 +494,10 @@ class Message extends StatelessWidget {
|
|||
),
|
||||
Container(
|
||||
alignment: alignment,
|
||||
padding:
|
||||
const EdgeInsets.only(left: 8),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 8,
|
||||
bottom: showReactionPicker ? 40 : 0,
|
||||
),
|
||||
child: GestureDetector(
|
||||
// #Pangea
|
||||
onTap: () =>
|
||||
|
|
@ -759,163 +769,209 @@ class Message extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
left:
|
||||
ownMessage ? null : Avatar.defaultSize + 8,
|
||||
right: ownMessage ? 0 : null,
|
||||
bottom: 0,
|
||||
child: AnimatedSize(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: showReactionPicker
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 8.0,
|
||||
bottom: 4.0,
|
||||
),
|
||||
child: Material(
|
||||
elevation: 4,
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppConfig.borderRadius,
|
||||
),
|
||||
shadowColor: theme
|
||||
.colorScheme.surface
|
||||
.withAlpha(128),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
...AppConfig.defaultReactions
|
||||
.map(
|
||||
(emoji) => IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Center(
|
||||
child: Opacity(
|
||||
opacity: sentReactions
|
||||
.contains(emoji)
|
||||
? 0.33
|
||||
: 1,
|
||||
child: Text(
|
||||
emoji,
|
||||
style:
|
||||
const TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
textAlign:
|
||||
TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: sentReactions
|
||||
.contains(emoji)
|
||||
? null
|
||||
: () {
|
||||
onSelect(event);
|
||||
event.room
|
||||
.sendReaction(
|
||||
event.eventId,
|
||||
emoji,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.add_reaction_outlined,
|
||||
),
|
||||
tooltip: L10n.of(context)
|
||||
.customReaction,
|
||||
onPressed: () async {
|
||||
final emoji =
|
||||
await showDialog<
|
||||
String>(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
AlertDialog(
|
||||
title: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
spacing: 4,
|
||||
children: [
|
||||
CloseButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(
|
||||
null,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
L10n.of(context)
|
||||
.customReaction,
|
||||
),
|
||||
],
|
||||
),
|
||||
titlePadding:
|
||||
const EdgeInsets
|
||||
.all(8),
|
||||
contentPadding:
|
||||
const EdgeInsets
|
||||
.all(0),
|
||||
clipBehavior:
|
||||
Clip.hardEdge,
|
||||
content: SizedBox(
|
||||
width: 350,
|
||||
height: 350,
|
||||
child: EmojiPicker(
|
||||
onEmojiSelected: (
|
||||
_,
|
||||
emoji,
|
||||
) =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(
|
||||
emoji.emoji,
|
||||
),
|
||||
config: Config(
|
||||
emojiViewConfig:
|
||||
const EmojiViewConfig(
|
||||
backgroundColor:
|
||||
Colors
|
||||
.transparent,
|
||||
),
|
||||
bottomActionBarConfig:
|
||||
const BottomActionBarConfig(
|
||||
enabled: false,
|
||||
),
|
||||
categoryViewConfig:
|
||||
CategoryViewConfig(
|
||||
initCategory:
|
||||
Category
|
||||
.SMILEYS,
|
||||
backspaceColor: theme
|
||||
.colorScheme
|
||||
.primary,
|
||||
iconColor: theme
|
||||
.colorScheme
|
||||
.primary
|
||||
.withAlpha(
|
||||
128,
|
||||
),
|
||||
iconColorSelected:
|
||||
theme
|
||||
.colorScheme
|
||||
.primary,
|
||||
indicatorColor: theme
|
||||
.colorScheme
|
||||
.primary,
|
||||
backgroundColor:
|
||||
theme
|
||||
.colorScheme
|
||||
.surface,
|
||||
),
|
||||
skinToneConfig:
|
||||
SkinToneConfig(
|
||||
dialogBackgroundColor:
|
||||
Color.lerp(
|
||||
theme
|
||||
.colorScheme
|
||||
.surface,
|
||||
theme
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
0.75,
|
||||
)!,
|
||||
indicatorColor: theme
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (emoji == null) return;
|
||||
if (sentReactions.contains(
|
||||
emoji,
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
onSelect(event);
|
||||
|
||||
await event.room
|
||||
.sendReaction(
|
||||
event.eventId,
|
||||
emoji,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// #Pangea
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.only(left: Avatar.defaultSize + 8.0),
|
||||
// child: AnimatedSize(
|
||||
// duration: FluffyThemes.animationDuration,
|
||||
// curve: FluffyThemes.animationCurve,
|
||||
// alignment: Alignment.bottomCenter,
|
||||
// child: singleSelected && event.room.canSendDefaultMessages
|
||||
// ? Padding(
|
||||
// padding: const EdgeInsets.only(bottom: 4.0),
|
||||
// child: Material(
|
||||
// elevation: 4,
|
||||
// borderRadius:
|
||||
// BorderRadius.circular(AppConfig.borderRadius),
|
||||
// shadowColor: theme.appBarTheme.shadowColor,
|
||||
// child: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.reply_outlined),
|
||||
// tooltip: L10n.of(context).reply,
|
||||
// onPressed: onSwipe,
|
||||
// ),
|
||||
// if (ownMessage)
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.edit_outlined),
|
||||
// tooltip: L10n.of(context).edit,
|
||||
// onPressed: onEdit,
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.add_reaction_outlined),
|
||||
// tooltip: L10n.of(context).customReaction,
|
||||
// onPressed: () async {
|
||||
// final emoji = await showDialog<String>(
|
||||
// context: context,
|
||||
// builder: (context) => AlertDialog(
|
||||
// title: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// spacing: 4,
|
||||
// children: [
|
||||
// CloseButton(
|
||||
// onPressed: () =>
|
||||
// Navigator.of(context)
|
||||
// .pop(null),
|
||||
// ),
|
||||
// Text(
|
||||
// L10n.of(context).customReaction,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// titlePadding: const EdgeInsets.all(8),
|
||||
// contentPadding: const EdgeInsets.all(0),
|
||||
// clipBehavior: Clip.hardEdge,
|
||||
// content: SizedBox(
|
||||
// width: 350,
|
||||
// height: 350,
|
||||
// child: EmojiPicker(
|
||||
// onEmojiSelected: (_, emoji) =>
|
||||
// Navigator.of(context)
|
||||
// .pop(emoji.emoji),
|
||||
// config: Config(
|
||||
// emojiViewConfig:
|
||||
// const EmojiViewConfig(
|
||||
// backgroundColor:
|
||||
// Colors.transparent,
|
||||
// ),
|
||||
// bottomActionBarConfig:
|
||||
// const BottomActionBarConfig(
|
||||
// enabled: false,
|
||||
// ),
|
||||
// categoryViewConfig:
|
||||
// CategoryViewConfig(
|
||||
// initCategory: Category.SMILEYS,
|
||||
// backspaceColor:
|
||||
// theme.colorScheme.primary,
|
||||
// iconColor: theme
|
||||
// .colorScheme.primary
|
||||
// .withAlpha(128),
|
||||
// iconColorSelected:
|
||||
// theme.colorScheme.primary,
|
||||
// indicatorColor:
|
||||
// theme.colorScheme.primary,
|
||||
// backgroundColor:
|
||||
// theme.colorScheme.surface,
|
||||
// ),
|
||||
// skinToneConfig: SkinToneConfig(
|
||||
// dialogBackgroundColor:
|
||||
// Color.lerp(
|
||||
// theme.colorScheme.surface,
|
||||
// theme.colorScheme
|
||||
// .primaryContainer,
|
||||
// 0.75,
|
||||
// )!,
|
||||
// indicatorColor:
|
||||
// theme.colorScheme.onSurface,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// if (emoji == null) return;
|
||||
// if (sentReactions.contains(emoji)) return;
|
||||
|
||||
// await event.room.sendReaction(
|
||||
// event.eventId,
|
||||
// emoji,
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ...AppConfig.defaultReactions.map(
|
||||
// (emoji) => IconButton(
|
||||
// padding: EdgeInsets.zero,
|
||||
// icon: Center(
|
||||
// child: Opacity(
|
||||
// opacity: sentReactions.contains(emoji)
|
||||
// ? 0.33
|
||||
// : 1,
|
||||
// child: Text(
|
||||
// emoji,
|
||||
// style: const TextStyle(fontSize: 20),
|
||||
// textAlign: TextAlign.center,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// onPressed: sentReactions.contains(emoji)
|
||||
// ? null
|
||||
// : () {
|
||||
// onSelect(event);
|
||||
// event.room.sendReaction(
|
||||
// event.eventId,
|
||||
// emoji,
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// : const SizedBox.shrink(),
|
||||
// ),
|
||||
// ),
|
||||
// Pangea#
|
||||
AnimatedSize(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
// #Pangea
|
||||
child: !showReceiptsRow &&
|
||||
!(pangeaMessageEvent?.showMessageButtons ?? false)
|
||||
// child: !showReceiptsRow
|
||||
// Pangea#
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: !showReceiptsRow
|
||||
? const SizedBox.shrink()
|
||||
: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ class _MxcImageState extends State<MxcImage> {
|
|||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.uri != widget.uri || oldWidget.cacheKey != widget.cacheKey) {
|
||||
_imageData = null;
|
||||
WidgetsBinding.instance.addPostFrameCallback(_tryLoad);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _tryLoad());
|
||||
}
|
||||
}
|
||||
// Pangea#
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue