Line data Source code
1 : import 'package:cwtch/models/contact.dart';
2 : import 'package:cwtch/models/message.dart';
3 : import 'package:cwtch/models/profile.dart';
4 : import 'package:cwtch/widgets/malformedbubble.dart';
5 : import 'package:cwtch/widgets/messageloadingbubble.dart';
6 : import 'package:flutter/material.dart';
7 : import 'package:provider/provider.dart';
8 : import 'package:flutter_gen/gen_l10n/app_localizations.dart';
9 : import '../models/redaction.dart';
10 : import '../settings.dart';
11 : import 'messageBubbleWidgetHelpers.dart';
12 : import 'messagebubbledecorations.dart';
13 :
14 : class QuotedMessageBubble extends StatefulWidget {
15 : final Future<Message> quotedMessage;
16 : final String body;
17 :
18 0 : QuotedMessageBubble(this.body, this.quotedMessage);
19 :
20 0 : @override
21 0 : QuotedMessageBubbleState createState() => QuotedMessageBubbleState();
22 : }
23 :
24 : class QuotedMessageBubbleState extends State<QuotedMessageBubble> {
25 : FocusNode _focus = FocusNode();
26 :
27 0 : @override
28 : Widget build(BuildContext context) {
29 0 : var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
30 : var borderRadiousEh = 15.0;
31 :
32 0 : DateTime messageDate = Provider.of<MessageMetadata>(context).timestamp;
33 :
34 : // If the sender is not us, then we want to give them a nickname...
35 : var senderDisplayStr = "";
36 : if (!fromMe) {
37 0 : ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
38 : if (contact != null) {
39 0 : senderDisplayStr = redactedNick(context, contact.onion, contact.nickname);
40 : } else {
41 0 : senderDisplayStr = Provider.of<MessageMetadata>(context).senderHandle;
42 : }
43 : }
44 :
45 0 : var showClickableLinks = Provider.of<Settings>(context).isExperimentEnabled(ClickableLinksExperiment);
46 0 : var formatMessages = Provider.of<Settings>(context).isExperimentEnabled(FormattingExperiment);
47 0 : Size size = MediaQuery.of(context).size;
48 0 : BoxConstraints constraints = BoxConstraints.loose(size);
49 0 : Widget wdgMessage = compileMessageContentWidget(context, constraints, fromMe, widget.body, _focus, formatMessages, showClickableLinks);
50 0 : var wdgQuote = FutureBuilder(
51 0 : future: widget.quotedMessage,
52 0 : builder: (context, snapshot) {
53 0 : if (snapshot.hasData) {
54 : try {
55 0 : var qMessage = (snapshot.data! as Message);
56 :
57 : // If the sender is not us, then we want to give them a nickname...
58 : String qMessageSender;
59 :
60 : // if we sent the quoted message then display our nickname
61 0 : if (qMessage.getMetadata().senderHandle == Provider.of<ProfileInfoState>(context).onion) {
62 0 : qMessageSender = Provider.of<ProfileInfoState>(context).nickname;
63 : } else {
64 : // default to handle
65 0 : qMessageSender = qMessage.getMetadata().senderHandle;
66 : // if we have the handle as a contact then replace with the nickname...
67 0 : ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(qMessageSender);
68 : if (contact != null) {
69 0 : qMessageSender = contact.nickname;
70 : }
71 : }
72 :
73 0 : var qTextColor = fromMe ? Provider.of<Settings>(context).theme.messageFromOtherTextColor : Provider.of<Settings>(context).theme.messageFromMeTextColor;
74 :
75 0 : var wdgReplyingTo = SelectableText(
76 0 : AppLocalizations.of(context)!.replyingTo.replaceAll("%1", qMessageSender),
77 0 : style: Provider.of<Settings>(context).scaleFonts(TextStyle(fontSize: 10, color: qTextColor.withOpacity(0.8))),
78 : );
79 : // Swap the background color for quoted tweets..
80 0 : return MouseRegion(
81 : cursor: SystemMouseCursors.click,
82 0 : child: GestureDetector(
83 0 : onTap: () {
84 0 : var messageInfo = Provider.of<ContactInfoState>(context, listen: false).messageCache.getByContentHash(qMessage.getMetadata().contenthash);
85 : if (messageInfo != null) {
86 0 : var index = Provider.of<ContactInfoState>(context, listen: false).messageCache.findIndex(messageInfo.metadata.messageID);
87 0 : Provider.of<ContactInfoState>(context, listen: false).messageScrollController.scrollTo(index: index, duration: Duration(milliseconds: 100));
88 : }
89 : },
90 0 : child: Container(
91 0 : margin: EdgeInsets.all(5),
92 0 : padding: EdgeInsets.all(5),
93 : clipBehavior: Clip.antiAliasWithSaveLayer,
94 0 : decoration: BoxDecoration(
95 0 : color: fromMe ? Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor : Provider.of<Settings>(context).theme.messageFromMeBackgroundColor,
96 : ),
97 : height: 75,
98 0 : child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [
99 0 : Align(alignment: Alignment.centerLeft, child: wdgReplyingTo),
100 0 : Flexible(
101 0 : child: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [
102 0 : Padding(padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), child: Icon(Icons.reply, size: 32, color: qTextColor)),
103 0 : Flexible(child: IntrinsicWidth(child: qMessage.getPreviewWidget(context))),
104 : ]))
105 : ])),
106 : ),
107 : );
108 : } catch (e) {
109 0 : return MalformedBubble();
110 : }
111 : } else {
112 : // This should be almost instantly resolved, any failure likely means an issue in decoding...
113 0 : return MessageLoadingBubble();
114 : }
115 : },
116 : );
117 :
118 0 : var wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageMetadata>(context).ackd, errored: Provider.of<MessageMetadata>(context).error, fromMe: fromMe, messageDate: messageDate);
119 :
120 0 : var error = Provider.of<MessageMetadata>(context).error;
121 0 : var wdgSender = compileSenderWidget(context, constraints, fromMe, senderDisplayStr);
122 0 : return Container(
123 0 : decoration: BoxDecoration(
124 0 : color: error ? malformedColor : (fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor),
125 0 : border: Border.all(
126 0 : color: error ? malformedColor : (fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor),
127 : width: 1),
128 0 : borderRadius: BorderRadius.only(
129 0 : topLeft: Radius.circular(borderRadiousEh),
130 0 : topRight: Radius.circular(borderRadiousEh),
131 0 : bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero,
132 0 : bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
133 : ),
134 : ),
135 0 : child: Padding(
136 0 : padding: EdgeInsets.all(9.0),
137 0 : child: Theme(
138 0 : data: Theme.of(context).copyWith(
139 0 : textSelectionTheme: TextSelectionThemeData(
140 0 : cursorColor: Provider.of<Settings>(context).theme.messageSelectionColor,
141 0 : selectionColor: Provider.of<Settings>(context).theme.messageSelectionColor,
142 0 : selectionHandleColor: Provider.of<Settings>(context).theme.messageSelectionColor),
143 :
144 : // Horrifying Hack: Flutter doesn't give us direct control over system menus but instead picks BG color from TextButtonThemeData ¯\_(ツ)_/¯
145 0 : textButtonTheme: TextButtonThemeData(
146 0 : style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.menuBackgroundColor)),
147 : ),
148 : ),
149 0 : child: IntrinsicWidth(
150 0 : child: Column(
151 : crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
152 : mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
153 : mainAxisSize: MainAxisSize.min,
154 : verticalDirection: VerticalDirection.up,
155 0 : children: fromMe ? [wdgDecorations, wdgMessage, wdgQuote] : [wdgDecorations, wdgMessage, wdgQuote, wdgSender])))));
156 : }
157 : }
|