Fix Up File Sharing Overlay
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Sarah Jamie Lewis 2024-02-08 15:43:10 -08:00
parent 659c7fe75e
commit cb079c2fd3
4 changed files with 178 additions and 213 deletions

View File

@ -1,9 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cwtch/config.dart';
import 'package:cwtch/cwtch/cwtch.dart';
import 'package:cwtch/main.dart'; import 'package:cwtch/main.dart';
import 'package:cwtch/models/appstate.dart';
import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/contact.dart';
import 'package:cwtch/models/profile.dart'; import 'package:cwtch/models/profile.dart';
import 'package:cwtch/settings.dart'; import 'package:cwtch/settings.dart';

View File

@ -146,133 +146,129 @@ class FileBubbleState extends State<FileBubble> {
); );
} }
return LayoutBuilder(builder: (bcontext, constraints) { var wdgSender = Visibility(
var wdgSender = Visibility( visible: widget.interactive,
visible: widget.interactive, child: Container(
child: Container( height: 14 * Provider.of<Settings>(context).fontScaling, clipBehavior: Clip.hardEdge, decoration: BoxDecoration(), child: compileSenderWidget(context, null, fromMe, senderDisplayStr)));
height: 14 * Provider.of<Settings>(context).fontScaling, var isPreview = false;
clipBehavior: Clip.hardEdge, var wdgMessage = !showFileSharing
decoration: BoxDecoration(), ? Text(AppLocalizations.of(context)!.messageEnableFileSharing, style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle))
child: compileSenderWidget(context, constraints, fromMe, senderDisplayStr))); : fromMe
var isPreview = false; ? senderFileChrome(AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash)
var wdgMessage = !showFileSharing : (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize,
? Text(AppLocalizations.of(context)!.messageEnableFileSharing, style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)) Provider.of<ProfileInfoState>(context).downloadSpeed(widget.fileKey())));
: fromMe Widget wdgDecorations;
? senderFileChrome(AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash, widget.fileSize)
: (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize,
Provider.of<ProfileInfoState>(context).downloadSpeed(widget.fileKey())));
Widget wdgDecorations;
if (!showFileSharing) { if (!showFileSharing) {
wdgDecorations = Text('\u202F'); wdgDecorations = Text('\u202F');
} else if (downloadComplete && path != null) { } else if (fromMe) {
// in this case, whatever marked download.complete would have also set the path wdgDecorations = Text('\u202F');
if (myFile != null && Provider.of<Settings>(context).shouldPreview(path)) { } else if (downloadComplete && path != null) {
isPreview = true; // in this case, whatever marked download.complete would have also set the path
wdgDecorations = Center( if (myFile != null && Provider.of<Settings>(context).shouldPreview(path)) {
widthFactor: 1.0, isPreview = true;
child: MouseRegion( wdgDecorations = Center(
cursor: SystemMouseCursors.click, widthFactor: 1.0,
child: GestureDetector( child: MouseRegion(
child: Padding(padding: EdgeInsets.all(1.0), child: getPreview(context)), cursor: SystemMouseCursors.click,
onTap: () { child: GestureDetector(
pop(bcontext, myFile!, widget.nameSuggestion); child: Padding(padding: EdgeInsets.all(1.0), child: getPreview(context)),
}, onTap: () {
))); pop(context, myFile!, widget.nameSuggestion);
} else { },
wdgDecorations = Visibility( )));
visible: widget.interactive, child: Text(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle))); } else {
} wdgDecorations = Visibility(
} else if (downloadActive) { visible: widget.interactive, child: SelectableText(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)));
if (!downloadGotManifest) { }
wdgDecorations = Visibility( } else if (downloadActive) {
visible: widget.interactive, child: Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle))); if (!downloadGotManifest) {
} else { wdgDecorations = Visibility(
wdgDecorations = Visibility( visible: widget.interactive, child: SelectableText(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)));
visible: widget.interactive, } else {
child: LinearProgressIndicator(
value: Provider.of<ProfileInfoState>(context).downloadProgress(widget.fileKey()),
color: Provider.of<Settings>(context).theme.defaultButtonActiveColor,
));
}
} else if (flagStarted) {
// in this case, the download was done in a previous application launch,
// so we probably have to request an info lookup
if (!downloadInterrupted) {
wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle));
// We should have already requested this...
} else {
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey()) ?? "";
wdgDecorations = Visibility(
visible: widget.interactive,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(AppLocalizations.of(context)!.fileInterrupted + ': ' + path + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)),
ElevatedButton(onPressed: _btnResume, child: Text(AppLocalizations.of(context)!.verfiyResumeButton, style: Provider.of<Settings>(context).scaleFonts(defaultTextButtonStyle)))
]));
}
} else if (!senderIsContact) {
wdgDecorations = Text(AppLocalizations.of(context)!.msgAddToAccept, style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle));
} else if (!widget.isAuto || Provider.of<MessageMetadata>(context).attributes["file-missing"] == "false") {
//Note: we need this second case to account for scenarios where a user deletes the downloaded file, we won't automatically
// fetch it again, so we need to offer the user the ability to restart..
wdgDecorations = Visibility( wdgDecorations = Visibility(
visible: widget.interactive, visible: widget.interactive,
child: Center( child: LinearProgressIndicator(
widthFactor: 1, value: Provider.of<ProfileInfoState>(context).downloadProgress(widget.fileKey()),
child: Wrap(children: [ color: Provider.of<Settings>(context).theme.defaultButtonActiveColor,
Padding( ));
padding: EdgeInsets.all(5),
child: ElevatedButton(
child: Text(AppLocalizations.of(context)!.downloadFileButton + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextButtonStyle)), onPressed: _btnAccept)),
])));
} else {
wdgDecorations = Container();
} }
} else if (flagStarted) {
// in this case, the download was done in a previous application launch,
// so we probably have to request an info lookup
if (!downloadInterrupted) {
wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle));
// We should have already requested this...
} else {
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey()) ?? "";
wdgDecorations = Visibility(
visible: widget.interactive,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(AppLocalizations.of(context)!.fileInterrupted + ': ' + path + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)),
ElevatedButton(onPressed: _btnResume, child: Text(AppLocalizations.of(context)!.verfiyResumeButton, style: Provider.of<Settings>(context).scaleFonts(defaultTextButtonStyle)))
]));
}
} else if (!senderIsContact) {
wdgDecorations = Text(AppLocalizations.of(context)!.msgAddToAccept, style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle));
} else if (!widget.isAuto || Provider.of<MessageMetadata>(context).attributes["file-missing"] == "false") {
//Note: we need this second case to account for scenarios where a user deletes the downloaded file, we won't automatically
// fetch it again, so we need to offer the user the ability to restart..
wdgDecorations = Visibility(
visible: widget.interactive,
child: Center(
widthFactor: 1,
child: Wrap(children: [
Padding(
padding: EdgeInsets.all(5),
child: ElevatedButton(
child: Text(AppLocalizations.of(context)!.downloadFileButton + '\u202F', style: Provider.of<Settings>(context).scaleFonts(defaultTextButtonStyle)), onPressed: _btnAccept)),
])));
} else {
wdgDecorations = Container();
}
return Container( return Container(
constraints: constraints, decoration: BoxDecoration(
decoration: BoxDecoration( color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor,
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor, border: Border.all(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor, width: 1),
border: Border.all(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only(
borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadius),
topLeft: Radius.circular(borderRadius), topRight: Radius.circular(borderRadius),
topRight: Radius.circular(borderRadius), bottomLeft: fromMe ? Radius.circular(borderRadius) : Radius.zero,
bottomLeft: fromMe ? Radius.circular(borderRadius) : Radius.zero, bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadius),
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadius),
),
), ),
child: Theme( ),
data: Theme.of(context).copyWith( child: Theme(
textSelectionTheme: TextSelectionThemeData( data: Theme.of(context).copyWith(
cursorColor: Provider.of<Settings>(context).theme.messageSelectionColor, textSelectionTheme: TextSelectionThemeData(
selectionColor: Provider.of<Settings>(context).theme.messageSelectionColor, cursorColor: Provider.of<Settings>(context).theme.messageSelectionColor,
selectionHandleColor: Provider.of<Settings>(context).theme.messageSelectionColor), selectionColor: Provider.of<Settings>(context).theme.messageSelectionColor,
selectionHandleColor: Provider.of<Settings>(context).theme.messageSelectionColor),
// Horrifying Hack: Flutter doesn't give us direct control over system menus but instead picks BG color from TextButtonThemeData ¯\_(ツ)_/¯ // Horrifying Hack: Flutter doesn't give us direct control over system menus but instead picks BG color from TextButtonThemeData ¯\_(ツ)_/¯
textButtonTheme: TextButtonThemeData( textButtonTheme: TextButtonThemeData(
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.menuBackgroundColor)), style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.menuBackgroundColor)),
),
), ),
child: Padding( ),
padding: EdgeInsets.all(9.0), child: Padding(
child: Column( padding: EdgeInsets.all(9.0),
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, child: Column(
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start, crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [ mainAxisSize: MainAxisSize.min,
wdgSender, children: [
isPreview wdgSender,
? Container( isPreview
width: 0, ? Container(
padding: EdgeInsets.zero, width: 0,
margin: EdgeInsets.zero, padding: EdgeInsets.zero,
) margin: EdgeInsets.zero,
: wdgMessage, )
wdgDecorations, : wdgMessage,
messageStatusWidget wdgDecorations,
]), messageStatusWidget
))); ]),
}); )));
} }
void _btnAccept() async { void _btnAccept() async {
@ -322,41 +318,27 @@ class FileBubbleState extends State<FileBubble> {
} }
// Construct an file chrome for the sender // Construct an file chrome for the sender
Widget senderFileChrome(String chrome, String fileName, String rootHash, int fileSize) { Widget senderFileChrome(String chrome, String fileName, String rootHash) {
var settings = Provider.of<Settings>(context); var settings = Provider.of<Settings>(context);
return ListTile( return ListTile(
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
title: Wrap(direction: Axis.horizontal, alignment: WrapAlignment.start, children: [ contentPadding: EdgeInsets.all(1.0),
SelectableText( title: SelectableText(
chrome + '\u202F', fileName + '\u202F',
style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of<Settings>(context).theme.messageFromMeTextColor)), style:
textAlign: TextAlign.left, settings.scaleFonts(defaultMessageTextStyle.copyWith(overflow: TextOverflow.ellipsis, fontWeight: FontWeight.bold, color: Provider.of<Settings>(context).theme.messageFromMeTextColor)),
maxLines: 2, textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine, textWidthBasis: TextWidthBasis.longestLine,
), maxLines: 2,
SelectableText( ),
fileName + '\u202F',
style:
settings.scaleFonts(defaultMessageTextStyle.copyWith(overflow: TextOverflow.ellipsis, fontWeight: FontWeight.bold, color: Provider.of<Settings>(context).theme.messageFromMeTextColor)),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.parent,
maxLines: 2,
),
SelectableText(
prettyBytes(fileSize) + '\u202F' + '\n',
style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of<Settings>(context).theme.messageFromMeTextColor)),
textAlign: TextAlign.left,
maxLines: 2,
)
]),
subtitle: SelectableText( subtitle: SelectableText(
'sha512: ' + rootHash + '\u202F', prettyBytes(widget.fileSize) + '\u202F' + '\n' + 'sha512: ' + rootHash + '\u202F',
style: settings.scaleFonts(defaultSmallTextStyle.copyWith(fontFamily: "RobotoMono", color: Provider.of<Settings>(context).theme.messageFromMeTextColor)), style: settings.scaleFonts(defaultSmallTextStyle.copyWith(fontFamily: "RobotoMono", color: Provider.of<Settings>(context).theme.messageFromMeTextColor)),
textAlign: TextAlign.left, textAlign: TextAlign.left,
maxLines: 4, maxLines: 4,
textWidthBasis: TextWidthBasis.parent, textWidthBasis: TextWidthBasis.longestLine,
), ),
leading: Icon(CwtchIcons.attached_file_3, size: 32, color: Provider.of<Settings>(context).theme.messageFromMeTextColor)); leading: FittedBox(child: Icon(CwtchIcons.attached_file_3, size: 32, color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)));
} }
// Construct an file chrome // Construct an file chrome
@ -364,46 +346,33 @@ class FileBubbleState extends State<FileBubble> {
var settings = Provider.of<Settings>(context); var settings = Provider.of<Settings>(context);
return ListTile( return ListTile(
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
title: Wrap(direction: Axis.horizontal, alignment: WrapAlignment.start, children: [ contentPadding: EdgeInsets.all(1.0),
SelectableText( title: SelectableText(
chrome + '\u202F', fileName + '\u202F',
style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)), style:
textAlign: TextAlign.left, settings.scaleFonts(defaultMessageTextStyle.copyWith(overflow: TextOverflow.ellipsis, fontWeight: FontWeight.bold, color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)),
maxLines: 2, textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine, textWidthBasis: TextWidthBasis.longestLine,
), maxLines: 2,
SelectableText( ),
fileName + '\u202F',
style: settings
.scaleFonts(defaultMessageTextStyle.copyWith(overflow: TextOverflow.ellipsis, fontWeight: FontWeight.bold, color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.parent,
maxLines: 2,
),
SelectableText(
AppLocalizations.of(context)!.labelFilesize + ': ' + prettyBytes(fileSize) + '\u202F' + '\n',
style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)),
textAlign: TextAlign.left,
maxLines: 2,
)
]),
subtitle: SelectableText( subtitle: SelectableText(
'sha512: ' + rootHash + '\u202F', prettyBytes(widget.fileSize) + '\u202F' + '\n' + 'sha512: ' + rootHash + '\u202F',
style: settings.scaleFonts(defaultSmallTextStyle.copyWith(fontFamily: "RobotoMono", color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)), style: settings.scaleFonts(defaultSmallTextStyle.copyWith(fontFamily: "RobotoMono", color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)),
textAlign: TextAlign.left, textAlign: TextAlign.left,
maxLines: 4, maxLines: 4,
textWidthBasis: TextWidthBasis.parent, textWidthBasis: TextWidthBasis.longestLine,
), ),
leading: Icon(CwtchIcons.attached_file_3, size: 32, color: Provider.of<Settings>(context).theme.messageFromOtherTextColor), leading: FittedBox(child: Icon(CwtchIcons.attached_file_3, size: 32, color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)),
trailing: Visibility( // Note: not using Visible here because we want to shrink this to nothing when not in use...
visible: speed != "0 B/s", trailing: speed == "0 B/s"
child: SelectableText( ? null
speed + '\u202F', : SelectableText(
style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)), speed + '\u202F',
textAlign: TextAlign.left, style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor)),
maxLines: 1, textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine, maxLines: 1,
)), textWidthBasis: TextWidthBasis.longestLine,
),
); );
} }

View File

@ -1,4 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -23,35 +24,33 @@ class _MessageBubbleDecoration extends State<MessageBubbleDecoration> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var prettyDate = prettyDateString(context, widget.messageDate.toLocal()); var prettyDate = prettyDateString(context, widget.messageDate.toLocal());
return Center( return FittedBox(
widthFactor: 1.0,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(prettyDate, Text(prettyDate,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( textWidthBasis: TextWidthBasis.longestLine,
fontSize: 9.0 * Provider.of<Settings>(context).fontScaling, style: TextStyle(
fontWeight: FontWeight.w200, fontSize: 9.0 * Provider.of<Settings>(context).fontScaling,
fontFamily: "Inter", fontWeight: FontWeight.w200,
color: widget.fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor), fontFamily: "Inter",
textAlign: widget.fromMe ? TextAlign.right : TextAlign.left), color: widget.fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor),
!widget.fromMe textAlign: widget.fromMe ? TextAlign.right : TextAlign.left),
? SizedBox(width: 1, height: 1) !widget.fromMe
: Padding( ? SizedBox(width: 1, height: 1)
padding: EdgeInsets.all(1.0), : Padding(
child: widget.ackd == true padding: EdgeInsets.all(1.0),
child: widget.ackd == true
? Tooltip(
message: AppLocalizations.of(context)!.acknowledgedLabel, child: Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor, size: 16))
: (widget.errored == true
? Tooltip( ? Tooltip(
message: AppLocalizations.of(context)!.acknowledgedLabel, message: AppLocalizations.of(context)!.couldNotSendMsgError, child: Icon(Icons.error_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor, size: 16))
child: Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor, size: 16)) : Tooltip(
: (widget.errored == true message: AppLocalizations.of(context)!.pendingLabel,
? Tooltip( child: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor, size: 16))))
message: AppLocalizations.of(context)!.couldNotSendMsgError, ],
child: Icon(Icons.error_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor, size: 16)) ));
: Tooltip(
message: AppLocalizations.of(context)!.pendingLabel,
child: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor, size: 16))))
],
));
} }
} }

View File

@ -63,7 +63,7 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
var isContact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle) != null; var isContact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle) != null;
var isGroup = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageMetadata>(context, listen: false).conversationIdentifier)!.isGroup; var isGroup = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageMetadata>(context, listen: false).conversationIdentifier)!.isGroup;
var isBlocked = isContact ? Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle)!.isBlocked : false; var isBlocked = isContact ? Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle)!.isBlocked : false;
var actualMessage = Flexible(flex: 1, fit: FlexFit.loose, child: widget.child); var actualMessage = Flexible(flex: Platform.isAndroid ? 10 : 7, fit: FlexFit.loose, child: widget.child);
_dragAffinity = fromMe ? Alignment.centerRight : Alignment.centerLeft; _dragAffinity = fromMe ? Alignment.centerRight : Alignment.centerLeft;
_dragAlignment = fromMe ? Alignment.centerRight : Alignment.centerLeft; _dragAlignment = fromMe ? Alignment.centerRight : Alignment.centerLeft;