2021-08-16 22:04:05 +00:00
|
|
|
import 'dart:io';
|
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
import 'package:cwtch/models/contact.dart';
|
2021-07-06 19:46:39 +00:00
|
|
|
import 'package:cwtch/models/message.dart';
|
2022-01-18 21:17:27 +00:00
|
|
|
import 'package:cwtch/third_party/linkify/flutter_linkify.dart';
|
2022-01-18 21:26:52 +00:00
|
|
|
import 'package:cwtch/models/profile.dart';
|
2021-06-24 23:10:45 +00:00
|
|
|
import 'package:cwtch/widgets/malformedbubble.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
2021-11-06 05:38:45 +00:00
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
2021-06-24 23:10:45 +00:00
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:intl/intl.dart';
|
2021-11-06 05:38:45 +00:00
|
|
|
import 'package:url_launcher/url_launcher.dart';
|
2021-06-24 23:10:45 +00:00
|
|
|
|
|
|
|
import '../settings.dart';
|
|
|
|
import 'messagebubbledecorations.dart';
|
|
|
|
|
|
|
|
class MessageBubble extends StatefulWidget {
|
2021-07-06 19:46:39 +00:00
|
|
|
final String content;
|
|
|
|
|
|
|
|
MessageBubble(this.content);
|
|
|
|
|
2021-06-24 23:10:45 +00:00
|
|
|
@override
|
|
|
|
MessageBubbleState createState() => MessageBubbleState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class MessageBubbleState extends State<MessageBubble> {
|
|
|
|
FocusNode _focus = FocusNode();
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2021-07-06 19:46:39 +00:00
|
|
|
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
|
2021-06-24 23:10:45 +00:00
|
|
|
var borderRadiousEh = 15.0;
|
2021-11-06 05:38:45 +00:00
|
|
|
var showClickableLinks = Provider.of<Settings>(context).isExperimentEnabled(ClickableLinksExperiment);
|
2021-06-24 23:10:45 +00:00
|
|
|
|
2021-07-06 19:46:39 +00:00
|
|
|
DateTime messageDate = Provider.of<MessageMetadata>(context).timestamp;
|
2021-06-24 23:10:45 +00:00
|
|
|
|
|
|
|
// If the sender is not us, then we want to give them a nickname...
|
|
|
|
var senderDisplayStr = "";
|
2021-07-06 19:46:39 +00:00
|
|
|
if (!fromMe) {
|
2021-11-18 23:44:54 +00:00
|
|
|
ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
|
2021-06-24 23:10:45 +00:00
|
|
|
if (contact != null) {
|
|
|
|
senderDisplayStr = contact.nickname;
|
|
|
|
} else {
|
2021-07-06 19:46:39 +00:00
|
|
|
senderDisplayStr = Provider.of<MessageMetadata>(context).senderHandle;
|
2021-06-24 23:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
var wdgSender = SelectableText(senderDisplayStr,
|
2021-12-10 04:22:55 +00:00
|
|
|
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor));
|
2021-06-24 23:10:45 +00:00
|
|
|
|
2021-11-06 05:38:45 +00:00
|
|
|
var wdgMessage;
|
|
|
|
|
2021-11-25 23:59:54 +00:00
|
|
|
if (!showClickableLinks) {
|
2021-11-06 05:38:45 +00:00
|
|
|
wdgMessage = SelectableText(
|
|
|
|
widget.content + '\u202F',
|
|
|
|
//key: Key(myKey),
|
|
|
|
focusNode: _focus,
|
|
|
|
style: TextStyle(
|
2021-12-10 04:22:55 +00:00
|
|
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor,
|
2021-11-06 05:38:45 +00:00
|
|
|
),
|
|
|
|
textAlign: TextAlign.left,
|
|
|
|
textWidthBasis: TextWidthBasis.longestLine,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
wdgMessage = SelectableLinkify(
|
|
|
|
text: widget.content + '\u202F',
|
|
|
|
// TODO: onOpen breaks the "selectable" functionality. Maybe something to do with gesture handler?
|
2022-01-18 22:32:45 +00:00
|
|
|
options: LinkifyOptions(looseUrl: true, defaultToHttps: true),
|
2021-11-06 17:53:42 +00:00
|
|
|
linkifiers: [UrlLinkifier()],
|
2021-11-06 05:38:45 +00:00
|
|
|
onOpen: (link) {
|
|
|
|
_modalOpenLink(context, link);
|
|
|
|
},
|
|
|
|
//key: Key(myKey),
|
|
|
|
focusNode: _focus,
|
|
|
|
style: TextStyle(
|
2021-12-10 04:22:55 +00:00
|
|
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor : Provider.of<Settings>(context).theme.messageFromOtherTextColor,
|
2021-11-06 05:38:45 +00:00
|
|
|
),
|
2021-11-08 20:57:55 +00:00
|
|
|
linkStyle: TextStyle(
|
2021-12-10 04:22:55 +00:00
|
|
|
color: Provider.of<Settings>(context).current().mainTextColor,
|
2021-11-08 20:57:55 +00:00
|
|
|
),
|
2021-11-06 05:38:45 +00:00
|
|
|
textAlign: TextAlign.left,
|
|
|
|
textWidthBasis: TextWidthBasis.longestLine,
|
|
|
|
);
|
|
|
|
}
|
2021-06-24 23:10:45 +00:00
|
|
|
|
2022-03-01 06:35:09 +00:00
|
|
|
var wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageMetadata>(context).ackd, errored: Provider.of<MessageMetadata>(context).error, fromMe: fromMe, messageDate: messageDate);
|
2021-06-24 23:10:45 +00:00
|
|
|
|
2021-07-06 19:46:39 +00:00
|
|
|
var error = Provider.of<MessageMetadata>(context).error;
|
2021-06-24 23:10:45 +00:00
|
|
|
|
|
|
|
return LayoutBuilder(builder: (context, constraints) {
|
|
|
|
//print(constraints.toString()+", "+constraints.maxWidth.toString());
|
|
|
|
return RepaintBoundary(
|
|
|
|
child: Container(
|
|
|
|
child: Container(
|
|
|
|
decoration: BoxDecoration(
|
2021-12-15 22:29:27 +00:00
|
|
|
color: error ? malformedColor : (fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor),
|
2021-06-24 23:10:45 +00:00
|
|
|
border: Border.all(
|
|
|
|
color: error
|
|
|
|
? malformedColor
|
2021-12-10 04:22:55 +00:00
|
|
|
: (fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor),
|
2021-06-24 23:10:45 +00:00
|
|
|
width: 1),
|
|
|
|
borderRadius: BorderRadius.only(
|
|
|
|
topLeft: Radius.circular(borderRadiousEh),
|
|
|
|
topRight: Radius.circular(borderRadiousEh),
|
|
|
|
bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero,
|
|
|
|
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
child: Padding(
|
|
|
|
padding: EdgeInsets.all(9.0),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
|
|
|
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])))));
|
|
|
|
});
|
|
|
|
}
|
2021-11-06 05:38:45 +00:00
|
|
|
|
|
|
|
void _modalOpenLink(BuildContext ctx, LinkableElement link) {
|
|
|
|
showModalBottomSheet<void>(
|
|
|
|
context: ctx,
|
|
|
|
builder: (BuildContext bcontext) {
|
|
|
|
return Container(
|
|
|
|
height: 200, // bespoke value courtesy of the [TextField] docs
|
|
|
|
child: Center(
|
|
|
|
child: Padding(
|
|
|
|
padding: EdgeInsets.all(30.0),
|
|
|
|
child: Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: <Widget>[
|
2022-03-21 16:18:17 +00:00
|
|
|
Text(AppLocalizations.of(context)!.clickableLinksWarning),
|
2021-11-06 05:38:45 +00:00
|
|
|
Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
|
|
|
Container(
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
|
|
|
child: ElevatedButton(
|
2022-03-21 16:18:17 +00:00
|
|
|
child: Text(AppLocalizations.of(context)!.clickableLinksCopy, semanticsLabel: AppLocalizations.of(context)!.clickableLinksCopy),
|
2021-11-06 05:38:45 +00:00
|
|
|
onPressed: () {
|
|
|
|
Clipboard.setData(new ClipboardData(text: link.url));
|
|
|
|
|
|
|
|
final snackBar = SnackBar(
|
2022-03-02 19:28:43 +00:00
|
|
|
content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification),
|
2021-11-06 05:38:45 +00:00
|
|
|
);
|
2021-11-06 17:53:42 +00:00
|
|
|
|
|
|
|
Navigator.pop(bcontext);
|
2021-11-06 05:38:45 +00:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Container(
|
|
|
|
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
|
|
|
child: ElevatedButton(
|
2022-03-21 16:18:17 +00:00
|
|
|
child: Text(AppLocalizations.of(context)!.clickableLinkOpen, semanticsLabel: AppLocalizations.of(context)!.clickableLinkOpen),
|
2021-11-06 05:38:45 +00:00
|
|
|
onPressed: () async {
|
|
|
|
if (await canLaunch(link.url)) {
|
|
|
|
await launch(link.url);
|
2021-12-13 23:42:42 +00:00
|
|
|
Navigator.pop(bcontext);
|
2021-11-06 05:38:45 +00:00
|
|
|
} else {
|
2022-03-21 16:18:17 +00:00
|
|
|
final snackBar = SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.clickableLinkError),
|
|
|
|
);
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
2021-11-06 05:38:45 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
],
|
|
|
|
)),
|
|
|
|
));
|
2021-11-25 23:59:54 +00:00
|
|
|
});
|
2021-11-06 05:38:45 +00:00
|
|
|
}
|
2021-06-24 23:10:45 +00:00
|
|
|
}
|