Refactoring modal alignment logic

This commit is contained in:
Leandro Borges Ferreira
2023-02-26 19:02:46 +01:00
parent 4818d094af
commit 009860d96a
4 changed files with 24 additions and 118 deletions
@@ -98,15 +98,11 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
Widget _showMessageOptionsModal() { Widget _showMessageOptionsModal() {
final mediaQueryData = MediaQuery.of(context); final mediaQueryData = MediaQuery.of(context);
final size = mediaQueryData.size;
final user = StreamChat.of(context).currentUser; final user = StreamChat.of(context).currentUser;
final orientation = mediaQueryData.orientation; final orientation = mediaQueryData.orientation;
final roughMaxSize = size.width * 2 / 3;
final fontSize = widget.messageTheme.messageTextStyle?.fontSize; final fontSize = widget.messageTheme.messageTextStyle?.fontSize;
final streamChatThemeData = StreamChatTheme.of(context); final streamChatThemeData = StreamChatTheme.of(context);
final numberOfReactions =
StreamChatConfiguration.of(context).reactionIcons.length;
final channel = StreamChannel.of(context).channel; final channel = StreamChannel.of(context).channel;
@@ -125,13 +121,11 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
builder: (context, constraints) { builder: (context, constraints) {
return Align( return Align(
alignment: Alignment( alignment: Alignment(
calculateReactionsHorizontalAlignmentValue( calculateReactionsHorizontalAlignment(
user, user,
widget.message, widget.message,
constraints, constraints,
roughMaxSize,
fontSize, fontSize,
numberOfReactions,
orientation, orientation,
), ),
0, 0,
@@ -40,17 +40,13 @@ class StreamMessageReactionsModal extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final user = StreamChat.of(context).currentUser; final user = StreamChat.of(context).currentUser;
final _userPermissions = StreamChannel.of(context).channel.ownCapabilities; final _userPermissions = StreamChannel.of(context).channel.ownCapabilities;
final orientation = MediaQuery.of(context).orientation; final orientation = MediaQuery.of(context).orientation;
final hasReactionPermission = final hasReactionPermission =
_userPermissions.contains(PermissionType.sendReaction); _userPermissions.contains(PermissionType.sendReaction);
final roughMaxSize = size.width * 2 / 3;
final fontSize = messageTheme.messageTextStyle?.fontSize; final fontSize = messageTheme.messageTextStyle?.fontSize;
final numberOfReactions =
StreamChatConfiguration.of(context).reactionIcons.length;
final child = Center( final child = Center(
child: SingleChildScrollView( child: SingleChildScrollView(
@@ -66,13 +62,11 @@ class StreamMessageReactionsModal extends StatelessWidget {
builder: (context, constraints) { builder: (context, constraints) {
return Align( return Align(
alignment: Alignment( alignment: Alignment(
calculateReactionsHorizontalAlignmentValue( calculateReactionsHorizontalAlignment(
user, user,
message, message,
constraints, constraints,
roughMaxSize,
fontSize, fontSize,
numberOfReactions,
orientation, orientation,
), ),
0, 0,
@@ -2,129 +2,47 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// This method calculates the align that the modal of reactions should have. /// This method calculates the align that the modal of reactions should have.
/// THis is an approximation based on the size of the message and the /// This is an approximation based on the size of the message and the
/// available space in the screen. /// available space in the screen.
double calculateReactionsHorizontalAlignmentValue( double calculateReactionsHorizontalAlignment(
User? user, User? user,
Message message, Message message,
BoxConstraints constraints, BoxConstraints constraints,
double maxSize,
double? fontSize, double? fontSize,
int reactionsCount,
Orientation orientation, Orientation orientation,
) { ) {
final shiftFactor = reactionsCount < 5 ? (5 - reactionsCount) * 0.1 : 0.0;
final maxWidth = constraints.maxWidth; final maxWidth = constraints.maxWidth;
final maxHeight = constraints.maxHeight;
final roughSentenceSize = message.roughMessageSize(fontSize); final roughSentenceSize = message.roughMessageSize(fontSize);
print('roughSentenceSize: $roughSentenceSize');
print('maxSize: $maxSize');
final hasAttachments = message.attachments.isNotEmpty; final hasAttachments = message.attachments.isNotEmpty;
final isReply = message.quotedMessageId != null; final isReply = message.quotedMessageId != null;
final isAttachment = hasAttachments && !isReply; final isAttachment = hasAttachments && !isReply;
final divFactor = isAttachment
? 1
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / maxSize));
if (orientation == Orientation.portrait) { // divFactor is the percentage of the available space that the message takes.
return _portraitAlign( // When the divFactor is bigger than 0.5 that means that the messages is
user, // bigger than 50% of the available space and the modal should have an offset
message, // in the direction that the message grows. When the divFactor is smaller
maxWidth, // than 0.5 then the offset should be to he side opposite of the message
maxHeight, // growth.
shiftFactor, // In resume, when divFactor > 0.5 then result > 0, when divFactor < 0.5
divFactor, // then result < 0.
isAttachment, var divFactor = 0.5;
);
} else {
return _landScapeAlign(
user,
message,
maxWidth,
maxHeight,
shiftFactor,
divFactor,
isAttachment,
);
}
}
double _portraitAlign( // When in portrait, attachments normally take 75% of the screen, when in
User? user, // landscape, attachments normally take 50% of the screen.
Message message,
double maxWidth,
double maxHeight,
double shiftFactor,
num divFactor,
bool isAttachment,
) {
var result = 0.0;
// This is an empiric value. This number tries to approximate all the
// offset necessary for the position of reaction look the best way
// possible.
const constant = 1300;
print('is attachment: $isAttachment');
print('shiftFactor: $shiftFactor');
print('divFactor: $divFactor');
if (user?.id == message.user?.id) {
if (divFactor >= 1.0 || isAttachment) {
result = shiftFactor - maxWidth / constant;
} else {
// Small messages, it is simpler to align then.
result = 1.2 - divFactor;
}
} else {
if (divFactor >= 1.0 || isAttachment) {
result = shiftFactor + maxWidth / constant;
} else {
result = -(1.2 - divFactor);
}
}
return _capResult(result);
}
double _landScapeAlign(
User? user,
Message message,
double maxWidth,
double maxHeight,
double shiftFactor,
num divFactor,
bool isAttachment,
) {
var result = 0.0;
print('is attachment: $isAttachment');
print('shiftFactor: $shiftFactor');
print('divFactor: $divFactor');
/*
This is an empiric value. This number tries to approximate all the
offset necessary for the position of reaction look the best way
possible.
*/
if (isAttachment) { if (isAttachment) {
result = 0; if (orientation == Orientation.portrait) {
} else if (user?.id == message.user?.id) { divFactor = 0.75;
if (divFactor >= 1.3) {
result = 0;
} else { } else {
// Small messages, it is simpler to align then. divFactor = 0.5;
result = 1 - divFactor * 0.6;
} }
} else { } else {
if (divFactor >= 1.3) { divFactor = roughSentenceSize == 0 ? 0.5 : (roughSentenceSize / maxWidth);
result = 0;
} else {
result = -(1 - divFactor * 0.6);
}
} }
final signal = user?.id == message.user?.id ? 1 : -1;
final result = signal * (1 - divFactor * 2.0);
return _capResult(result); return _capResult(result);
} }
@@ -384,9 +384,9 @@ extension MessageX on Message {
// Quoted message have a smaller font, so it is necessary to reduce the // Quoted message have a smaller font, so it is necessary to reduce the
// size of the multiplier to count for the smaller font. // size of the multiplier to count for the smaller font.
var multiplier = 1.2; var multiplier = 0.55;
if (quotedMessage != null) { if (quotedMessage != null) {
multiplier = 1; multiplier = 0.45;
} }
return messageTextLength * (fontSize ?? 1) * multiplier; return messageTextLength * (fontSize ?? 1) * multiplier;