From 686ca41b4e25a75475c7c27f69a85a37e5ccad17 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Thu, 4 Nov 2021 21:51:11 +0100 Subject: [PATCH] UI improvement in small terminals. Urwid bug mitigation. --- nomadnet/NomadNetworkApp.py | 15 +++++++++++++++ nomadnet/_version.py | 2 +- nomadnet/ui/textui/Conversations.py | 2 +- nomadnet/ui/textui/Guide.py | 2 ++ nomadnet/ui/textui/Main.py | 1 + nomadnet/ui/textui/Network.py | 27 +++++++++++++++++++++------ 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/nomadnet/NomadNetworkApp.py b/nomadnet/NomadNetworkApp.py index ba7465d..42e1d91 100644 --- a/nomadnet/NomadNetworkApp.py +++ b/nomadnet/NomadNetworkApp.py @@ -1,6 +1,8 @@ import os +import sys import time import atexit +import traceback import RNS import LXMF @@ -25,6 +27,18 @@ class NomadNetworkApp: self.directory.save_to_disk() RNS.log("Nomad Network Client exiting now", RNS.LOG_VERBOSE) + def exception_handler(self, e_type, e_value, e_traceback): + RNS.log("An unhandled exception occurred, the details of which will be dumped below", RNS.LOG_ERROR) + RNS.log("Type : "+str(e_type), RNS.LOG_ERROR) + RNS.log("Value : "+str(e_value), RNS.LOG_ERROR) + t_string = "" + for line in traceback.format_tb(e_traceback): + t_string += line + RNS.log("Trace : \n"+t_string, RNS.LOG_ERROR) + + if issubclass(e_type, KeyboardInterrupt): + sys.__excepthook__(e_type, e_value, e_traceback) + def __init__(self, configdir = None, rnsconfigdir = None): self.version = __version__ self.enable_client = False @@ -194,6 +208,7 @@ class NomadNetworkApp: self.announce_now() atexit.register(self.exit_handler) + sys.excepthook = self.exception_handler nomadnet.ui.spawn(self.uimode) diff --git a/nomadnet/_version.py b/nomadnet/_version.py index 51e0a06..de49d1f 100644 --- a/nomadnet/_version.py +++ b/nomadnet/_version.py @@ -1 +1 @@ -__version__ = "0.1.4" \ No newline at end of file +__version__ = "0.1.5" \ No newline at end of file diff --git a/nomadnet/ui/textui/Conversations.py b/nomadnet/ui/textui/Conversations.py index 43eda8e..1c9f36f 100644 --- a/nomadnet/ui/textui/Conversations.py +++ b/nomadnet/ui/textui/Conversations.py @@ -98,7 +98,7 @@ class ConversationsDisplay(): highlight_offFocus="list_off_focus" ) - self.listbox = ConversationsArea(urwid.Filler(self.ilb, height=("relative", 100))) + self.listbox = ConversationsArea(urwid.Filler(self.ilb, height=("relative", 100)), title="Conversations") self.listbox.delegate = self def delete_selected_conversation(self): diff --git a/nomadnet/ui/textui/Guide.py b/nomadnet/ui/textui/Guide.py index 9be9868..e6c9867 100644 --- a/nomadnet/ui/textui/Guide.py +++ b/nomadnet/ui/textui/Guide.py @@ -302,6 +302,8 @@ You're currently located in the guide section of the program. I'm sorry I had to To get the most out of Nomad Network, you will need a terminal that supports UTF-8 and at least 256 colors, ideally true-color. If your terminal supports true-color, you can go to the `![ Config ]`! menu item, launch the editor and change the configuration. +It is recommended to use a terminal size of at least 122x32. Nomad Network will work with smaller terminal sizes, but the interface might feel a bit cramped. + If you don't already have a Nerd Font installed (see https://www.nerdfonts.com/), I also highly recommend to do so, since it will greatly expand the amount of glyphs, icons and graphics that Nomad Network can use. Once you have your terminal set up with a Nerd Font, go to the `![ Config ]`! menu item and enable Nerd Fonts in the configuration instead of normal unicode glyphs. Nomad Network expects that you are already connected to some form of Reticulum network. That could be as simple as the default UDP-based demo interface on your local ethernet network. This short guide won't go into any details on building networks, but you will find other entries in the guide that deal with network setup and configuration. diff --git a/nomadnet/ui/textui/Main.py b/nomadnet/ui/textui/Main.py index deca22a..68e7235 100644 --- a/nomadnet/ui/textui/Main.py +++ b/nomadnet/ui/textui/Main.py @@ -125,6 +125,7 @@ class MainDisplay(): def update_active_sub_display(self): self.frame.contents["body"] = (self.sub_displays.active().widget, None) self.update_active_shortcuts() + self.app.ui.main_display.request_redraw(extra_delay=0.0) def update_active_shortcuts(self): self.frame.contents["footer"] = (self.sub_displays.active().shortcuts().widget, None) diff --git a/nomadnet/ui/textui/Network.py b/nomadnet/ui/textui/Network.py index c47d5c1..4e4ca4b 100644 --- a/nomadnet/ui/textui/Network.py +++ b/nomadnet/ui/textui/Network.py @@ -107,7 +107,7 @@ class AnnounceInfo(urwid.WidgetWrap): self.parent.left_pile.contents[0] = (self.parent.announce_stream_display, options) def connect(sender): - self.app.ui.main_display.request_redraw(extra_delay=0.75) + self.app.ui.main_display.request_redraw(extra_delay=0.15) self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False)) show_announce_stream(None) @@ -255,7 +255,7 @@ class AnnounceStream(urwid.WidgetWrap): self.widget_list = [] self.update_widget_list() - self.ilb = IndicativeListBox( + self.ilb = ExceptionHandlingListBox( self.widget_list, on_selection_change=self.list_selection, initialization_is_selection_change=False, @@ -434,7 +434,7 @@ class KnownNodeInfo(urwid.WidgetWrap): self.parent.left_pile.contents[0] = (self.parent.known_nodes_display, options) def connect(sender): - self.app.ui.main_display.request_redraw(extra_delay=0.75) + self.app.ui.main_display.request_redraw(extra_delay=0.15) self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False)) show_known_nodes(None) @@ -498,6 +498,21 @@ class KnownNodeInfo(urwid.WidgetWrap): urwid.WidgetWrap.__init__(self, urwid.LineBox(self.display_widget, title="Node Info")) +# Yes, this is weird. There is a bug in Urwid/ILB that causes +# an indexing exception when the list is very small vertically. +# This mitigates it. +class ExceptionHandlingListBox(IndicativeListBox): + def keypress(self, size, key): + try: + return super(ExceptionHandlingListBox, self).keypress(size, key) + + except Exception as e: + if key == "up": + nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.frame.set_focus("header") + elif key == "down": + nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.sub_displays.network_display.left_pile.set_focus(1) + + class KnownNodes(urwid.WidgetWrap): def __init__(self, app): self.app = app @@ -506,7 +521,7 @@ class KnownNodes(urwid.WidgetWrap): self.widget_list = self.make_node_widgets() - self.ilb = IndicativeListBox( + self.ilb = ExceptionHandlingListBox( self.widget_list, on_selection_change=self.node_list_selection, initialization_is_selection_change=False, @@ -684,7 +699,7 @@ class AnnounceTime(urwid.WidgetWrap): if self.app.peer_settings["last_announce"] != None: self.last_announce_string = pretty_date(int(self.app.peer_settings["last_announce"])) - self.display_widget.set_text("Last Announce : "+self.last_announce_string) + self.display_widget.set_text("Announced : "+self.last_announce_string) def update_time_callback(self, loop=None, user_data=None): self.update_time() @@ -1006,7 +1021,7 @@ class NetworkStats(urwid.WidgetWrap): def get_num_nodes(): return self.app.directory.number_of_known_nodes() - self.w_heard_peers = UpdatingText(self.app, "Heard Peers: ", get_num_peers, append_text=" (last 30m)") + self.w_heard_peers = UpdatingText(self.app, "Heard Peers: ", get_num_peers, append_text=" (30m)") self.w_known_nodes = UpdatingText(self.app, "Known Nodes: ", get_num_nodes) pile = urwid.Pile([