LCOV - code coverage report
Current view: top level - lib/widgets - quotedmessage.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 75 0.0 %
Date: 2026-07-15 19:28:30 Functions: 0 0 -

          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:cwtch/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(color: fromMe ? Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor : Provider.of<Settings>(context).theme.messageFromMeBackgroundColor),
      95             :                   height: 75,
      96           0 :                   child: Column(
      97             :                     crossAxisAlignment: CrossAxisAlignment.start,
      98             :                     mainAxisSize: MainAxisSize.min,
      99           0 :                     children: [
     100           0 :                       Align(alignment: Alignment.centerLeft, child: wdgReplyingTo),
     101           0 :                       Flexible(
     102           0 :                         child: Row(
     103             :                           mainAxisSize: MainAxisSize.max,
     104             :                           mainAxisAlignment: MainAxisAlignment.start,
     105             :                           crossAxisAlignment: CrossAxisAlignment.center,
     106           0 :                           children: [
     107           0 :                             Padding(
     108           0 :                               padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
     109           0 :                               child: Icon(Icons.reply, size: 32, color: qTextColor),
     110             :                             ),
     111           0 :                             Flexible(child: IntrinsicWidth(child: qMessage.getPreviewWidget(context))),
     112             :                           ],
     113             :                         ),
     114             :                       ),
     115             :                     ],
     116             :                   ),
     117             :                 ),
     118             :               ),
     119             :             );
     120             :           } catch (e) {
     121           0 :             return MalformedBubble();
     122             :           }
     123             :         } else {
     124             :           // This should be almost instantly resolved, any failure likely means an issue in decoding...
     125           0 :           return MessageLoadingBubble();
     126             :         }
     127             :       },
     128             :     );
     129             : 
     130           0 :     var wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageMetadata>(context).ackd, errored: Provider.of<MessageMetadata>(context).error, fromMe: fromMe, messageDate: messageDate);
     131             : 
     132           0 :     var error = Provider.of<MessageMetadata>(context).error;
     133           0 :     var wdgSender = compileSenderWidget(context, constraints, fromMe, senderDisplayStr);
     134           0 :     return Container(
     135           0 :       decoration: BoxDecoration(
     136           0 :         color: error ? malformedColor : (fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor),
     137           0 :         border: Border.all(
     138           0 :           color: error ? malformedColor : (fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor),
     139             :           width: 1,
     140             :         ),
     141           0 :         borderRadius: BorderRadius.only(
     142           0 :           topLeft: Radius.circular(borderRadiousEh),
     143           0 :           topRight: Radius.circular(borderRadiousEh),
     144           0 :           bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero,
     145           0 :           bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
     146             :         ),
     147             :       ),
     148           0 :       child: Padding(
     149           0 :         padding: EdgeInsets.all(9.0),
     150           0 :         child: Theme(
     151           0 :           data: Theme.of(context).copyWith(
     152           0 :             textSelectionTheme: TextSelectionThemeData(
     153           0 :               cursorColor: Provider.of<Settings>(context).theme.messageSelectionColor,
     154           0 :               selectionColor: Provider.of<Settings>(context).theme.messageSelectionColor,
     155           0 :               selectionHandleColor: Provider.of<Settings>(context).theme.messageSelectionColor,
     156             :             ),
     157             : 
     158             :             // Horrifying Hack: Flutter doesn't give us direct control over system menus but instead picks BG color from TextButtonThemeData ¯\_(ツ)_/¯
     159           0 :             textButtonTheme: TextButtonThemeData(style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.menuBackgroundColor))),
     160             :           ),
     161           0 :           child: IntrinsicWidth(
     162           0 :             child: Column(
     163             :               crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
     164             :               mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
     165             :               mainAxisSize: MainAxisSize.min,
     166             :               verticalDirection: VerticalDirection.up,
     167           0 :               children: fromMe ? [wdgDecorations, wdgMessage, wdgQuote] : [wdgDecorations, wdgMessage, wdgQuote, wdgSender],
     168             :             ),
     169             :           ),
     170             :         ),
     171             :       ),
     172             :     );
     173             :   }
     174             : }

Generated by: LCOV version 1.14