Skip to content

Commit

Permalink
bruig: show list of active kx attempts
Browse files Browse the repository at this point in the history
  • Loading branch information
miki authored and miki-totefu committed Oct 11, 2024
1 parent 60d50a1 commit 5778917
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 20 deletions.
31 changes: 19 additions & 12 deletions bruig/flutterui/bruig/lib/components/info_grid.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,32 @@ class SimpleInfoGridAdv extends StatelessWidget {
this.textSize = TextSize.small,
});

Widget _widgetFor(dynamic v) {
if (v is String) {
return Txt(v, size: textSize);
} else if (v is Copyable) {
return Copyable.txt(Txt(v.text, size: textSize), tooltip: v.tooltip);
} else if (v is Widget) {
return v;
} else {
return Txt("$v", size: textSize);
}
}

Widget buildChild(dynamic child) {
late Widget label;
late Widget value;
if (child is Tuple2<String, String>) {
label = Txt(child.item1, size: textSize);
value = Txt(child.item2, size: textSize);
label = _widgetFor(child.item1);
value = _widgetFor(child.item2);
} else if (child is List<String>) {
label = Txt(child[0], size: textSize);
value = Txt(child[1], size: textSize);
label = _widgetFor(child[0]);
value = _widgetFor(child[1]);
} else if (child is List<dynamic>) {
label = Txt(child[0], size: textSize);
if (child[1] is Copyable) {
var c = child[1] as Copyable;
value = Copyable.txt(Txt(c.text, size: textSize), tooltip: c.tooltip);
} else {
value = Txt(child[1], size: textSize);
}
label = _widgetFor(child[0]);
value = _widgetFor(child[1]);
} else if (child is SimpleInfoGridCopyableVal) {
label = Txt(child.label);
label = _widgetFor(child.label);
value = Copyable.txt(Txt(child.value, size: textSize));
} else {
label = const Text("error");
Expand Down
37 changes: 31 additions & 6 deletions bruig/flutterui/bruig/lib/components/interactive_avatar.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:bruig/components/empty_widget.dart';
import 'package:bruig/components/gc_context_menu.dart';
import 'package:bruig/components/text.dart';
import 'package:bruig/components/user_context_menu.dart';
import 'package:bruig/models/client.dart';
import 'package:bruig/util.dart';
Expand Down Expand Up @@ -194,11 +195,13 @@ class UserMenuAvatar extends StatelessWidget {
class SelfAvatar extends StatelessWidget {
final ClientModel client;
final VoidCallback? onTap;
const SelfAvatar(this.client, {this.onTap, super.key});
final double? radius;
const SelfAvatar(this.client, {this.onTap, this.radius, super.key});

@override
Widget build(BuildContext context) {
return AvatarModelAvatar(client.myAvatar, client.nick, onTap: onTap);
return AvatarModelAvatar(client.myAvatar, client.nick,
radius: radius, onTap: onTap);
}
}

Expand All @@ -212,34 +215,56 @@ class UserAvatarFromID extends StatelessWidget {
final bool showChatSideMenuOnTap;
final String? postFrom;
final String? nick;
final double? radius;
const UserAvatarFromID(this.client, this.uid,
{this.disableTooltip = false,
this.showChatSideMenuOnTap = false,
this.postFrom,
this.radius,
this.nick,
super.key});

@override
Widget build(BuildContext context) {
if (uid == client.publicID) {
return SelfAvatar(client);
return SelfAvatar(client, radius: radius);
}

var chat = client.getExistingChat(uid);
if (chat != null) {
return UserMenuAvatar(client, chat,
showChatSideMenuOnTap: showChatSideMenuOnTap,
postFrom: postFrom,
disableTooltip: disableTooltip);
disableTooltip: disableTooltip,
radius: radius);
}

if (disableTooltip) {
return InteractiveAvatar(chatNick: nick ?? uid);
return InteractiveAvatar(chatNick: nick ?? uid, radius: radius);
}

return Tooltip(
message: "Unknown user $uid",
child: InteractiveAvatar(chatNick: nick ?? uid),
child: InteractiveAvatar(chatNick: nick ?? uid, radius: radius),
);
}
}

class UserNickFromID extends StatelessWidget {
final String uid;
final TextSize? textSize;
const UserNickFromID(this.uid, {this.textSize, super.key});

@override
Widget build(BuildContext context) {
String nick = "";
var client = Provider.of<ClientModel>(context, listen: false);
var chat = client.getExistingChat(uid);
if (chat != null) {
nick = chat.nick;
} else if (uid == client.publicID) {
nick = "me (${client.nick})";
}
return Txt(nick, size: textSize);
}
}
2 changes: 2 additions & 0 deletions bruig/flutterui/bruig/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:bruig/screens/contacts_msg_times.dart';
import 'package:bruig/screens/fetch_invite.dart';
import 'package:bruig/screens/gc_invitations.dart';
import 'package:bruig/screens/generate_invite.dart';
import 'package:bruig/screens/list_kxs.dart';
import 'package:bruig/screens/log.dart';
import 'package:bruig/screens/onboarding.dart';
import 'package:bruig/screens/server_unwelcome_error.dart';
Expand Down Expand Up @@ -475,6 +476,7 @@ class _AppState extends State<App> with WindowListener {
builder: (context, theme, child) => ThemeTestScreen(theme)),
GCInvitationsScreen.routeName: (context) =>
const GCInvitationsScreen(),
ListKXsScreen.routeName: (context) => const ListKXsScreen(),
ShutdownScreen.routeName: (context) =>
ShutdownScreen(widget.log, widget.shutdown),
},
Expand Down
82 changes: 82 additions & 0 deletions bruig/flutterui/bruig/lib/screens/list_kxs.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import 'package:bruig/components/copyable.dart';
import 'package:bruig/components/info_grid.dart';
import 'package:bruig/components/interactive_avatar.dart';
import 'package:bruig/components/snackbars.dart';
import 'package:bruig/components/text.dart';
import 'package:bruig/models/client.dart';
import 'package:bruig/screens/startupscreen.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:golib_plugin/definitions.dart';
import 'package:golib_plugin/golib_plugin.dart';
import 'package:provider/provider.dart';

class ListKXsScreen extends StatefulWidget {
static const routeName = "/listKXs";

const ListKXsScreen({super.key});

@override
State<ListKXsScreen> createState() => _ListKXsScreenState();
}

class _ListKXsScreenState extends State<ListKXsScreen> {
List<KXData> kxs = [];

void listKXs() async {
try {
var newKXs = await Golib.listKXs();
newKXs.sortBy((v) => v.timestamp);
newKXs.reverseRange(0, newKXs.length);
setState(() => kxs = newKXs);
} catch (exception) {
showErrorSnackbar(this, "Unable to list KXs: $exception");
}
}

@override
void initState() {
super.initState();
listKXs();
}

@override
Widget build(BuildContext context) {
var client = Provider.of<ClientModel>(context, listen: false);

return StartupScreen([
kxs.isNotEmpty
? const Txt.H("List of Ongoing KX Attempts")
: const Txt.L("No KX attempt in progress"),
const SizedBox(height: 30),
...kxs.map<Widget>((kx) => Container(
padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 10),
child: SimpleInfoGridAdv(items: [
["For Reset?", "${kx.isForReset}"],
["Stage", "${kx.stage}"],
["Updated", "${kx.timestamp}"],
["Initial RV", Copyable(kx.initialRV)],
["Target Nick", kx.invitee?.nick ?? ""],
["Target ID", Copyable(kx.invitee?.identity ?? "")],
["Mediator ID", Copyable(kx.mediatorID ?? "")],
[
"Mediator",
kx.mediatorID != null && kx.mediatorID != ""
? Row(children: [
UserAvatarFromID(client, kx.mediatorID!, radius: 10),
const SizedBox(width: 10),
UserNickFromID(kx.mediatorID!)
])
: ""
],
["My Reset RV", Copyable(kx.myResetRV)],
]))),
const SizedBox(height: 10),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text("Done"))
]);
}
}
15 changes: 13 additions & 2 deletions bruig/flutterui/bruig/lib/screens/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:bruig/models/snackbar.dart';
import 'package:bruig/models/uistate.dart';
import 'package:bruig/notification_service.dart';
import 'package:bruig/screens/config_network.dart';
import 'package:bruig/screens/list_kxs.dart';
import 'package:bruig/screens/ln_management.dart';
import 'package:bruig/screens/log.dart';
import 'package:bruig/screens/manage_content/manage_content.dart';
Expand Down Expand Up @@ -125,6 +126,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
}
}

void listKXs() {
Navigator.of(context, rootNavigator: true)
.pushNamed(ListKXsScreen.routeName);
}

void changePage(String newPage) {
setState(() {
client.ui.settingsTitle.title = newPage;
Expand Down Expand Up @@ -168,7 +174,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
switch (settingsPage) {
case "Account":
settingsView = AccountSettingsScreen(client, resetAllOldKX1s,
resetAllOldKX, pickAvatarFile, subAllPosts);
resetAllOldKX, pickAvatarFile, subAllPosts, listKXs);
break;
case "Appearance":
settingsView = Consumer<ThemeNotifier>(
Expand Down Expand Up @@ -321,8 +327,9 @@ class AccountSettingsScreen extends StatelessWidget {
final ResetKXCB resetKXCB;
final VoidCallback subAllPostsCB;
final VoidCallback pickAvatarCB;
final VoidCallback listKXs;
const AccountSettingsScreen(this.client, this.resetAllKXCB, this.resetKXCB,
this.pickAvatarCB, this.subAllPostsCB,
this.pickAvatarCB, this.subAllPostsCB, this.listKXs,
{super.key});

@override
Expand Down Expand Up @@ -352,6 +359,10 @@ class AccountSettingsScreen extends StatelessWidget {
title: const Text("Subscribe to all posts"),
onTap: () => subAllPostsCB(),
),
ListTile(
title: const Text("List ongoing KX attempts"),
onTap: () => listKXs(),
),
]))
]);
}
Expand Down
57 changes: 57 additions & 0 deletions bruig/flutterui/plugin/lib/definitions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2217,6 +2217,50 @@ class UINotificationsConfig {
Map<String, dynamic> toJson() => _$UINotificationsConfigToJson(this);
}

enum KXStage {
@JsonValue(0)
unknown,
@JsonValue(1)
step2IdKX,
@JsonValue(2)
step3IDKX,
}

@JsonSerializable()
class KXData {
final PublicIdentity? public;
@JsonKey(name: "initial_rv")
final String initialRV;
@JsonKey(name: "step3_rv")
final String step3RV;
@JsonKey(name: "my_resetrv")
final String myResetRV;
@JsonKey(name: "their_resetrv")
final String theirResetRV;
@JsonKey(name: "stage")
final KXStage stage;
final DateTime timestamp;
final PublicIdentity? invitee;
@JsonKey(name: "is_for_reset")
final bool isForReset;
@JsonKey(name: "mediator_id")
final String? mediatorID;

KXData(
this.public,
this.initialRV,
this.step3RV,
this.myResetRV,
this.theirResetRV,
this.stage,
this.timestamp,
this.invitee,
this.isForReset,
this.mediatorID);

factory KXData.fromJson(Map<String, dynamic> json) => _$KXDataFromJson(json);
}

mixin NtfStreams {
StreamController<RemoteUser> ntfAcceptedInvites =
StreamController<RemoteUser>();
Expand Down Expand Up @@ -3250,6 +3294,18 @@ abstract class PluginPlatform {

return (res as List).map<String>((v) => v as String).toList();
}

Future<List<KXData>> listKXs() async {
// jsonToList(await asyncCall(CTListKXs, null), KXData.fromJson);
var res = await asyncCall(
CTListKXs, null);
if (res == null) {
return List.empty();
}
return (res as List)
.map<KXData>((v) => KXData.fromJson(v))
.toList();
}
}

const int CTUnknown = 0x00;
Expand Down Expand Up @@ -3384,6 +3440,7 @@ const int CTCancelDownload = 0x8c;
const int CTSubAllPosts = 0x8d;
const int CTUpdateUINotificationsCfg = 0x8e;
const int CTGCListUnkxdMembers = 0x8f;
const int CTListKXs = 0x90;

const int notificationsStartID = 0x1000;

Expand Down
36 changes: 36 additions & 0 deletions bruig/flutterui/plugin/lib/definitions.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5778917

Please sign in to comment.