LCOV - code coverage report
Current view: top level - lib/widgets - eventbubble.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 69 0.0 %
Date: 2026-08-31 21:57:20 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:convert';
       2             : import 'package:flutter/material.dart';
       3             : import 'package:provider/provider.dart';
       4             : 
       5             : import 'package:cwtch/cwtch_icons_icons.dart';
       6             : import 'package:cwtch/l10n/app_localizations.dart';
       7             : import 'package:cwtch/models/contact.dart';
       8             : import 'package:cwtch/models/profile.dart';
       9             : import 'package:cwtch/models/redaction.dart';
      10             : import 'package:cwtch/themes/opaque.dart';
      11             : 
      12             : import '../constants.dart';
      13             : import '../settings.dart';
      14             : 
      15             : // WithheldBubble is displayed for messages hidden by default due to +m
      16             : class EventBubble extends StatefulWidget {
      17             :   final String content;
      18             :   dynamic? message;
      19             :   String? errorMessage = null;
      20             :   String? stringified = null;
      21             : 
      22           0 :   EventBubble(this.content) {
      23             :     try {
      24           0 :       this.message = jsonDecode(this.content);
      25             :     } catch (e) {
      26           0 :       this.errorMessage = "json decode error $e: " + this.content;
      27             :     }
      28             :   }
      29             : 
      30           0 :   @override
      31           0 :   EventBubbleState createState() => EventBubbleState();
      32             : }
      33             : 
      34             : class EventBubbleState extends State<EventBubble> {
      35           0 :   @override
      36             :   Widget build(BuildContext context) {
      37           0 :     if (widget.stringified == null) {
      38             :       try {
      39           0 :         widget.stringified = stringify(); // + widget.message["b"];//.keys.join(",");
      40             :       } catch (e) {
      41           0 :         widget.stringified = "parse error $e";
      42             :       }
      43             :     }
      44             : 
      45           0 :     return Align(
      46             :       alignment: Alignment.center,
      47           0 :       child: Padding(
      48           0 :         padding: EdgeInsets.all(5.0),
      49           0 :         child: Container(
      50           0 :           decoration: BoxDecoration(
      51           0 :             color: Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor,
      52           0 :             border: Border.all(color: Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor, width: 1),
      53           0 :             borderRadius: BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8), bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)),
      54             :           ),
      55           0 :           child: Padding(
      56           0 :             padding: EdgeInsets.all(9.0),
      57           0 :             child: Text(widget.stringified ?? "", style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle), maxLines: 3),
      58             :           ),
      59             :         ),
      60             :       ),
      61             :     );
      62             :   }
      63             : 
      64           0 :   String stringify() {
      65           0 :     if (widget.errorMessage != null) {
      66           0 :       return widget.errorMessage!;
      67             :     }
      68             : 
      69           0 :     int eventCode = widget.message["e"];
      70             :     switch (eventCode) {
      71           0 :       case AddMemberEvent:
      72           0 :         if (widget.message["a"].toString() == Provider.of<ContactInfoState>(context, listen: false).onion) {
      73           0 :           return r("\$handle joined the group");
      74             :         } else {
      75           0 :           return r("\$author added \$handle to the group");
      76             :         }
      77           0 :       case RemoveMemberEvent:
      78           0 :         dynamic params = jsonDecode(widget.message["b"]);
      79           0 :         if (widget.message["a"].toString() == params["h"]) {
      80           0 :           return r("\$author left the group");
      81             :         } else {
      82           0 :           return r("\$author removed \$handle from the group");
      83             :         }
      84           0 :       case ChangeMemberRoleEvent:
      85           0 :         return r("\$author changed \$handle to \$role");
      86           0 :       case ChangeGroupModeEvent:
      87           0 :         return r("\$author changed the group mode to \$mode");
      88           0 :       case ChangeGroupMaskEvent:
      89           0 :         return r("\$author changed the group mask to \$mask");
      90           0 :       case UpdateGroupMetadataEvent:
      91           0 :         return r("\$author updated the group name/attributes");
      92           0 :       case UpdateGroupPictureEvent:
      93           0 :         return r("\$author updated the group picture");
      94             :       default:
      95           0 :         return r("(Missing message: \$author did an event code \$e");
      96             :     }
      97             :   }
      98             : 
      99           0 :   String r(String input) {
     100             :     // widget.message {
     101             :     // g: group onion
     102             :     // a: author onion
     103             :     // m: member message id
     104             :     // b: event parameters {
     105             :     //    Additive: "true"|"false" for mode/mask
     106             :     //    a: mask bit
     107             :     //    h: handle
     108             :     //    n: mask bit
     109             :     //    r: role
     110             :     // t: ?
     111             :     // s: sig?
     112             :     // e: event code
     113           0 :     String author = widget.message["a"].toString();
     114           0 :     if (author == Provider.of<ProfileInfoState>(context).onion) {
     115             :       author = "You";
     116             :     } else {
     117           0 :       ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(author);
     118             :       if (contact != null) {
     119           0 :         author = redactedNick(context, contact.onion, contact.nickname);
     120             :       }
     121             :     }
     122             : 
     123             :     String handle = "";
     124             :     String role = "";
     125             :     String mode = "";
     126             :     String mask = "";
     127             : 
     128           0 :     if (widget.message.containsKey("b")) {
     129           0 :       dynamic params = jsonDecode(widget.message["b"]);
     130             : 
     131           0 :       if (params.containsKey("h")) {
     132           0 :         handle = params["h"];
     133           0 :         if (handle == Provider.of<ProfileInfoState>(context).onion) {
     134             :           handle = "you";
     135             :         } else {
     136           0 :           ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(handle);
     137             :           if (contact != null) {
     138           0 :             handle = redactedNick(context, contact.onion, contact.nickname);
     139             :           }
     140             :         }
     141             :       }
     142             : 
     143           0 :       if (params.containsKey("r")) {
     144           0 :         role = params["r"];
     145             :       }
     146             : 
     147           0 :       String additive = (params.containsKey("Additive") && params["Additive"]) ? "+" : "-";
     148           0 :       if (params.containsKey("a")) {
     149           0 :         mode = additive + params["a"];
     150             :       }
     151           0 :       if (params.containsKey("n")) {
     152           0 :         mask = additive + params["n"];
     153             :       }
     154             :     }
     155             : 
     156             :     return input
     157           0 :         .replaceAll("\$author", author)
     158           0 :         .replaceAll("\$e", widget.message["e"].toString())
     159           0 :         .replaceAll("\$handle", handle)
     160           0 :         .replaceAll("\$role", role)
     161           0 :         .replaceAll("\$mask", mask)
     162           0 :         .replaceAll("\$mode", mode);
     163             :   }
     164             : }

Generated by: LCOV version 1.14