LCOV - code coverage report
Current view: top level - lib/views - peersettingsview.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 227 0.0 %
Date: 2024-04-05 23:55:39 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:cwtch/config.dart';
       2             : import 'package:cwtch/cwtch_icons_icons.dart';
       3             : import 'package:cwtch/models/appstate.dart';
       4             : import 'package:cwtch/models/contact.dart';
       5             : import 'package:cwtch/models/profile.dart';
       6             : import 'package:cwtch/widgets/profileimage.dart';
       7             : import 'package:flutter/services.dart';
       8             : import 'package:cwtch/widgets/buttontextfield.dart';
       9             : import 'package:cwtch/widgets/cwtchlabel.dart';
      10             : import 'package:flutter/material.dart';
      11             : import 'package:cwtch/settings.dart';
      12             : import 'package:provider/provider.dart';
      13             : import 'package:flutter_gen/gen_l10n/app_localizations.dart';
      14             : 
      15             : import '../main.dart';
      16             : import '../themes/opaque.dart';
      17             : 
      18             : /// Peer Settings View Provides  way to Configure .
      19             : class PeerSettingsView extends StatefulWidget {
      20           0 :   @override
      21           0 :   _PeerSettingsViewState createState() => _PeerSettingsViewState();
      22             : }
      23             : 
      24             : class _PeerSettingsViewState extends State<PeerSettingsView> {
      25           0 :   @override
      26             :   void dispose() {
      27           0 :     super.dispose();
      28             :   }
      29             : 
      30             :   final ctrlrNick = TextEditingController(text: "");
      31             :   ScrollController peerSettingsScrollController = ScrollController();
      32             : 
      33           0 :   @override
      34             :   void initState() {
      35           0 :     super.initState();
      36           0 :     final nickname = Provider.of<ContactInfoState>(context, listen: false).nickname;
      37           0 :     if (nickname.isNotEmpty) {
      38           0 :       ctrlrNick.text = nickname;
      39             :     }
      40             :   }
      41             : 
      42           0 :   @override
      43             :   Widget build(BuildContext context) {
      44           0 :     var handle = Provider.of<ContactInfoState>(context).nickname;
      45           0 :     if (handle.isEmpty) {
      46           0 :       handle = Provider.of<ContactInfoState>(context).onion;
      47             :     }
      48           0 :     return Scaffold(
      49           0 :       appBar: AppBar(
      50           0 :         title: Container(
      51           0 :             height: Provider.of<Settings>(context).fontScaling * 24.0,
      52             :             clipBehavior: Clip.hardEdge,
      53           0 :             decoration: BoxDecoration(),
      54           0 :             child: Text(handle + " " + AppLocalizations.of(context)!.conversationSettings)),
      55             :       ),
      56           0 :       body: _buildSettingsList(),
      57             :     );
      58             :   }
      59             : 
      60           0 :   Widget _buildSettingsList() {
      61           0 :     return Consumer<Settings>(builder: (context, settings, child) {
      62           0 :       return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
      63           0 :         String? acnCircuit = Provider.of<ContactInfoState>(context).acnCircuit;
      64             : 
      65           0 :         Widget path = Text(Provider.of<ContactInfoState>(context).status);
      66             : 
      67             :         if (acnCircuit != null) {
      68           0 :           var hops = acnCircuit.split(",");
      69           0 :           if (hops.length == 3) {
      70           0 :             List<Widget> paths = hops.map((String countryCodeAndIp) {
      71           0 :               var parts = countryCodeAndIp.split(":");
      72           0 :               var country = parts[0];
      73           0 :               var ip = parts[1];
      74           0 :               return RichText(
      75             :                   textAlign: TextAlign.left,
      76           0 :                   text: TextSpan(
      77             :                       text: country,
      78           0 :                       style: TextStyle(fontWeight: FontWeight.bold, fontSize: 10, fontFamily: "RobotoMono"),
      79           0 :                       children: [TextSpan(text: " ($ip)", style: TextStyle(fontSize: 8, fontWeight: FontWeight.normal))]));
      80           0 :             }).toList(growable: true);
      81             : 
      82           0 :             paths.add(RichText(text: TextSpan(text: AppLocalizations.of(context)!.labelTorNetwork, style: TextStyle(fontWeight: FontWeight.normal, fontSize: 8, fontFamily: "monospace"))));
      83             : 
      84           0 :             path = Column(
      85             :               children: paths,
      86             :             );
      87             :           }
      88             :         }
      89             : 
      90           0 :         List<Widget> evWidgets = Provider.of<ContactInfoState>(context, listen: false).contactEvents.map((ev) {
      91           0 :           return ListTile(
      92           0 :             title: Text(ev.summary, style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)),
      93           0 :             subtitle: Text(ev.timestamp.toLocal().toIso8601String(), style: Provider.of<Settings>(context).scaleFonts(defaultTextStyle)),
      94             :           );
      95           0 :         }).toList();
      96             : 
      97           0 :         return Scrollbar(
      98             :             trackVisibility: true,
      99           0 :             controller: peerSettingsScrollController,
     100           0 :             child: SingleChildScrollView(
     101             :                 clipBehavior: Clip.antiAlias,
     102           0 :                 controller: peerSettingsScrollController,
     103           0 :                 child: ConstrainedBox(
     104           0 :                     constraints: BoxConstraints(
     105           0 :                       minHeight: viewportConstraints.maxHeight,
     106             :                     ),
     107           0 :                     child: Container(
     108           0 :                         color: settings.theme.backgroundPaneColor,
     109           0 :                         padding: EdgeInsets.all(12),
     110           0 :                         child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [
     111           0 :                           Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
     112           0 :                             ProfileImage(
     113           0 :                                 imagePath: Provider.of<Settings>(context).isExperimentEnabled(ImagePreviewsExperiment)
     114           0 :                                     ? Provider.of<ContactInfoState>(context).imagePath
     115           0 :                                     : Provider.of<ContactInfoState>(context).defaultImagePath,
     116             :                                 diameter: 120,
     117             :                                 maskOut: false,
     118           0 :                                 border: settings.theme.portraitOnlineBorderColor,
     119           0 :                                 badgeTextColor: settings.theme.portraitContactBadgeTextColor,
     120           0 :                                 badgeColor: settings.theme.portraitContactBadgeColor,
     121             :                                 badgeEdit: false),
     122           0 :                             SizedBox(
     123           0 :                                 width: MediaQuery.of(context).size.width / 2,
     124           0 :                                 child: Column(children: [
     125           0 :                                   Padding(
     126           0 :                                     padding: EdgeInsets.all(1),
     127           0 :                                     child: SelectableText(
     128           0 :                                       Provider.of<ContactInfoState>(context, listen: false).attributes[0] ?? "",
     129             :                                       textAlign: TextAlign.center,
     130             :                                     ),
     131             :                                   ),
     132           0 :                                   Padding(
     133           0 :                                     padding: EdgeInsets.all(1),
     134           0 :                                     child: SelectableText(
     135           0 :                                       Provider.of<ContactInfoState>(context, listen: false).attributes[1] ?? "",
     136             :                                       textAlign: TextAlign.center,
     137             :                                     ),
     138             :                                   ),
     139           0 :                                   Padding(
     140           0 :                                     padding: EdgeInsets.all(1),
     141           0 :                                     child: SelectableText(
     142           0 :                                       Provider.of<ContactInfoState>(context, listen: false).attributes[2] ?? "",
     143             :                                       textAlign: TextAlign.center,
     144             :                                     ),
     145             :                                   )
     146             :                                 ]))
     147             :                           ]),
     148             : 
     149           0 :                           Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
     150           0 :                             CwtchLabel(label: AppLocalizations.of(context)!.displayNameLabel),
     151           0 :                             SizedBox(
     152             :                               height: 20,
     153             :                             ),
     154           0 :                             CwtchButtonTextField(
     155           0 :                               controller: ctrlrNick,
     156             :                               readonly: false,
     157           0 :                               onPressed: () {
     158           0 :                                 var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
     159           0 :                                 var conversation = Provider.of<ContactInfoState>(context, listen: false).identifier;
     160           0 :                                 Provider.of<ContactInfoState>(context, listen: false).localNickname = ctrlrNick.text;
     161           0 :                                 Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, conversation, "profile.name", ctrlrNick.text);
     162           0 :                                 final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.nickChangeSuccess));
     163           0 :                                 ScaffoldMessenger.of(context).showSnackBar(snackBar);
     164             :                               },
     165           0 :                               icon: Icon(Icons.save),
     166           0 :                               tooltip: AppLocalizations.of(context)!.saveBtn,
     167             :                             )
     168             :                           ]),
     169             : 
     170             :                           // Address Copy Button
     171           0 :                           Visibility(
     172           0 :                               visible: settings.streamerMode == false,
     173           0 :                               child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
     174           0 :                                 SizedBox(
     175             :                                   height: 20,
     176             :                                 ),
     177           0 :                                 CwtchLabel(label: AppLocalizations.of(context)!.addressLabel),
     178           0 :                                 SizedBox(
     179             :                                   height: 20,
     180             :                                 ),
     181           0 :                                 CwtchButtonTextField(
     182           0 :                                   controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion),
     183           0 :                                   onPressed: _copyOnion,
     184           0 :                                   icon: Icon(CwtchIcons.address_copy),
     185           0 :                                   tooltip: AppLocalizations.of(context)!.copyBtn,
     186             :                                 )
     187             :                               ])),
     188           0 :                           Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
     189           0 :                             SizedBox(
     190             :                               height: 20,
     191             :                             ),
     192           0 :                             CwtchLabel(label: AppLocalizations.of(context)!.conversationSettings),
     193           0 :                             SizedBox(
     194             :                               height: 20,
     195             :                             ),
     196           0 :                             ListTile(
     197           0 :                               leading: Icon(CwtchIcons.onion_on, color: settings.current().mainTextColor),
     198             :                               isThreeLine: true,
     199           0 :                               title: Text(AppLocalizations.of(context)!.labelACNCircuitInfo),
     200           0 :                               subtitle: Text(AppLocalizations.of(context)!.descriptionACNCircuitInfo),
     201             :                               trailing: path,
     202             :                             ),
     203           0 :                             SizedBox(
     204             :                               height: 20,
     205             :                             ),
     206           0 :                             SwitchListTile(
     207           0 :                               title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor)),
     208           0 :                               value: Provider.of<ContactInfoState>(context).isBlocked,
     209           0 :                               onChanged: (bool blocked) {
     210           0 :                                 Provider.of<ContactInfoState>(context, listen: false).blocked = blocked;
     211             : 
     212           0 :                                 var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
     213           0 :                                 var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
     214             : 
     215             :                                 if (blocked) {
     216           0 :                                   Provider.of<FlwtchState>(context, listen: false).cwtch.BlockContact(profileOnion, identifier);
     217             :                                 } else {
     218           0 :                                   Provider.of<FlwtchState>(context, listen: false).cwtch.UnblockContact(profileOnion, identifier);
     219             :                                 }
     220             :                               },
     221           0 :                               activeTrackColor: settings.theme.defaultButtonColor,
     222           0 :                               inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
     223           0 :                               secondary: Icon(CwtchIcons.block_peer, color: settings.current().mainTextColor),
     224             :                             ),
     225           0 :                             ListTile(
     226           0 :                                 title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor)),
     227           0 :                                 subtitle: Text(AppLocalizations.of(context)!.savePeerHistoryDescription),
     228           0 :                                 leading: Icon(CwtchIcons.peer_history, color: settings.current().mainTextColor),
     229           0 :                                 trailing: DropdownButton(
     230             :                                     value:
     231           0 :                                         (Provider.of<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory" || Provider.of<ContactInfoState>(context).savePeerHistory == "HistoryDefault")
     232           0 :                                             ? AppLocalizations.of(context)!.conversationNotificationPolicyDefault
     233           0 :                                             : (Provider.of<ContactInfoState>(context).savePeerHistory == "SaveHistory"
     234           0 :                                                 ? AppLocalizations.of(context)!.savePeerHistory
     235           0 :                                                 : AppLocalizations.of(context)!.dontSavePeerHistory),
     236           0 :                                     onChanged: (newValue) {
     237           0 :                                       setState(() {
     238             :                                         // Set whether or not to dave the Contact History...
     239           0 :                                         var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
     240           0 :                                         var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
     241             :                                         const SaveHistoryKey = "profile.SavePeerHistory";
     242             :                                         const SaveHistory = "SaveHistory";
     243             :                                         const DelHistory = "DeleteHistoryConfirmed";
     244             :                                         const HistoryDefault = "HistoryDefault";
     245             : 
     246             :                                         // NOTE: .savePeerHistory is used to show ephemeral warnings so it's state is important to update.
     247           0 :                                         if (newValue == AppLocalizations.of(context)!.conversationNotificationPolicyDefault) {
     248           0 :                                           Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = HistoryDefault;
     249           0 :                                           Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, SaveHistoryKey, HistoryDefault);
     250           0 :                                         } else if (newValue == AppLocalizations.of(context)!.savePeerHistory) {
     251           0 :                                           Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = SaveHistory;
     252           0 :                                           Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, SaveHistoryKey, SaveHistory);
     253             :                                         } else {
     254           0 :                                           Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = DelHistory;
     255           0 :                                           Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, SaveHistoryKey, DelHistory);
     256             :                                         }
     257             :                                       });
     258             :                                     },
     259           0 :                                     items: [
     260           0 :                                       AppLocalizations.of(context)!.conversationNotificationPolicyDefault,
     261           0 :                                       AppLocalizations.of(context)!.savePeerHistory,
     262           0 :                                       AppLocalizations.of(context)!.dontSavePeerHistory
     263           0 :                                     ].map<DropdownMenuItem<String>>((String value) {
     264           0 :                                       return DropdownMenuItem<String>(
     265             :                                         value: value,
     266           0 :                                         child: Text(value, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
     267             :                                       );
     268           0 :                                     }).toList())),
     269           0 :                             ListTile(
     270           0 :                                 title: Text(AppLocalizations.of(context)!.conversationNotificationPolicySettingLabel, style: TextStyle(color: settings.current().mainTextColor)),
     271           0 :                                 subtitle: Text(AppLocalizations.of(context)!.conversationNotificationPolicySettingDescription),
     272           0 :                                 leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor),
     273           0 :                                 trailing: DropdownButton(
     274           0 :                                   value: Provider.of<ContactInfoState>(context).notificationsPolicy,
     275           0 :                                   items: ConversationNotificationPolicy.values.map<DropdownMenuItem<ConversationNotificationPolicy>>((ConversationNotificationPolicy value) {
     276           0 :                                     return DropdownMenuItem<ConversationNotificationPolicy>(
     277             :                                       value: value,
     278           0 :                                       child: Text(value.toName(context), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
     279             :                                     );
     280           0 :                                   }).toList(),
     281           0 :                                   onChanged: (ConversationNotificationPolicy? newVal) {
     282           0 :                                     Provider.of<ContactInfoState>(context, listen: false).notificationsPolicy = newVal!;
     283           0 :                                     var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
     284           0 :                                     var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
     285             :                                     const NotificationPolicyKey = "profile.notification-policy";
     286           0 :                                     Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationPolicyKey, newVal.toString());
     287             :                                   },
     288             :                                 )),
     289             :                           ]),
     290           0 :                           Column(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [
     291           0 :                             SizedBox(
     292             :                               height: 20,
     293             :                             ),
     294           0 :                             Row(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [
     295           0 :                               Tooltip(
     296           0 :                                   message: AppLocalizations.of(context)!.archiveConversation,
     297           0 :                                   child: ElevatedButton.icon(
     298           0 :                                     onPressed: () {
     299           0 :                                       var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
     300           0 :                                       var handle = Provider.of<ContactInfoState>(context, listen: false).identifier;
     301             :                                       // locally update cache...
     302           0 :                                       Provider.of<ContactInfoState>(context, listen: false).isArchived = true;
     303           0 :                                       Provider.of<FlwtchState>(context, listen: false).cwtch.ArchiveConversation(profileOnion, handle);
     304           0 :                                       Future.delayed(Duration(milliseconds: 500), () {
     305           0 :                                         Provider.of<AppState>(context, listen: false).selectedConversation = null;
     306           0 :                                         Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
     307             :                                       });
     308             :                                     },
     309           0 :                                     icon: Icon(Icons.archive),
     310           0 :                                     label: Text(AppLocalizations.of(context)!.archiveConversation),
     311             :                                   ))
     312             :                             ]),
     313           0 :                             SizedBox(
     314             :                               height: 20,
     315             :                             ),
     316           0 :                             Row(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [
     317           0 :                               Tooltip(
     318           0 :                                   message: AppLocalizations.of(context)!.leaveConversation,
     319           0 :                                   child: TextButton.icon(
     320           0 :                                     onPressed: () {
     321           0 :                                       showAlertDialog(context);
     322             :                                     },
     323           0 :                                     style: ButtonStyle(
     324           0 :                                         backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.backgroundPaneColor),
     325           0 :                                         foregroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.mainTextColor)),
     326           0 :                                     icon: Icon(CwtchIcons.leave_group),
     327           0 :                                     label: Text(
     328           0 :                                       AppLocalizations.of(context)!.leaveConversation,
     329           0 :                                       style: settings.scaleFonts(defaultTextButtonStyle.copyWith(decoration: TextDecoration.underline)),
     330             :                                     ),
     331             :                                   ))
     332             :                             ]),
     333             :                           ]),
     334           0 :                           Visibility(
     335           0 :                               visible: EnvironmentConfig.BUILD_VER == dev_version,
     336             :                               maintainSize: false,
     337           0 :                               child: Column(
     338             :                                 children: evWidgets,
     339             :                               ))
     340             :                         ])))));
     341             :       });
     342             :     });
     343             :   }
     344             : 
     345           0 :   void _copyOnion() {
     346           0 :     Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
     347           0 :     final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification));
     348           0 :     ScaffoldMessenger.of(context).showSnackBar(snackBar);
     349             :   }
     350             : 
     351           0 :   showAlertDialog(BuildContext context) {
     352             :     // set up the buttons
     353           0 :     Widget cancelButton = ElevatedButton(
     354           0 :       child: Text(AppLocalizations.of(context)!.cancel),
     355           0 :       style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.all(20))),
     356           0 :       onPressed: () {
     357           0 :         Navigator.of(context).pop(); // dismiss dialog
     358             :       },
     359             :     );
     360           0 :     Widget continueButton = ElevatedButton(
     361           0 :       style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.all(20))),
     362           0 :       child: Text(AppLocalizations.of(context)!.yesLeave),
     363           0 :       onPressed: () {
     364           0 :         var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
     365           0 :         var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
     366             :         // locally update cache...
     367           0 :         Provider.of<ProfileInfoState>(context, listen: false).contactList.removeContact(identifier);
     368           0 :         Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, identifier);
     369           0 :         Future.delayed(Duration(milliseconds: 500), () {
     370           0 :           Provider.of<AppState>(context, listen: false).selectedConversation = null;
     371           0 :           Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
     372             :         });
     373             :       },
     374             :     );
     375             : 
     376             :     // set up the AlertDialog
     377           0 :     AlertDialog alert = AlertDialog(
     378           0 :       title: Text(AppLocalizations.of(context)!.reallyLeaveThisGroupPrompt),
     379           0 :       actions: [
     380             :         cancelButton,
     381             :         continueButton,
     382             :       ],
     383             :     );
     384             : 
     385             :     // show the dialog
     386           0 :     showDialog(
     387             :       context: context,
     388           0 :       builder: (BuildContext context) {
     389             :         return alert;
     390             :       },
     391             :     );
     392             :   }
     393             : }

Generated by: LCOV version 1.14