Compare commits

...

18 Commits
0.9.1 ... 0.9.3

Author SHA1 Message Date
Mark Qvist
7ed85ad398 Updated version 2025-12-27 13:30:11 +01:00
Mark Qvist
5ceb0c671e Fixed composite unicode characters breaking text alignment rendering 2025-12-27 13:29:10 +01:00
Mark Qvist
3e7e55a9ca Fixed announce stream keyboard navigation 2025-12-27 12:25:25 +01:00
markqvist
a7a88e6a3e Merge pull request #86 from RFnexus/announce-stream
Announce stream improvements
2025-12-27 12:15:58 +01:00
Mark Qvist
5de1b93fd9 Updated readme 2025-12-22 22:28:42 +01:00
Mark Qvist
c9ca0a2fd1 Updated version 2025-12-22 13:09:17 +01:00
Mark Qvist
cb87148ec3 Updated dependencies 2025-12-22 13:08:39 +01:00
markqvist
9596361a6b Merge pull request #87 from strijar/pyc_fix
Fixed work from compiled pyc files
2025-12-22 12:54:04 +01:00
Mark Qvist
d4a3a91e04 Updated micron text aligment parsing. Fixes #83. 2025-12-22 12:51:31 +01:00
Mark Qvist
dbd1d87adb Fixed micron fg/bg color header parsing. 2025-12-22 12:42:32 +01:00
Mark Qvist
db3642ee05 Parse intro_time as float. Fixes #79. 2025-12-22 11:41:59 +01:00
Mark Qvist
6b74e49b0f Merge branch 'master' of github.com:markqvist/NomadNet 2025-12-22 11:27:33 +01:00
Mark Qvist
5253cccfa7 Save peer settings file using write-then-copy 2025-12-22 11:27:05 +01:00
Mark Qvist
a2e6a06a35 Added warning and explanation on corrupt peer settings file 2025-12-22 11:18:21 +01:00
Belousov Oleg
9c79496504 Fixed work from compiled pyc files 2025-12-19 23:50:02 +03:00
markqvist
eafe77718f Merge pull request #85 from RFnexus/master
Strip whitespace from LXMF address and URL dialog
2025-12-13 13:56:50 +01:00
Zenith
abde448e00 Add count and search options to announce stream. Add toggle for destination and announce data on list. Fix list dialog closing on new announce 2025-12-12 20:50:11 -05:00
Zenith
6d2bf21f0d Strip whitespace from LXMF address and URL dialog 2025-12-12 19:21:03 -05:00
15 changed files with 164 additions and 73 deletions

View File

@@ -148,14 +148,17 @@ You can help support the continued development of open, free and private communi
``` ```
- Bitcoin - Bitcoin
``` ```
bc1p4a6axuvl7n9hpapfj8sv5reqj8kz6uxa67d5en70vzrttj0fmcusgxsfk5 bc1pgqgu8h8xvj4jtafslq396v7ju7hkgymyrzyqft4llfslz5vp99psqfk3a6
``` ```
- Ethereum - Ethereum
``` ```
0xae89F3B94fC4AD6563F0864a55F9a697a90261ff 0x91C421DdfB8a30a49A71d63447ddb54cEBe3465E
``` ```
- Liberapay: https://liberapay.com/Reticulum/
- Ko-Fi: https://ko-fi.com/markqvist - Ko-Fi: https://ko-fi.com/markqvist
## Development Roadmap ## Development Roadmap
- New major features - New major features
@@ -171,8 +174,6 @@ You can help support the continued development of open, free and private communi
- Better navigation handling when requests fail (also because of closed links) - Better navigation handling when requests fail (also because of closed links)
- Retry failed messages mechanism - Retry failed messages mechanism
- Re-arrange buttons to be more consistent - Re-arrange buttons to be more consistent
- Input field for pages
- Post mechanism
- Term compatibility notice in readme - Term compatibility notice in readme
- Selected icon in conversation list - Selected icon in conversation list
- Possibly a Search Local Nodes function - Possibly a Search Local Nodes function

View File

@@ -7,6 +7,7 @@ import threading
import RNS.vendor.umsgpack as msgpack import RNS.vendor.umsgpack as msgpack
from LXMF import pn_announce_data_is_valid from LXMF import pn_announce_data_is_valid
from nomadnet.util import strip_modifiers
class PNAnnounceHandler: class PNAnnounceHandler:
def __init__(self, owner): def __init__(self, owner):
@@ -229,7 +230,7 @@ class Directory:
def display_name(self, source_hash): def display_name(self, source_hash):
if source_hash in self.directory_entries: if source_hash in self.directory_entries:
return self.directory_entries[source_hash].display_name return strip_modifiers(self.directory_entries[source_hash].display_name)
else: else:
return None return None
@@ -241,7 +242,7 @@ class Directory:
if dn == None: if dn == None:
return RNS.prettyhexrep(source_hash) return RNS.prettyhexrep(source_hash)
else: else:
return dn+" <"+RNS.hexrep(source_hash, delimit=False)+">" return strip_modifiers(dn)+" <"+RNS.hexrep(source_hash, delimit=False)+">"
else: else:
return "<"+RNS.hexrep(source_hash, delimit=False)+">" return "<"+RNS.hexrep(source_hash, delimit=False)+">"
else: else:
@@ -250,13 +251,13 @@ class Directory:
if dn == None: if dn == None:
return RNS.prettyhexrep(source_hash) return RNS.prettyhexrep(source_hash)
else: else:
return dn return strip_modifiers(dn)
else: else:
return "<"+RNS.hexrep(source_hash, delimit=False)+">" return "<"+RNS.hexrep(source_hash, delimit=False)+">"
def alleged_display_str(self, source_hash): def alleged_display_str(self, source_hash):
if source_hash in self.directory_entries: if source_hash in self.directory_entries:
return self.directory_entries[source_hash].display_name return strip_modifiers(self.directory_entries[source_hash].display_name)
else: else:
return None return None

View File

@@ -245,8 +245,11 @@ class NomadNetworkApp:
self.peer_settings["served_file_requests"] = 0 self.peer_settings["served_file_requests"] = 0
except Exception as e: except Exception as e:
RNS.log("Could not load local peer settings from "+self.peersettingspath, RNS.LOG_ERROR) RNS.logdest = RNS.LOG_STDOUT
RNS.log("The contained exception was: %s" % (str(e)), RNS.LOG_ERROR) RNS.log(f"Could not load local peer settings from {self.peersettingspath}", RNS.LOG_ERROR)
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
RNS.log(f"This likely means that the peer settings file has become corrupt.", RNS.LOG_ERROR)
RNS.log(f"You can try deleting the file at {self.peersettingspath} and restarting nomadnet.", RNS.LOG_ERROR)
nomadnet.panic() nomadnet.panic()
else: else:
try: try:
@@ -558,9 +561,9 @@ class NomadNetworkApp:
return self.message_router.get_outbound_propagation_node() return self.message_router.get_outbound_propagation_node()
def save_peer_settings(self): def save_peer_settings(self):
file = open(self.peersettingspath, "wb") tmp_path = f"{self.peersettingspath}.tmp"
file.write(msgpack.packb(self.peer_settings)) with open(tmp_path, "wb") as file: file.write(msgpack.packb(self.peer_settings))
file.close() os.replace(tmp_path, self.peersettingspath)
def lxmf_delivery(self, message): def lxmf_delivery(self, message):
time_string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.timestamp)) time_string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(message.timestamp))
@@ -805,7 +808,7 @@ class NomadNetworkApp:
if not "intro_time" in self.config["textui"]: if not "intro_time" in self.config["textui"]:
self.config["textui"]["intro_time"] = 1 self.config["textui"]["intro_time"] = 1
else: else:
self.config["textui"]["intro_time"] = self.config["textui"].as_int("intro_time") self.config["textui"]["intro_time"] = self.config["textui"].as_float("intro_time")
if not "intro_text" in self.config["textui"]: if not "intro_text" in self.config["textui"]:
self.config["textui"]["intro_text"] = "Nomad Network" self.config["textui"]["intro_text"] = "Nomad Network"

View File

@@ -8,8 +8,10 @@ from .Node import Node
from .ui import * from .ui import *
modules = glob.glob(os.path.dirname(__file__)+"/*.py") py_modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] pyc_modules = glob.glob(os.path.dirname(__file__)+"/*.pyc")
modules = py_modules+pyc_modules
__all__ = list(set([os.path.basename(f).replace(".pyc", "").replace(".py", "") for f in modules if not (f.endswith("__init__.py") or f.endswith("__init__.pyc"))]))
def panic(): def panic():
os._exit(255) os._exit(255)

View File

@@ -1 +1 @@
__version__ = "0.9.1" __version__ = "0.9.3"

View File

@@ -3,8 +3,10 @@ import glob
import RNS import RNS
import nomadnet import nomadnet
modules = glob.glob(os.path.dirname(__file__)+"/*.py") py_modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] pyc_modules = glob.glob(os.path.dirname(__file__)+"/*.pyc")
modules = py_modules+pyc_modules
__all__ = list(set([os.path.basename(f).replace(".pyc", "").replace(".py", "") for f in modules if not (f.endswith("__init__.py") or f.endswith("__init__.pyc"))]))
UI_NONE = 0x00 UI_NONE = 0x00

View File

@@ -11,6 +11,7 @@ import threading
from .MicronParser import markup_to_attrmaps, make_style, default_state from .MicronParser import markup_to_attrmaps, make_style, default_state
from nomadnet.Directory import DirectoryEntry from nomadnet.Directory import DirectoryEntry
from nomadnet.vendor.Scrollable import * from nomadnet.vendor.Scrollable import *
from nomadnet.util import strip_modifiers
class BrowserFrame(urwid.Frame): class BrowserFrame(urwid.Frame):
def keypress(self, size, key): def keypress(self, size, key):
@@ -697,7 +698,7 @@ class Browser:
def confirmed(sender): def confirmed(sender):
try: try:
self.retrieve_url(e_url.get_edit_text()) self.retrieve_url(e_url.get_edit_text().strip())
except Exception as e: except Exception as e:
self.browser_footer = urwid.Text("Could not open link: "+str(e)) self.browser_footer = urwid.Text("Could not open link: "+str(e))
self.frame.contents["footer"] = (self.browser_footer, self.frame.options()) self.frame.contents["footer"] = (self.browser_footer, self.frame.options())
@@ -799,7 +800,7 @@ class Browser:
self.page_background_color = None self.page_background_color = None
bgpos = self.markup.find("#!bg=") bgpos = self.markup.find("#!bg=")
if bgpos: if bgpos >= 0:
endpos = self.markup.find("\n", bgpos) endpos = self.markup.find("\n", bgpos)
if endpos-(bgpos+5) == 3: if endpos-(bgpos+5) == 3:
bg = self.markup[bgpos+5:endpos] bg = self.markup[bgpos+5:endpos]
@@ -807,13 +808,13 @@ class Browser:
self.page_foreground_color = None self.page_foreground_color = None
fgpos = self.markup.find("#!fg=") fgpos = self.markup.find("#!fg=")
if fgpos: if fgpos >= 0:
endpos = self.markup.find("\n", fgpos) endpos = self.markup.find("\n", fgpos)
if endpos-(fgpos+5) == 3: if endpos-(fgpos+5) == 3:
fg = self.markup[fgpos+5:endpos] fg = self.markup[fgpos+5:endpos]
self.page_foreground_color = fg self.page_foreground_color = fg
self.attr_maps = markup_to_attrmaps(self.markup, url_delegate=self, fg_color=self.page_foreground_color, bg_color=self.page_background_color) self.attr_maps = markup_to_attrmaps(strip_modifiers(self.markup), url_delegate=self, fg_color=self.page_foreground_color, bg_color=self.page_background_color)
self.response_progress = 0 self.response_progress = 0
self.response_speed = None self.response_speed = None
@@ -866,7 +867,7 @@ class Browser:
self.page_background_color = None self.page_background_color = None
bgpos = self.markup.find("#!bg=") bgpos = self.markup.find("#!bg=")
if bgpos: if bgpos >= 0:
endpos = self.markup.find("\n", bgpos) endpos = self.markup.find("\n", bgpos)
if endpos-(bgpos+5) == 3: if endpos-(bgpos+5) == 3:
bg = self.markup[bgpos+5:endpos] bg = self.markup[bgpos+5:endpos]
@@ -874,13 +875,13 @@ class Browser:
self.page_foreground_color = None self.page_foreground_color = None
fgpos = self.markup.find("#!fg=") fgpos = self.markup.find("#!fg=")
if fgpos: if fgpos >= 0:
endpos = self.markup.find("\n", fgpos) endpos = self.markup.find("\n", fgpos)
if endpos-(fgpos+5) == 3: if endpos-(fgpos+5) == 3:
fg = self.markup[fgpos+5:endpos] fg = self.markup[fgpos+5:endpos]
self.page_foreground_color = fg self.page_foreground_color = fg
self.attr_maps = markup_to_attrmaps(self.markup, url_delegate=self, fg_color=self.page_foreground_color, bg_color=self.page_background_color) self.attr_maps = markup_to_attrmaps(strip_modifiers(self.markup), url_delegate=self, fg_color=self.page_foreground_color, bg_color=self.page_background_color)
self.response_progress = 0 self.response_progress = 0
self.response_speed = None self.response_speed = None
@@ -1018,7 +1019,7 @@ class Browser:
self.page_background_color = None self.page_background_color = None
bgpos = self.markup.find("#!bg=") bgpos = self.markup.find("#!bg=")
if bgpos: if bgpos >= 0:
endpos = self.markup.find("\n", bgpos) endpos = self.markup.find("\n", bgpos)
if endpos-(bgpos+5) == 3: if endpos-(bgpos+5) == 3:
bg = self.markup[bgpos+5:endpos] bg = self.markup[bgpos+5:endpos]
@@ -1026,13 +1027,13 @@ class Browser:
self.page_foreground_color = None self.page_foreground_color = None
fgpos = self.markup.find("#!fg=") fgpos = self.markup.find("#!fg=")
if fgpos: if fgpos >= 0:
endpos = self.markup.find("\n", fgpos) endpos = self.markup.find("\n", fgpos)
if endpos-(fgpos+5) == 3: if endpos-(fgpos+5) == 3:
fg = self.markup[fgpos+5:endpos] fg = self.markup[fgpos+5:endpos]
self.page_foreground_color = fg self.page_foreground_color = fg
self.attr_maps = markup_to_attrmaps(self.markup, url_delegate=self, fg_color=self.page_foreground_color, bg_color=self.page_background_color) self.attr_maps = markup_to_attrmaps(strip_modifiers(self.markup), url_delegate=self, fg_color=self.page_foreground_color, bg_color=self.page_background_color)
self.response_progress = 0 self.response_progress = 0
self.response_speed = None self.response_speed = None
self.progress_updated_at = None self.progress_updated_at = None

View File

@@ -331,7 +331,7 @@ class ConversationsDisplay():
existing_conversations = nomadnet.Conversation.conversation_list(self.app) existing_conversations = nomadnet.Conversation.conversation_list(self.app)
display_name = e_name.get_edit_text() display_name = e_name.get_edit_text()
source_hash_text = e_id.get_edit_text() source_hash_text = e_id.get_edit_text().strip()
source_hash = bytes.fromhex(source_hash_text) source_hash = bytes.fromhex(source_hash_text)
trust_level = DirectoryEntry.UNTRUSTED trust_level = DirectoryEntry.UNTRUSTED
if r_unknown.state == True: if r_unknown.state == True:
@@ -412,7 +412,7 @@ class ConversationsDisplay():
try: try:
local_delivery_signal = "local_delivery_occurred" local_delivery_signal = "local_delivery_occurred"
duplicate_signal = "duplicate_lxm" duplicate_signal = "duplicate_lxm"
lxm_uri = e_uri.get_edit_text() lxm_uri = e_uri.get_edit_text().strip()
ingest_result = self.app.message_router.ingest_lxm_uri( ingest_result = self.app.message_router.ingest_lxm_uri(
lxm_uri, lxm_uri,

View File

View File

@@ -487,20 +487,14 @@ def make_output(state, line, url_delegate, pre_escape=False):
state["bg_color"] = state["default_bg"] state["bg_color"] = state["default_bg"]
state["align"] = state["default_align"] state["align"] = state["default_align"]
elif c == "c": elif c == "c":
if state["align"] != "center": if state["align"] != "center": state["align"] = "center"
state["align"] = "center" # else: state["align"] = state["default_align"]
else:
state["align"] = state["default_align"]
elif c == "l": elif c == "l":
if state["align"] != "left": if state["align"] != "left": state["align"] = "left"
state["align"] = "left" # else: state["align"] = state["default_align"]
else:
state["align"] = state["default_align"]
elif c == "r": elif c == "r":
if state["align"] != "right": if state["align"] != "right": state["align"] = "right"
state["align"] = "right" # else: state["align"] = state["default_align"]
else:
state["align"] = state["default_align"]
elif c == "a": elif c == "a":
state["align"] = state["default_align"] state["align"] = state["default_align"]
@@ -649,7 +643,7 @@ def make_output(state, line, url_delegate, pre_escape=False):
orig_spec = speclist[4] orig_spec = speclist[4]
if url_delegate != None: if url_delegate != None:
linkspec = LinkSpec(link_url, orig_spec) linkspec = LinkSpec(link_url, orig_spec, cm=cm)
if link_fields != "": if link_fields != "":
lf = link_fields.split("|") lf = link_fields.split("|")
if len(lf) > 0: if len(lf) > 0:
@@ -696,11 +690,11 @@ def make_output(state, line, url_delegate, pre_escape=False):
class LinkSpec(urwid.AttrSpec): class LinkSpec(urwid.AttrSpec):
def __init__(self, link_target, orig_spec): def __init__(self, link_target, orig_spec, cm=256):
self.link_target = link_target self.link_target = link_target
self.link_fields = None self.link_fields = None
super().__init__(orig_spec.foreground, orig_spec.background) super().__init__(orig_spec.foreground, orig_spec.background, colors=cm)
class LinkableText(urwid.Text): class LinkableText(urwid.Text):

View File

@@ -6,6 +6,7 @@ import threading
from datetime import datetime from datetime import datetime
from nomadnet.Directory import DirectoryEntry from nomadnet.Directory import DirectoryEntry
from nomadnet.vendor.additional_urwid_widgets import IndicativeListBox, MODIFIER_KEY from nomadnet.vendor.additional_urwid_widgets import IndicativeListBox, MODIFIER_KEY
from nomadnet.util import strip_modifiers
from .Browser import Browser from .Browser import Browser
@@ -250,7 +251,7 @@ class AnnounceInfo(urwid.WidgetWrap):
class AnnounceStreamEntry(urwid.WidgetWrap): class AnnounceStreamEntry(urwid.WidgetWrap):
def __init__(self, app, announce, delegate): def __init__(self, app, announce, delegate, show_destination=False):
full_time_format = "%Y-%m-%d %H:%M:%S" full_time_format = "%Y-%m-%d %H:%M:%S"
date_time_format = "%Y-%m-%d" date_time_format = "%Y-%m-%d"
time_time_format = "%H:%M:%S" time_time_format = "%H:%M:%S"
@@ -274,7 +275,16 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
ts_string = dt.strftime(date_only_format) ts_string = dt.strftime(date_only_format)
trust_level = self.app.directory.trust_level(source_hash) trust_level = self.app.directory.trust_level(source_hash)
display_str = self.app.directory.simplest_display_str(source_hash)
if show_destination:
display_str = RNS.hexrep(source_hash, delimit=False)
else:
try:
display_str = strip_modifiers(announce[2].decode("utf-8"))
if len(display_str) > 32:
display_str = display_str[:32] + "..."
except:
display_str = self.app.directory.simplest_display_str(source_hash)
if trust_level == DirectoryEntry.UNTRUSTED: if trust_level == DirectoryEntry.UNTRUSTED:
symbol = g["cross"] symbol = g["cross"]
@@ -381,22 +391,33 @@ class AnnounceStream(urwid.WidgetWrap):
self.ilb = None self.ilb = None
self.no_content = True self.no_content = True
self.current_tab = "nodes" self.current_tab = "nodes"
self.show_destination = False
self.search_text = ""
self.added_entries = [] self.added_entries = []
self.widget_list = [] self.widget_list = []
self.update_widget_list()
# Create tab buttons self.tab_nodes = TabButton("Nodes (0)", on_press=self.show_nodes_tab)
self.tab_nodes = TabButton("Nodes", on_press=self.show_nodes_tab) self.tab_peers = TabButton("Peers (0)", on_press=self.show_peers_tab)
self.tab_peers = TabButton("Peers", on_press=self.show_peers_tab) self.tab_pn = TabButton("Propagation Nodes (0)", on_press=self.show_pn_tab)
self.tab_pn = TabButton("Propagation Nodes", on_press=self.show_pn_tab)
# Create tab bar with proportional widths
self.tab_bar = urwid.Columns([ self.tab_bar = urwid.Columns([
('weight', 1, self.tab_nodes), ('weight', 1, self.tab_nodes),
('weight', 1, self.tab_peers), ('weight', 1, self.tab_peers),
('weight', 3, self.tab_pn), ('weight', 3, self.tab_pn),
], dividechars=1) # Add 1 character spacing between tabs ], dividechars=1)
self.search_edit = urwid.Edit(caption="Search: ")
urwid.connect_signal(self.search_edit, 'change', self.on_search_change)
self.display_toggle = TabButton("Show: Name", on_press=self.toggle_display_mode)
self.filter_bar = urwid.Columns([
('weight', 2, self.search_edit),
('weight', 1, self.display_toggle),
], dividechars=1)
self.update_widget_list()
self.ilb = ExceptionHandlingListBox( self.ilb = ExceptionHandlingListBox(
self.widget_list, self.widget_list,
@@ -406,9 +427,9 @@ class AnnounceStream(urwid.WidgetWrap):
#highlight_offFocus="list_off_focus" #highlight_offFocus="list_off_focus"
) )
# Combine tab bar and list box
self.pile = urwid.Pile([ self.pile = urwid.Pile([
('pack', self.tab_bar), ('pack', self.tab_bar),
('pack', self.filter_bar),
('weight', 1, self.ilb), ('weight', 1, self.ilb),
]) ])
@@ -416,13 +437,25 @@ class AnnounceStream(urwid.WidgetWrap):
super().__init__(urwid.LineBox(self.display_widget, title="Announce Stream")) super().__init__(urwid.LineBox(self.display_widget, title="Announce Stream"))
def keypress(self, size, key): def keypress(self, size, key):
if key == "up" and (self.no_content or self.ilb.first_item_is_selected()): if key == "up" and self.pile.focus == self.tab_bar:
nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.frame.focus_position = "header" nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.frame.focus_position = "header"
elif key == "ctrl x": elif key == "ctrl x":
self.delete_selected_entry() self.delete_selected_entry()
return super(AnnounceStream, self).keypress(size, key) return super(AnnounceStream, self).keypress(size, key)
def on_search_change(self, widget, text):
self.search_text = text.lower()
self.update_widget_list()
def toggle_display_mode(self, button):
self.show_destination = not self.show_destination
if self.show_destination:
self.display_toggle.set_label("Show: Dest")
else:
self.display_toggle.set_label("Show: Name")
self.update_widget_list()
def delete_selected_entry(self): def delete_selected_entry(self):
if self.ilb.get_selected_item() != None: if self.ilb.get_selected_item() != None:
self.app.directory.remove_announce_with_timestamp(self.ilb.get_selected_item().original_widget.timestamp) self.app.directory.remove_announce_with_timestamp(self.ilb.get_selected_item().original_widget.timestamp)
@@ -438,19 +471,36 @@ class AnnounceStream(urwid.WidgetWrap):
self.widget_list = [] self.widget_list = []
new_entries = [] new_entries = []
node_count = 0
peer_count = 0
pn_count = 0
for e in self.app.directory.announce_stream: for e in self.app.directory.announce_stream:
announce_type = e[3] announce_type = e[3]
# Filter based on current tab if self.search_text:
if self.current_tab == "nodes" and (announce_type == "node" or announce_type == True): try:
new_entries.append(e) announce_data = e[2].decode("utf-8").lower()
elif self.current_tab == "peers" and (announce_type == "peer" or announce_type == False): except:
new_entries.append(e) announce_data = ""
elif self.current_tab == "pn" and announce_type == "pn": if self.search_text not in announce_data:
new_entries.append(e) continue
if announce_type == "node" or announce_type == True:
node_count += 1
if self.current_tab == "nodes":
new_entries.append(e)
elif announce_type == "peer" or announce_type == False:
peer_count += 1
if self.current_tab == "peers":
new_entries.append(e)
elif announce_type == "pn":
pn_count += 1
if self.current_tab == "pn":
new_entries.append(e)
for e in new_entries: for e in new_entries:
nw = AnnounceStreamEntry(self.app, e, self) nw = AnnounceStreamEntry(self.app, e, self, show_destination=self.show_destination)
nw.timestamp = e[0] nw.timestamp = e[0]
self.widget_list.append(nw) self.widget_list.append(nw)
@@ -460,6 +510,10 @@ class AnnounceStream(urwid.WidgetWrap):
self.no_content = True self.no_content = True
self.widget_list = [urwid.Text(f"No {self.current_tab} announces", align='center')] self.widget_list = [urwid.Text(f"No {self.current_tab} announces", align='center')]
self.tab_nodes.set_label(f"Nodes ({node_count})")
self.tab_peers.set_label(f"Peers ({peer_count})")
self.tab_pn.set_label(f"Propagation Nodes ({pn_count})")
if self.ilb: if self.ilb:
self.ilb.set_body(self.widget_list) self.ilb.set_body(self.widget_list)
@@ -555,7 +609,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
if node_entry == None: if node_entry == None:
display_str = self.app.directory.simplest_display_str(source_hash) display_str = self.app.directory.simplest_display_str(source_hash)
else: else:
display_str = node_entry.display_name display_str = strip_modifiers(node_entry.display_name)
addr_str = "<"+RNS.hexrep(source_hash, delimit=False)+">" addr_str = "<"+RNS.hexrep(source_hash, delimit=False)+">"
@@ -1648,7 +1702,6 @@ class NetworkDisplay():
def reinit_known_nodes(self): def reinit_known_nodes(self):
self.known_nodes_display = KnownNodes(self.app) self.known_nodes_display = KnownNodes(self.app)
self.known_nodes_display.delegate = self self.known_nodes_display.delegate = self
self.close_list_dialogs()
self.announce_stream_display.rebuild_widget_list() self.announce_stream_display.rebuild_widget_list()
def reinit_lxmf_peers(self): def reinit_lxmf_peers(self):
@@ -1908,4 +1961,4 @@ def pretty_date(time=False):
return str(int(day_diff / 7)) + " weeks ago" return str(int(day_diff / 7)) + " weeks ago"
if day_diff < 365: if day_diff < 365:
return str(int(day_diff / 30)) + " months ago" return str(int(day_diff / 30)) + " months ago"
return str(int(day_diff / 365)) + " years ago" return str(int(day_diff / 365)) + " years ago"

View File

@@ -1,5 +1,7 @@
import os import os
import glob import glob
modules = glob.glob(os.path.dirname(__file__)+"/*.py") py_modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] pyc_modules = glob.glob(os.path.dirname(__file__)+"/*.pyc")
modules = py_modules+pyc_modules
__all__ = list(set([os.path.basename(f).replace(".pyc", "").replace(".py", "") for f in modules if not (f.endswith("__init__.py") or f.endswith("__init__.pyc"))]))

30
nomadnet/util.py Normal file
View File

@@ -0,0 +1,30 @@
import re
import unicodedata
import RNS
def strip_modifiers(text):
def process_characters(text):
result = []
i = 0
while i < len(text):
char = text[i]
category = unicodedata.category(char)
if category.startswith(('L', 'N', 'P', 'S')):
result.append(char)
i += 1
elif category.startswith(('M', 'Sk', 'Cf')) or char in '\u200d\u200c':
i += 1
else:
result.append(char)
i += 1
return ''.join(result)
stripped = process_characters(text)
stripped = re.sub(r'[\uFE00-\uFE0F]', '', stripped)
stripped = re.sub(r'[\U000E0100-\U000E01EF]', '', stripped, flags=re.UNICODE)
stripped = re.sub(r'[\U0001F3FB-\U0001F3FF]', '', stripped, flags=re.UNICODE)
stripped = re.sub(r'[\u200D\u200C]', '', stripped)
return stripped

View File

@@ -1,5 +1,7 @@
import os import os
import glob import glob
modules = glob.glob(os.path.dirname(__file__)+"/*.py") py_modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] pyc_modules = glob.glob(os.path.dirname(__file__)+"/*.pyc")
modules = py_modules+pyc_modules
__all__ = list(set([os.path.basename(f).replace(".pyc", "").replace(".py", "") for f in modules if not (f.endswith("__init__.py") or f.endswith("__init__.pyc"))]))

View File

@@ -30,6 +30,6 @@ setuptools.setup(
entry_points= { entry_points= {
'console_scripts': ['nomadnet=nomadnet.nomadnet:main'] 'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
}, },
install_requires=["rns>=1.0.1", "lxmf>=0.9.1", "urwid>=2.6.16", "qrcode"], install_requires=["rns>=1.0.4", "lxmf>=0.9.3", "urwid>=2.6.16", "qrcode"],
python_requires=">=3.7", python_requires=">=3.7",
) )