Center toolbar overlay
This commit is contained in:
parent
aa20fd3b35
commit
668b9dd65f
3 changed files with 126 additions and 204 deletions
|
|
@ -26,6 +26,7 @@ class OverlayUtil {
|
|||
Alignment? targetAnchor,
|
||||
Alignment? followerAnchor,
|
||||
bool closePrevOverlay = true,
|
||||
bool targetScreen = false,
|
||||
}) {
|
||||
try {
|
||||
if (closePrevOverlay) {
|
||||
|
|
@ -47,14 +48,16 @@ class OverlayUtil {
|
|||
Positioned(
|
||||
width: width,
|
||||
height: height,
|
||||
child: CompositedTransformFollower(
|
||||
targetAnchor: targetAnchor ?? Alignment.topLeft,
|
||||
followerAnchor: followerAnchor ?? Alignment.topLeft,
|
||||
link: layerLinkAndKey.link,
|
||||
showWhenUnlinked: false,
|
||||
offset: offset ?? Offset.zero,
|
||||
child: child,
|
||||
),
|
||||
child: targetScreen
|
||||
? Center(child: child)
|
||||
: CompositedTransformFollower(
|
||||
targetAnchor: targetAnchor ?? Alignment.topLeft,
|
||||
followerAnchor: followerAnchor ?? Alignment.topLeft,
|
||||
link: layerLinkAndKey.link,
|
||||
showWhenUnlinked: false,
|
||||
offset: offset ?? Offset.zero,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import 'package:fluffychat/config/themes.dart';
|
|||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/enum/message_mode_enum.dart';
|
||||
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/utils/any_state_holder.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/utils/overlay.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/message_audio_card.dart';
|
||||
|
|
@ -20,7 +19,6 @@ import 'package:fluffychat/pangea/widgets/user_settings/p_language_dialog.dart';
|
|||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class ToolbarDisplayController {
|
||||
|
|
@ -61,73 +59,13 @@ class ToolbarDisplayController {
|
|||
void showToolbar(BuildContext context, {MessageMode? mode}) {
|
||||
// Close keyboard, if open
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
bool toolbarUp = true;
|
||||
if (highlighted) return;
|
||||
if (controller.selectMode) {
|
||||
controller.clearSelectedEvents();
|
||||
}
|
||||
if (!MatrixState.pangeaController.languageController.languagesSet) {
|
||||
pLanguageDialog(context, () {});
|
||||
return;
|
||||
}
|
||||
focusNode.requestFocus();
|
||||
|
||||
final LayerLinkAndKey layerLinkAndKey =
|
||||
MatrixState.pAnyState.layerLinkAndKey(targetId);
|
||||
final targetRenderBox =
|
||||
layerLinkAndKey.key.currentContext?.findRenderObject();
|
||||
if (targetRenderBox != null) {
|
||||
final Size transformTargetSize = (targetRenderBox as RenderBox).size;
|
||||
messageWidth = transformTargetSize.width;
|
||||
final Offset targetOffset = (targetRenderBox).localToGlobal(Offset.zero);
|
||||
|
||||
// If there is enough space above, procede as normal
|
||||
// Else if there is enough space below, show toolbar underneath
|
||||
if (targetOffset.dy < 320) {
|
||||
final spaceBeneath = MediaQuery.of(context).size.height -
|
||||
(targetOffset.dy + transformTargetSize.height);
|
||||
// If toolbar is open, opening toolbar beneath without scrolling can cause issues
|
||||
// if (spaceBeneath >= 320) {
|
||||
// toolbarUp = false;
|
||||
// }
|
||||
|
||||
// See if it's possible to scroll up to make space
|
||||
if (controller.scrollController.offset - targetOffset.dy + 320 >=
|
||||
controller.scrollController.position.minScrollExtent &&
|
||||
controller.scrollController.offset - targetOffset.dy + 320 <=
|
||||
controller.scrollController.position.maxScrollExtent) {
|
||||
controller.scrollController.animateTo(
|
||||
controller.scrollController.offset - targetOffset.dy + 320,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
);
|
||||
}
|
||||
|
||||
// See if it's possible to scroll down to make space
|
||||
else if (controller.scrollController.offset + spaceBeneath - 320 >=
|
||||
controller.scrollController.position.minScrollExtent &&
|
||||
controller.scrollController.offset + spaceBeneath - 320 <=
|
||||
controller.scrollController.position.maxScrollExtent) {
|
||||
controller.scrollController.animateTo(
|
||||
controller.scrollController.offset + spaceBeneath - 320,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
);
|
||||
toolbarUp = false;
|
||||
}
|
||||
|
||||
// If message is too big and can't scroll either way
|
||||
// Scroll up as much as possible, and show toolbar above
|
||||
else {
|
||||
controller.scrollController.animateTo(
|
||||
controller.scrollController.position.minScrollExtent,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Widget overlayMessage = OverlayMessage(
|
||||
pangeaMessageEvent.event,
|
||||
timeline: pangeaMessageEvent.timeline,
|
||||
|
|
@ -146,16 +84,18 @@ class ToolbarDisplayController {
|
|||
Widget overlayEntry;
|
||||
if (toolbar == null) return;
|
||||
try {
|
||||
overlayEntry = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: pangeaMessageEvent.ownMessage
|
||||
? CrossAxisAlignment.end
|
||||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
toolbarUp ? toolbar! : overlayMessage,
|
||||
const SizedBox(height: 6),
|
||||
toolbarUp ? overlayMessage : toolbar!,
|
||||
],
|
||||
overlayEntry = Container(
|
||||
constraints:
|
||||
BoxConstraints(maxHeight: MediaQuery.sizeOf(context).height * .72),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
toolbar!,
|
||||
const SizedBox(height: 6),
|
||||
overlayMessage,
|
||||
],
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
debugger(when: kDebugMode);
|
||||
|
|
@ -167,25 +107,16 @@ class ToolbarDisplayController {
|
|||
context: context,
|
||||
child: overlayEntry,
|
||||
transformTargetId: targetId,
|
||||
targetAnchor: pangeaMessageEvent.ownMessage
|
||||
? toolbarUp
|
||||
? Alignment.bottomRight
|
||||
: Alignment.topRight
|
||||
: toolbarUp
|
||||
? Alignment.bottomLeft
|
||||
: Alignment.topLeft,
|
||||
followerAnchor: pangeaMessageEvent.ownMessage
|
||||
? toolbarUp
|
||||
? Alignment.bottomRight
|
||||
: Alignment.topRight
|
||||
: toolbarUp
|
||||
? Alignment.bottomLeft
|
||||
: Alignment.topLeft,
|
||||
targetAnchor: Alignment.center,
|
||||
followerAnchor: Alignment.center,
|
||||
backgroundColor: const Color.fromRGBO(0, 0, 0, 1).withAlpha(100),
|
||||
closePrevOverlay:
|
||||
MatrixState.pangeaController.subscriptionController.isSubscribed,
|
||||
targetScreen: true,
|
||||
);
|
||||
|
||||
// controller.onSelectMessage(pangeaMessageEvent.event);
|
||||
|
||||
if (MatrixState.pAnyState.entries.isNotEmpty) {
|
||||
overlayId = MatrixState.pAnyState.entries.last.hashCode.toString();
|
||||
}
|
||||
|
|
@ -361,11 +292,6 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
|
||||
void spellCheck() {}
|
||||
|
||||
void showMore() {
|
||||
MatrixState.pAnyState.closeOverlay();
|
||||
widget.controller.onSelectMessage(widget.pangeaMessageEvent.event);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -454,40 +380,31 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: MessageMode.values.map((mode) {
|
||||
if ([
|
||||
MessageMode.definition,
|
||||
MessageMode.textToSpeech,
|
||||
MessageMode.translation,
|
||||
].contains(mode) &&
|
||||
widget.pangeaMessageEvent.isAudioMessage) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
if (mode == MessageMode.speechToText &&
|
||||
!widget.pangeaMessageEvent.isAudioMessage) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Tooltip(
|
||||
message: mode.tooltip(context),
|
||||
child: IconButton(
|
||||
icon: Icon(mode.icon),
|
||||
color: mode.iconColor(
|
||||
widget.pangeaMessageEvent,
|
||||
currentMode,
|
||||
context,
|
||||
),
|
||||
onPressed: () => updateMode(mode),
|
||||
),
|
||||
);
|
||||
}).toList() +
|
||||
[
|
||||
Tooltip(
|
||||
message: L10n.of(context)!.more,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.add_reaction_outlined),
|
||||
onPressed: showMore,
|
||||
),
|
||||
if ([
|
||||
MessageMode.definition,
|
||||
MessageMode.textToSpeech,
|
||||
MessageMode.translation,
|
||||
].contains(mode) &&
|
||||
widget.pangeaMessageEvent.isAudioMessage) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
if (mode == MessageMode.speechToText &&
|
||||
!widget.pangeaMessageEvent.isAudioMessage) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Tooltip(
|
||||
message: mode.tooltip(context),
|
||||
child: IconButton(
|
||||
icon: Icon(mode.icon),
|
||||
color: mode.iconColor(
|
||||
widget.pangeaMessageEvent,
|
||||
currentMode,
|
||||
context,
|
||||
),
|
||||
],
|
||||
onPressed: () => updateMode(mode),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -119,83 +119,85 @@ class OverlayMessage extends StatelessWidget {
|
|||
);
|
||||
|
||||
return Flexible(
|
||||
child: Material(
|
||||
color: noBubble ? Colors.transparent : color,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: borderRadius,
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppConfig.borderRadius,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Material(
|
||||
color: noBubble ? Colors.transparent : color,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: borderRadius,
|
||||
),
|
||||
padding: noBubble || noPadding
|
||||
? EdgeInsets.zero
|
||||
: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: width ?? FluffyThemes.columnWidth * 1.25,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: MessageContent(
|
||||
event.getDisplayEvent(timeline),
|
||||
textColor: textColor,
|
||||
borderRadius: borderRadius,
|
||||
selected: selected,
|
||||
pangeaMessageEvent: pangeaMessageEvent,
|
||||
immersionMode: immersionMode,
|
||||
toolbarController: toolbarController,
|
||||
isOverlay: true,
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppConfig.borderRadius,
|
||||
),
|
||||
if (event.hasAggregatedEvents(
|
||||
timeline,
|
||||
RelationshipTypes.edit,
|
||||
) ||
|
||||
(pangeaMessageEvent.showUseType))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 4.0,
|
||||
),
|
||||
padding: noBubble || noPadding
|
||||
? EdgeInsets.zero
|
||||
: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (pangeaMessageEvent.showUseType) ...[
|
||||
pangeaMessageEvent.msgUseType.iconView(
|
||||
context,
|
||||
textColor.withAlpha(164),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
if (event.hasAggregatedEvents(
|
||||
timeline,
|
||||
RelationshipTypes.edit,
|
||||
)) ...[
|
||||
Icon(
|
||||
Icons.edit_outlined,
|
||||
color: textColor.withAlpha(164),
|
||||
size: 14,
|
||||
),
|
||||
Text(
|
||||
' - ${event.getDisplayEvent(timeline).originServerTs.localizedTimeShort(context)}',
|
||||
style: TextStyle(
|
||||
color: textColor.withAlpha(164),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: width ?? FluffyThemes.columnWidth * 1.25,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: MessageContent(
|
||||
event.getDisplayEvent(timeline),
|
||||
textColor: textColor,
|
||||
borderRadius: borderRadius,
|
||||
selected: selected,
|
||||
pangeaMessageEvent: pangeaMessageEvent,
|
||||
immersionMode: immersionMode,
|
||||
toolbarController: toolbarController,
|
||||
isOverlay: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (event.hasAggregatedEvents(
|
||||
timeline,
|
||||
RelationshipTypes.edit,
|
||||
) ||
|
||||
(pangeaMessageEvent.showUseType))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 4.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (pangeaMessageEvent.showUseType) ...[
|
||||
pangeaMessageEvent.msgUseType.iconView(
|
||||
context,
|
||||
textColor.withAlpha(164),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
if (event.hasAggregatedEvents(
|
||||
timeline,
|
||||
RelationshipTypes.edit,
|
||||
)) ...[
|
||||
Icon(
|
||||
Icons.edit_outlined,
|
||||
color: textColor.withAlpha(164),
|
||||
size: 14,
|
||||
),
|
||||
Text(
|
||||
' - ${event.getDisplayEvent(timeline).originServerTs.localizedTimeShort(context)}',
|
||||
style: TextStyle(
|
||||
color: textColor.withAlpha(164),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue