diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index ab03a8cb..80e0643d 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -351,6 +351,10 @@ class CwtchNotifier { case "DoneStorageMigration": appState.SetModalState(ModalState.none); break; + case "ACNInfo": + var handle = data["Handle"]; + profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(handle)?.acnCircuit = data["Data"]; + break; default: EnvironmentConfig.debugLog("unhandled event: $type"); } diff --git a/lib/model.dart b/lib/model.dart index 40a98110..035b73d2 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -565,6 +565,8 @@ class ContactInfoState extends ChangeNotifier { String? _server; late bool _archived; + String? _acnCircuit; + ContactInfoState(this.profileOnion, this.identifier, this.onion, {nickname = "", isGroup = false, @@ -598,6 +600,11 @@ class ContactInfoState extends ChangeNotifier { String get savePeerHistory => this._savePeerHistory; + String? get acnCircuit => this._acnCircuit; + set acnCircuit(String? acnCircuit) { + this._acnCircuit = acnCircuit; + } + // Indicated whether the conversation is archived, in which case it will // be moved to the very bottom of the active conversations list until // new messages appear diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index 2c11bcb3..1456d176 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:ui'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:flutter/services.dart'; import 'package:cwtch/model.dart'; @@ -47,6 +48,33 @@ class _PeerSettingsViewState extends State { Widget _buildSettingsList() { return Consumer(builder: (context, settings, child) { return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { + String? acnCircuit = Provider.of(context).acnCircuit; + + Widget path = Text(Provider.of(context, listen: false).status); + + if (acnCircuit != null) { + var hops = acnCircuit.split(","); + if (hops.length == 3) { + List paths = hops.map((String countryCodeAndIp) { + var parts = countryCodeAndIp.split(":"); + var country = parts[0]; + var ip = parts[1]; + return RichText( + textAlign: TextAlign.left, + text: TextSpan( + text: "$country", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 10, fontFamily: "monospace"), + children: [TextSpan(text: " ($ip)", style: TextStyle(fontSize: 8, fontWeight: FontWeight.normal))])); + }).toList(growable: true); + + paths.add(RichText(text: TextSpan(text: "Tor Network", style: TextStyle(fontWeight: FontWeight.normal, fontSize: 8, fontFamily: "monospace")))); + + path = Column( + children: paths, + ); + } + } + return Scrollbar( isAlwaysShown: true, child: SingleChildScrollView( @@ -104,6 +132,16 @@ class _PeerSettingsViewState extends State { SizedBox( height: 20, ), + ListTile( + leading: Icon(CwtchIcons.onion_on, color: settings.current().mainTextColor), + isThreeLine: true, + title: Text("ACN Circuit Info"), + subtitle: Text("In depth information about the path that the anonymous communication network is using to connect to this conversation"), + trailing: path, + ), + SizedBox( + height: 20, + ), SwitchListTile( title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor)), value: Provider.of(context).isBlocked,