Compare commits

...

14 Commits
0.0.9 ... 0.1.1

Author SHA1 Message Date
Mark Qvist
b82cfce3f8 Announce stream update on unknown node announce 2021-09-25 17:19:26 +02:00
Mark Qvist
722cb35759 Glyph modification on Darwin 2021-09-25 17:13:18 +02:00
Mark Qvist
6da665f1c7 Glyph modification on Darwin 2021-09-25 17:11:52 +02:00
Mark Qvist
efc24d361b Added node saving from announce stream 2021-09-25 16:57:29 +02:00
Mark Qvist
848514ec54 Fixed potential None reference 2021-09-25 15:47:42 +02:00
Mark Qvist
3a4d7eed82 Updated RNS dependency 2021-09-24 16:59:53 +02:00
Mark Qvist
f2e7e098f9 Added browser cache cleanup on startup. 2021-09-23 19:04:52 +02:00
Mark Qvist
ee6cc9fd4f Improved conversation sorting 2021-09-23 17:45:01 +02:00
Mark Qvist
398c3c3504 Updated version 2021-09-23 17:20:46 +02:00
Mark Qvist
f86cdb4c5e Added unread indicator to menu bar. 2021-09-23 17:20:13 +02:00
Mark Qvist
953c8c94c7 Fixed browser view on non node hosting instances. 2021-09-19 00:30:07 +02:00
Mark Qvist
0c94dfa482 Updated version 2021-09-19 00:27:19 +02:00
Mark Qvist
08f1d4cda7 Fixed node info view on non node hosting instances. 2021-09-19 00:25:13 +02:00
Mark Qvist
718e2ca859 Fixed None reference 2021-09-19 00:15:26 +02:00
10 changed files with 171 additions and 79 deletions

View File

@@ -236,6 +236,7 @@ class ConversationMessage:
self.lxm = LXMF.LXMessage.unpack_from_file(open(self.file_path, "rb")) self.lxm = LXMF.LXMessage.unpack_from_file(open(self.file_path, "rb"))
self.loaded = True self.loaded = True
self.timestamp = self.lxm.timestamp self.timestamp = self.lxm.timestamp
self.sort_timestamp = os.path.getmtime(self.file_path)
if self.lxm.state > LXMF.LXMessage.DRAFT and self.lxm.state < LXMF.LXMessage.SENT: if self.lxm.state > LXMF.LXMessage.DRAFT and self.lxm.state < LXMF.LXMessage.SENT:
found = False found = False

View File

@@ -87,6 +87,7 @@ class Directory:
if self.trust_level(associated_peer) == DirectoryEntry.TRUSTED: if self.trust_level(associated_peer) == DirectoryEntry.TRUSTED:
node_entry = DirectoryEntry(source_hash, display_name=app_data.decode("utf-8"), trust_level=DirectoryEntry.TRUSTED, hosts_node=True) node_entry = DirectoryEntry(source_hash, display_name=app_data.decode("utf-8"), trust_level=DirectoryEntry.TRUSTED, hosts_node=True)
self.remember(node_entry) self.remember(node_entry)
self.app.ui.main_display.sub_displays.network_display.directory_change_callback() self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def remove_announce_with_timestamp(self, timestamp): def remove_announce_with_timestamp(self, timestamp):

View File

@@ -223,6 +223,12 @@ class NomadNetworkApp:
def conversations(self): def conversations(self):
return nomadnet.Conversation.conversation_list(self) return nomadnet.Conversation.conversation_list(self)
def has_unread_conversations(self):
if len(nomadnet.Conversation.unread_conversations) > 0:
return True
else:
return False
def conversation_is_unread(self, source_hash): def conversation_is_unread(self, source_hash):
if bytes.fromhex(source_hash) in nomadnet.Conversation.unread_conversations: if bytes.fromhex(source_hash) in nomadnet.Conversation.unread_conversations:
return True return True
@@ -430,8 +436,8 @@ announce_at_start = yes
intro_time = 1 intro_time = 1
# You can specify the display theme. # You can specify the display theme.
# theme = dark # theme = light
theme = light theme = dark
# Specify the number of colors to use # Specify the number of colors to use
# valid colormodes are: # valid colormodes are:
@@ -486,12 +492,12 @@ enable_node = no
node_name = None node_name = None
# Automatic announce interval in minutes. # Automatic announce interval in minutes.
# 12 hours by default. # 6 hours by default.
announce_interval = 720 announce_interval = 360
# Whether to announce when the node starts # Whether to announce when the node starts
announce_at_start = No announce_at_start = Yes
'''.splitlines() '''.splitlines()

View File

@@ -1 +1 @@
__version__ = "0.0.9" __version__ = "0.1.1"

View File

@@ -2,6 +2,7 @@ import RNS
import urwid import urwid
import time import time
import os import os
import platform
import nomadnet import nomadnet
from nomadnet.ui.textui import * from nomadnet.ui.textui import *
@@ -90,6 +91,13 @@ GLYPHSETS = {
"nerdfont": 3 "nerdfont": 3
} }
if platform.system() == "Darwin":
urm_char = " \uf0e0 "
ur_char = "\uf0e0 "
else:
urm_char = " \uf003 "
ur_char = "\uf003 "
GLYPHS = { GLYPHS = {
# Glyph name # Plain # Unicode # Nerd Font # Glyph name # Plain # Unicode # Nerd Font
("check", "=", "\u2713", "\u2713"), ("check", "=", "\u2713", "\u2713"),
@@ -103,13 +111,14 @@ GLYPHS = {
("arrow_d", "\\/", "\u2193", "\u2193"), ("arrow_d", "\\/", "\u2193", "\u2193"),
("warning", "!", "\u26a0", "\uf12a"), ("warning", "!", "\u26a0", "\uf12a"),
("info", "i", "\u2139", "\ufb4d"), ("info", "i", "\u2139", "\ufb4d"),
("unread", "[U]", "\u2709", "\uf003 "), ("unread", "[!]", "\u2709", ur_char),
("divider1", "-", "\u2504", "\u2504"), ("divider1", "-", "\u2504", "\u2504"),
("peer", "[P]", "\u24c5 ", "\uf415"), ("peer", "[P]", "\u24c5 ", "\uf415"),
("node", "[N]", "\u24c3 ", "\uf502"), ("node", "[N]", "\u24c3 ", "\uf502"),
("page", "", "\u25a4", "\uf719 "), ("page", "", "\u25a4", "\uf719 "),
("speed", "", "\u25F7", "\uf9c4"), ("speed", "", "\u25F7", "\uf9c4"),
("decoration_menu", "", "", " \uf93a"), ("decoration_menu", " +", " +", " \uf93a"),
("unread_menu", " !", " \u2709", urm_char),
("globe", "", "", "\uf484"), ("globe", "", "", "\uf484"),
} }
@@ -183,6 +192,7 @@ class TextUI:
self.set_colormode(colormode) self.set_colormode(colormode)
self.main_display.start()
self.loop.run() self.loop.run()
def set_colormode(self, colormode): def set_colormode(self, colormode):

View File

@@ -90,6 +90,8 @@ class Browser:
if self.destination_hash != None: if self.destination_hash != None:
self.load_page() self.load_page()
self.clean_cache()
def current_url(self): def current_url(self):
if self.destination_hash == None: if self.destination_hash == None:
return "" return ""
@@ -201,8 +203,12 @@ class Browser:
else: else:
self.display_widget.set_attr_map({None: "body_text"}) self.display_widget.set_attr_map({None: "body_text"})
self.browser_header = self.make_control_widget() self.browser_header = self.make_control_widget()
if self.destination_hash != None:
remote_display_string = self.app.directory.simplest_display_str(self.destination_hash) remote_display_string = self.app.directory.simplest_display_str(self.destination_hash)
if remote_display_string == RNS.prettyhexrep(self.loopback): else:
remote_display_string = ""
if self.loopback != None and remote_display_string == RNS.prettyhexrep(self.loopback):
remote_display_string = self.app.node.name remote_display_string = self.app.node.name
self.linebox.set_title(remote_display_string) self.linebox.set_title(remote_display_string)
@@ -697,6 +703,22 @@ class Browser:
return None return None
def clean_cache(self):
files = os.listdir(self.app.cachepath)
for file in files:
cachepath = self.app.cachepath+"/"+file
try:
components = file.split("_")
if len(components) == 2 and len(components[0]) == 64 and len(components[1]) > 0:
expires = float(components[1])
if time.time() > expires:
RNS.log("Removing stale cache entry "+str(file), RNS.LOG_DEBUG)
os.unlink(cachepath)
except Exception as e:
pass
def cache_page(self, cache_time): def cache_page(self, cache_time):
url_hash = self.url_hash(self.current_url()) url_hash = self.url_hash(self.current_url())

View File

@@ -316,6 +316,7 @@ class ConversationsDisplay():
self.ilb.select_item(ilb_position) self.ilb.select_item(ilb_position)
nomadnet.NomadNetworkApp.get_shared_instance().ui.loop.draw_screen() nomadnet.NomadNetworkApp.get_shared_instance().ui.loop.draw_screen()
if self.app.ui.main_display.sub_displays.active_display == self.app.ui.main_display.sub_displays.conversations_display:
if self.currently_displayed_conversation != None: if self.currently_displayed_conversation != None:
if self.app.conversation_is_unread(self.currently_displayed_conversation): if self.app.conversation_is_unread(self.currently_displayed_conversation):
self.app.mark_conversation_read(self.currently_displayed_conversation) self.app.mark_conversation_read(self.currently_displayed_conversation)
@@ -422,7 +423,8 @@ class ConversationsDisplay():
if trust_level != DirectoryEntry.TRUSTED: if trust_level != DirectoryEntry.TRUSTED:
display_text += " <"+source_hash+">" display_text += " <"+source_hash+">"
else:
if trust_level != DirectoryEntry.UNTRUSTED:
if unread: if unread:
if source_hash != self.currently_displayed_conversation: if source_hash != self.currently_displayed_conversation:
display_text += " "+g["unread"] display_text += " "+g["unread"]
@@ -664,7 +666,7 @@ class ConversationWidget(urwid.WidgetWrap):
message_widget = LXMessageWidget(message) message_widget = LXMessageWidget(message)
self.message_widgets.append(message_widget) self.message_widgets.append(message_widget)
self.message_widgets.sort(key=lambda m: m.timestamp, reverse=False) self.message_widgets.sort(key=lambda m: m.sort_timestamp, reverse=False)
from nomadnet.vendor.additional_urwid_widgets import IndicativeListBox from nomadnet.vendor.additional_urwid_widgets import IndicativeListBox
self.messagelist = IndicativeListBox(self.message_widgets, position = len(self.message_widgets)-1) self.messagelist = IndicativeListBox(self.message_widgets, position = len(self.message_widgets)-1)
@@ -698,6 +700,7 @@ class LXMessageWidget(urwid.WidgetWrap):
app = nomadnet.NomadNetworkApp.get_shared_instance() app = nomadnet.NomadNetworkApp.get_shared_instance()
g = app.ui.glyphs g = app.ui.glyphs
self.timestamp = message.get_timestamp() self.timestamp = message.get_timestamp()
self.sort_timestamp = message.sort_timestamp
time_format = app.time_format time_format = app.time_format
message_time = datetime.fromtimestamp(self.timestamp) message_time = datetime.fromtimestamp(self.timestamp)
encryption_string = "" encryption_string = ""

View File

@@ -135,6 +135,9 @@ class MainDisplay():
def redraw_now(self, sender=None, data=None): def redraw_now(self, sender=None, data=None):
self.app.ui.loop.draw_screen() self.app.ui.loop.draw_screen()
def start(self):
self.menu_display.start()
def quit(self, sender=None): def quit(self, sender=None):
raise urwid.ExitMainLoop raise urwid.ExitMainLoop
@@ -147,11 +150,16 @@ class MenuColumns(urwid.Columns):
return super(MenuColumns, self).keypress(size, key) return super(MenuColumns, self).keypress(size, key)
class MenuDisplay(): class MenuDisplay():
UPDATE_INTERVAL = 2
def __init__(self, app, handler): def __init__(self, app, handler):
self.app = app self.app = app
g = self.app.ui.glyphs self.update_interval = MenuDisplay.UPDATE_INTERVAL
self.g = self.app.ui.glyphs
menu_text = ("pack", urwid.Text(g["decoration_menu"])) self.menu_indicator = urwid.Text("")
menu_text = ("pack", self.menu_indicator)
button_network = (11, MenuButton("Network", on_press=handler.show_network)) button_network = (11, MenuButton("Network", on_press=handler.show_network))
button_conversations = (17, MenuButton("Conversations", on_press=handler.show_conversations)) button_conversations = (17, MenuButton("Conversations", on_press=handler.show_conversations))
button_directory = (13, MenuButton("Directory", on_press=handler.show_directory)) button_directory = (13, MenuButton("Directory", on_press=handler.show_directory))
@@ -170,4 +178,25 @@ class MenuDisplay():
columns = MenuColumns(buttons, dividechars=1) columns = MenuColumns(buttons, dividechars=1)
columns.handler = handler columns.handler = handler
self.update_display()
self.widget = urwid.AttrMap(columns, "menubar") self.widget = urwid.AttrMap(columns, "menubar")
def start(self):
self.update_display_job()
def update_display_job(self, event = None, sender = None):
self.update_display()
self.app.ui.loop.set_alarm_in(self.update_interval, self.update_display_job)
def update_display(self):
if self.app.has_unread_conversations():
self.indicate_unread()
else:
self.indicate_normal()
def indicate_normal(self):
self.menu_indicator.set_text(self.g["decoration_menu"])
def indicate_unread(self):
self.menu_indicator.set_text(self.g["unread_menu"])

View File

@@ -110,6 +110,12 @@ class AnnounceInfo(urwid.WidgetWrap):
self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False)) self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False))
show_announce_stream(None) show_announce_stream(None)
def save_node(sender):
node_entry = DirectoryEntry(source_hash, display_name=data_str, trust_level=trust_level, hosts_node=True)
self.app.directory.remember(node_entry)
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
show_announce_stream(None)
def converse(sender): def converse(sender):
show_announce_stream(None) show_announce_stream(None)
try: try:
@@ -133,8 +139,15 @@ class AnnounceInfo(urwid.WidgetWrap):
if is_node: if is_node:
type_button = ("weight", 0.45, urwid.Button("Connect", on_press=connect)) type_button = ("weight", 0.45, urwid.Button("Connect", on_press=connect))
save_button = ("weight", 0.45, urwid.Button("Save", on_press=save_node))
else: else:
type_button = ("weight", 0.45, urwid.Button("Converse", on_press=converse)) type_button = ("weight", 0.45, urwid.Button("Converse", on_press=converse))
save_button = None
if is_node:
button_columns = urwid.Columns([("weight", 0.45, urwid.Button("Back", on_press=show_announce_stream)), ("weight", 0.1, urwid.Text("")), save_button, ("weight", 0.1, urwid.Text("")), type_button])
else:
button_columns = urwid.Columns([("weight", 0.45, urwid.Button("Back", on_press=show_announce_stream)), ("weight", 0.1, urwid.Text("")), type_button])
pile_widgets = [ pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"), urwid.Text("Time : "+ts_string, align="left"),
@@ -145,7 +158,7 @@ class AnnounceInfo(urwid.WidgetWrap):
urwid.Divider(g["divider1"]), urwid.Divider(g["divider1"]),
urwid.Text(["Announce Data: \n", (data_style, data_str)], align="left"), urwid.Text(["Announce Data: \n", (data_style, data_str)], align="left"),
urwid.Divider(g["divider1"]), urwid.Divider(g["divider1"]),
urwid.Columns([("weight", 0.45, urwid.Button("Back", on_press=show_announce_stream)), ("weight", 0.1, urwid.Text("")), type_button]) button_columns
] ]
if is_node: if is_node:
@@ -700,7 +713,19 @@ class NodeInfo(urwid.WidgetWrap):
g = self.app.ui.glyphs g = self.app.ui.glyphs
self.dialog_open = False self.dialog_open = False
widget_style = ""
def show_peer_info(sender):
options = self.parent.left_pile.options(height_type="pack", height_amount=None)
self.parent.left_pile.contents[2] = (LocalPeer(self.app, self.parent), options)
if self.app.enable_node:
if self.app.node != None:
display_name = self.app.node.name display_name = self.app.node.name
else:
display_name = None
if display_name == None: if display_name == None:
display_name = "" display_name = ""
@@ -731,10 +756,6 @@ class NodeInfo(urwid.WidgetWrap):
options = self.parent.left_pile.options(height_type="pack", height_amount=None) options = self.parent.left_pile.options(height_type="pack", height_amount=None)
self.parent.left_pile.contents[2] = (overlay, options) self.parent.left_pile.contents[2] = (overlay, options)
def show_peer_info(sender):
options = self.parent.left_pile.options(height_type="pack", height_amount=None)
self.parent.left_pile.contents[2] = (LocalPeer(self.app, self.parent), options)
def connect_query(sender): def connect_query(sender):
self.parent.browser.retrieve_url(RNS.hexrep(self.app.node.destination.hash, delimit=False)) self.parent.browser.retrieve_url(RNS.hexrep(self.app.node.destination.hash, delimit=False))
@@ -755,8 +776,6 @@ class NodeInfo(urwid.WidgetWrap):
announce_button = urwid.Button("Announce Now", on_press=announce_query) announce_button = urwid.Button("Announce Now", on_press=announce_query)
connect_button = urwid.Button("Browse", on_press=connect_query) connect_button = urwid.Button("Browse", on_press=connect_query)
widget_style = ""
if self.app.enable_node:
pile = urwid.Pile([ pile = urwid.Pile([
t_id, t_id,
e_name, e_name,
@@ -784,6 +803,7 @@ class NodeInfo(urwid.WidgetWrap):
urwid.WidgetWrap.__init__(self, urwid.AttrMap(urwid.LineBox(self.display_widget, title="Local Node Info"), widget_style)) urwid.WidgetWrap.__init__(self, urwid.AttrMap(urwid.LineBox(self.display_widget, title="Local Node Info"), widget_style))
def start(self): def start(self):
if self.app.node != None:
self.t_last_announce.start() self.t_last_announce.start()
self.t_active_links.start() self.t_active_links.start()

View File

@@ -23,6 +23,6 @@ setuptools.setup(
entry_points= { entry_points= {
'console_scripts': ['nomadnet=nomadnet.nomadnet:main'] 'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
}, },
install_requires=['rns>=0.2.5', 'lxmf>=0.0.9', 'urwid>=2.1.2'], install_requires=['rns>=0.2.6', 'lxmf>=0.0.9', 'urwid>=2.1.2'],
python_requires='>=3.6', python_requires='>=3.6',
) )