diff --git a/nomadnet/ui/TextUI.py b/nomadnet/ui/TextUI.py index c6700b9..d41981f 100644 --- a/nomadnet/ui/TextUI.py +++ b/nomadnet/ui/TextUI.py @@ -20,7 +20,7 @@ THEMES = { # Style name # 16-color style # Monochrome style # 88, 256 and true-color style ('heading', 'light gray,underline', 'default', 'underline', 'g93,underline', 'default'), ('menubar', 'black', 'light gray', 'standout', '#111', '#bbb'), - ('scrollbar', 'black', 'light gray', 'standout', '#444', 'default'), + ('scrollbar', 'light gray', 'default', 'standout', '#444', 'default'), ('shortcutbar', 'black', 'light gray', 'standout', '#111', '#bbb'), ('body_text', 'white', 'default', 'default', '#ddd', 'default'), ('error_text', 'dark red', 'default', 'default', 'dark red', 'default'), @@ -38,10 +38,13 @@ THEMES = { ("list_off_focus", "black", "dark gray", "standout", "#111", "dark gray"), ("list_trusted", "light green", "default", "default", "#6b2", "default"), ("list_focus_trusted", "black", "light gray", "standout", "#180", "#bbb"), - ("list_unknown", "dark gray", "default", "default", "light gray", "default"), - ("list_normal", "dark gray", "default", "default", "light gray", "default"), + ("list_unknown", "dark gray", "default", "default", "#bbb", "default"), + ("list_normal", "dark gray", "default", "default", "#bbb", "default"), ("list_untrusted", "dark red", "default", "default", "dark red", "default"), ("list_focus_untrusted", "black", "light gray", "standout", "#810", "#bbb"), + ("topic_list_normal", "white", "default", "default", "#ddd", "default"), + ("progress_full", "black", "light gray", "standout", "#111", "#bbb"), + ("progress_empty", "light gray", "default", "default", "#ddd", "default"), ], } } @@ -68,6 +71,8 @@ GLYPHS = { ("divider1", "-", "\u2504", "\u2504"), ("peer", "P", "\U0001F464", "\uf415"), ("node", "N", "\U0001F5A5", "\uf502"), + ("page", "", "\U0001F5B9", "\uf719 "), + ("speed", "", "\U0001F5B9", "\uf9c4"), ("decoration_menu", "", "", " \uf93a"), } diff --git a/nomadnet/ui/textui/Browser.py b/nomadnet/ui/textui/Browser.py index 4e506b6..88d467c 100644 --- a/nomadnet/ui/textui/Browser.py +++ b/nomadnet/ui/textui/Browser.py @@ -53,6 +53,9 @@ class Browser: self.link = None self.status = Browser.DISCONECTED + self.response_progress = 0 + self.response_size = None + self.response_transfer_size = None self.page_data = None self.displayed_page_data = None self.auth_identity = auth_identity @@ -78,7 +81,7 @@ class Browser: return RNS.hexrep(self.destination_hash, delimit=False)+":"+path def handle_link(self, link_target): - RNS.log("Browser handling link to: "+str(link_target)) + RNS.log("Browser handling link to: "+str(link_target), RNS.LOG_DEBUG) try: self.retrieve_url(link_target) except Exception as e: @@ -101,7 +104,13 @@ class Browser: self.display_widget = urwid.AttrMap(urwid.LineBox(self.frame, title="Remote Node"), "inactive_text") def make_status_widget(self): - return urwid.Pile([urwid.Divider(self.g["divider1"]), urwid.Text(self.status_text())]) + if self.response_progress > 0: + pb = ResponseProgressBar("progress_empty" , "progress_full", current=self.response_progress, done=1.0, satt=None) + widget = urwid.Pile([urwid.Divider(self.g["divider1"]), pb]) + else: + widget = urwid.Pile([urwid.Divider(self.g["divider1"]), urwid.Text(self.status_text())]) + + return widget def make_control_widget(self): return urwid.Pile([urwid.Text(self.g["node"]+" "+self.current_url()), urwid.Divider(self.g["divider1"])]) @@ -119,9 +128,14 @@ class Browser: ("weight", 0.5, urwid.Text(" ")) ]) - pile = urwid.Pile([ - urwid.Text("!\n\n"+self.status_text()+"\n", align="center"), - columns + if len(self.attr_maps) > 0: + pile = urwid.Pile([ + urwid.Text("!\n\n"+self.status_text()+"\n", align="center"), + columns + ]) + else: + pile = urwid.Pile([ + urwid.Text("!\n\n"+self.status_text(), align="center") ]) return urwid.Filler(pile, "middle") @@ -139,16 +153,21 @@ class Browser: if self.status == Browser.DONE: self.browser_footer = self.make_status_widget() self.update_page_display() + elif self.status <= Browser.REQUEST_SENT: if len(self.attr_maps) == 0: self.browser_body = urwid.Filler(urwid.Text("Retrieving\n["+self.current_url()+"]", align="center"), "middle") + self.browser_footer = self.make_status_widget() + elif self.status == Browser.REQUEST_FAILED: self.browser_body = self.make_request_failed_widget() self.browser_footer = urwid.Text("") + elif self.status == Browser.REQUEST_TIMEOUT: self.browser_body = self.make_request_failed_widget() self.browser_footer = urwid.Text("") + else: pass @@ -172,6 +191,10 @@ class Browser: self.attr_maps = [] self.status = Browser.DISCONECTED + self.response_progress = 0 + self.response_size = None + self.response_transfer_size = None + self.update_display() @@ -264,6 +287,7 @@ class Browser: now = time.time() if now > pr_time+self.timeout: self.request_timeout() + return time.sleep(0.25) @@ -286,6 +310,7 @@ class Browser: now = time.time() if now > l_time+self.timeout: self.request_timeout() + return time.sleep(0.25) @@ -293,12 +318,17 @@ class Browser: # Send the request self.status = Browser.REQUESTING + self.response_progress = 0 + self.response_size = None + self.response_transfer_size = None + self.update_display() receipt = self.link.request( self.path, data = None, response_callback = self.response_received, failed_callback = self.request_failed, + progress_callback = self.response_progressed, timeout = self.timeout ) @@ -328,6 +358,8 @@ class Browser: self.page_data = request_receipt.response self.markup = self.page_data.decode("utf-8") self.attr_maps = markup_to_attrmaps(self.markup, url_delegate=self) + self.response_progress = 0 + self.update_display() except Exception as e: RNS.log("An error occurred while handling response. The contained exception was: "+str(e)) @@ -337,18 +369,46 @@ class Browser: if request_receipt != None: if request_receipt.request_id == self.last_request_id: self.status = Browser.REQUEST_FAILED + self.response_progress = 0 + self.response_size = None + self.response_transfer_size = None + self.update_display() else: self.status = Browser.REQUEST_FAILED + self.response_progress = 0 + self.response_size = None + self.response_transfer_size = None + self.update_display() def request_timeout(self, request_receipt=None): self.status = Browser.REQUEST_TIMEOUT + self.response_progress = 0 + self.response_size = None + self.response_transfer_size = None + + self.update_display() + + + def response_progressed(self, request_receipt): + self.response_progress = request_receipt.progress + self.response_time = request_receipt.response_time() + self.response_size = request_receipt.response_size + self.response_transfer_size = request_receipt.response_transfer_size self.update_display() def status_text(self): + if self.response_transfer_size != None: + response_time_str = "{:.2f}".format(self.response_time) + stats_string = " "+self.g["page"]+size_str(self.response_size) + stats_string += " "+self.g["arrow_d"]+size_str(self.response_transfer_size)+" in "+response_time_str + stats_string += "s "+self.g["speed"]+size_str(self.response_transfer_size/self.response_time, suffix="b")+"/s" + else: + stats_string = "" + if self.status == Browser.NO_PATH: return "No path to destination known" elif self.status == Browser.PATH_REQUESTED: @@ -368,10 +428,30 @@ class Browser: elif self.status == Browser.RECEIVING_RESPONSE: return "Receiving response..." elif self.status == Browser.DONE: - return "Done" + return "Done"+stats_string elif self.status == Browser.DISCONECTED: return "Disconnected" else: return "Browser Status Unknown" - \ No newline at end of file + +class ResponseProgressBar(urwid.ProgressBar): + def get_text(self): + return "Receiving response "+super().get_text() + +# A convenience function for printing a human- +# readable file size +def size_str(num, suffix='B'): + units = ['','K','M','G','T','P','E','Z'] + last_unit = 'Y' + + if suffix == 'b': + num *= 8 + units = ['','K','M','G','T','P','E','Z'] + last_unit = 'Y' + + for unit in units: + if abs(num) < 1000.0: + return "%3.2f %s%s" % (num, unit, suffix) + num /= 1000.0 + return "%.2f %s%s" % (num, last_unit, suffix) \ No newline at end of file diff --git a/nomadnet/ui/textui/Guide.py b/nomadnet/ui/textui/Guide.py index 78352a8..5db5222 100644 --- a/nomadnet/ui/textui/Guide.py +++ b/nomadnet/ui/textui/Guide.py @@ -70,7 +70,7 @@ class GuideEntry(urwid.WidgetWrap): widget = ListEntry(topic_name) urwid.connect_signal(widget, "click", self.display_topic, topic_name) - style = "list_normal" + style = "topic_list_normal" focus_style = "list_focus" self.display_widget = urwid.AttrMap(widget, style, focus_style) urwid.WidgetWrap.__init__(self, self.display_widget) @@ -155,12 +155,6 @@ TOPIC_INTRODUCTION = '''>Nomad Network `c`*Communicate Freely.`* `a -TODO: REMOVE -This is a `F07flink `[With a label`344858860838a8d9f8ed:/page/test] to some resource`f. -This is a link `*`[With a label`:/page/test]`* to some resource. -This is a link `[With a label`:] to some resource. -This is a link `*`[With a label`344858860838a8d9f8ed] to some`* resource. - The intention with this program is to provide a tool to that allows you to build private and resilient communications platforms that are in complete control and ownership of the people that use them. Nomad Network is build on LXMF and Reticulum, which together provides the cryptographic mesh functionality and peer-to-peer message routing that Nomad Network relies on. This foundation also makes it possible to use the program over a very wide variety of communication mediums, from packet radio to gigabit fiber. @@ -417,9 +411,13 @@ TOPIC_MARKUP += "\n`=\n\n>Closing Remarks\n\nIf you made it all the way here, yo TOPIC_FIRST_RUN = '''>First Time Information -Hi there. This first run message will only appear once. It contains a few pointers on getting started with Nomad Network, and getting the most out of the program. You're currently located in the guide section of the program. I'm sorry I had to drag you here by force, but it will only happen this one time, I promise. If you ever get lost, return here and peruse the list of topics you see on the left. I will do my best to fill it with answers to mostly anything about Nomad Network. +Hi there. This first run message will only appear once. It contains a few pointers on getting started with Nomad Network, and getting the most out of the program. -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. By default, Nomad Network starts in low-color mode. It does this for the sake of compatibility, but it does look rather ugly. If your terminal supports true-color or just 256 colors, you should go to the `![ Config ]`! menu item, launch the editor and change the configuration to use a high-color mode. +You're currently located in the guide section of the program. I'm sorry I had to drag you here by force, but it will only happen this one time, I promise. If you ever get lost, return here and peruse the list of topics you see on the left. I will do my best to fill it with answers to mostly anything about Nomad Network. + +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. + +By default, Nomad Network starts in low-color mode. It does this for the sake of compatibility, but it does look rather ugly. If your terminal supports true-color or just 256 colors, you should go to the `![ Config ]`! menu item, launch the editor and change the configuration to use a high-color mode. 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. diff --git a/nomadnet/ui/textui/MicronParser.py b/nomadnet/ui/textui/MicronParser.py index 8ee451f..cd1582b 100644 --- a/nomadnet/ui/textui/MicronParser.py +++ b/nomadnet/ui/textui/MicronParser.py @@ -291,7 +291,6 @@ def make_output(state, line, url_delegate): specname = make_style(state) speclist = SYNTH_SPECS[specname] - orig_spec = urwid.AttrSpec('underline', 'default', cm) if cm == 1: orig_spec = speclist[0] elif cm == 16: diff --git a/setup.py b/setup.py index fd9d70c..2ff3653 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,6 @@ setuptools.setup( entry_points= { 'console_scripts': ['nomadnet=nomadnet.nomadnet:main'] }, - install_requires=['rns>=0.2.2', 'lxmf>=0.0.6', 'urwid>=2.1.2'], - python_requires='>=3.5', + install_requires=['rns>=0.2.3', 'lxmf>=0.0.7', 'urwid>=2.1.2'], + python_requires='>=3.6', ) \ No newline at end of file