Sideband/sbapp/ui/announces.py

320 lines
12 KiB
Python
Raw Normal View History

2022-04-07 13:03:53 -06:00
import time
import RNS
from kivy.metrics import dp,sp
2022-04-07 13:03:53 -06:00
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, BooleanProperty
2022-10-19 10:35:23 -06:00
from kivymd.uix.list import MDList, IconLeftWidget, IconRightWidget, TwoLineAvatarIconListItem
2022-04-07 13:03:53 -06:00
from kivymd.uix.menu import MDDropdownMenu
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
2022-10-08 11:55:46 -06:00
from kivy.clock import Clock
from kivy.core.clipboard import Clipboard
2022-04-07 13:03:53 -06:00
from kivymd.uix.button import MDRectangleFlatButton
2022-04-07 13:03:53 -06:00
from kivymd.uix.dialog import MDDialog
from kivy.lang.builder import Builder
2024-01-05 10:05:34 -07:00
from kivy.utils import escape_markup
if RNS.vendor.platformutils.get_platform() == "android":
2024-12-11 11:25:46 -07:00
from ui.helpers import multilingual_markup, sig_icon_for_q
2024-01-05 10:05:34 -07:00
else:
2024-12-11 11:25:46 -07:00
from .helpers import multilingual_markup, sig_icon_for_q
2024-01-05 10:05:34 -07:00
2022-07-07 14:16:10 -06:00
if RNS.vendor.platformutils.get_platform() == "android":
from ui.helpers import ts_format
else:
from .helpers import ts_format
2022-04-07 13:03:53 -06:00
class Announces():
def __init__(self, app):
self.app = app
self.context_dests = []
self.added_item_dests = []
self.list = None
if not self.app.root.ids.screen_manager.has_screen("announces_screen"):
self.screen = Builder.load_string(layout_announces_screen)
self.screen.app = self.app
self.ids = self.screen.ids
self.app.root.ids.screen_manager.add_widget(self.screen)
self.fetch_announces()
self.list = MDList()
# self.update()
def fetch_announces(self):
self.announces = self.app.sideband.list_announces()
2022-04-07 13:03:53 -06:00
def reload(self):
self.clear_list()
self.update()
def clear_list(self):
if self.list != None:
self.list.clear_widgets()
self.context_dests = []
self.added_item_dests = []
def update(self):
2022-10-08 11:55:46 -06:00
us = time.time()
self.fetch_announces()
2022-04-07 13:03:53 -06:00
self.update_widget()
self.app.sideband.setstate("app.flags.new_announces", False)
2022-10-08 11:55:46 -06:00
RNS.log("Updated announce stream widgets in "+RNS.prettytime(time.time()-us), RNS.LOG_DEBUG)
2022-04-07 13:03:53 -06:00
def update_widget(self):
if self.list == None:
self.list = MDList()
remove_widgets = []
for item in self.list.children:
if not item.sb_uid in (a["dest"] for a in self.announces):
remove_widgets.append(item)
2022-04-07 13:03:53 -06:00
else:
for announce in self.announces:
if announce["dest"] == item.sb_uid:
if announce["time"] > item.ts:
remove_widgets.append(item)
break
for item in remove_widgets:
if item.sb_uid in self.added_item_dests:
self.added_item_dests.remove(item.sb_uid)
self.list.remove_widget(item)
2022-04-07 13:03:53 -06:00
for announce in self.announces:
context_dest = announce["dest"]
ts = announce["time"]
2024-09-12 02:06:24 -06:00
a_name = announce["name"]
a_cost = announce["cost"]
dest_type = announce["type"]
2024-12-11 11:25:46 -07:00
a_rssi = None
a_snr = None
a_q = None
link_extras_str = ""
link_extras_full = ""
if "extras" in announce and announce["extras"] != None:
extras = announce["extras"]
RNS.log("Announce has extras: "+str(announce["extras"]))
if "link_stats" in extras:
link_stats = extras["link_stats"]
if "rssi" in link_stats and "snr" in link_stats and "q" in link_stats:
a_rssi = link_stats["rssi"]
a_snr = link_stats["snr"]
a_q = link_stats["q"]
link_extras_str = f" ([b]RSSI[/b] {a_rssi} [b]SNR[/b] {a_snr})"
link_extras_full = f"\n[b]Link Quality[/b] {a_q}%[/b]\n[b]RSSI[/b] {a_rssi}\n[b]SNR[/b] {a_snr}"
sig_icon = multilingual_markup(sig_icon_for_q(a_q).encode("utf-8")).decode("utf-8")
2022-04-07 13:03:53 -06:00
if not context_dest in self.added_item_dests:
if self.app.sideband.is_trusted(context_dest):
trust_icon = "account-check"
else:
trust_icon = "account-question"
2024-12-11 11:25:46 -07:00
def gen_info(ts, dest, name, cost, dtype, link_extras):
2024-01-05 10:05:34 -07:00
name = multilingual_markup(escape_markup(str(name)).encode("utf-8")).decode("utf-8")
2024-09-12 02:06:24 -06:00
cost = str(cost)
2022-04-07 13:03:53 -06:00
def x(sender):
2024-01-05 10:05:34 -07:00
yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18))
if dtype == "lxmf.delivery":
2024-12-11 11:25:46 -07:00
ad_text = "[size=22dp]LXMF Peer[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+"\n[b]Name[/b] "+name+"\n[b]Stamp Cost[/b] "+cost+link_extras
if dtype == "lxmf.propagation":
2024-12-11 11:25:46 -07:00
ad_text = "[size=22dp]LXMF Propagation Node[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+link_extras
2022-04-07 13:03:53 -06:00
dialog = MDDialog(
text=ad_text,
2022-04-07 13:03:53 -06:00
buttons=[ yes_button ],
2022-10-02 16:56:39 -06:00
# elevation=0,
2022-04-07 13:03:53 -06:00
)
def dl_yes(s):
dialog.dismiss()
yes_button.bind(on_release=dl_yes)
item.dmenu.dismiss()
dialog.open()
return x
2024-12-11 11:25:46 -07:00
time_string = sig_icon + " " + time.strftime(ts_format, time.localtime(ts)) + link_extras_str
time_string_plain = time.strftime(ts_format, time.localtime(ts))
if dest_type == "lxmf.delivery":
2024-01-05 10:05:34 -07:00
disp_name = multilingual_markup(escape_markup(str(self.app.sideband.peer_display_name(context_dest))).encode("utf-8")).decode("utf-8")
iconl = IconLeftWidget(icon=trust_icon)
elif dest_type == "lxmf.propagation":
disp_name = "Propagation Node "+RNS.prettyhexrep(context_dest)
iconl = IconLeftWidget(icon="upload-network")
else:
disp_name = "Unknown Announce"
iconl = IconLeftWidget(icon="progress-question")
2024-12-11 11:25:46 -07:00
item = TwoLineAvatarIconListItem(text=time_string, secondary_text=disp_name, on_release=gen_info(time_string_plain, context_dest, a_name, a_cost, dest_type, link_extras_full))
2022-04-07 13:03:53 -06:00
item.add_widget(iconl)
item.sb_uid = context_dest
item.ts = ts
2022-04-07 13:03:53 -06:00
def gen_del(dest, item):
def x():
2022-10-13 14:12:39 -06:00
yes_button = MDRectangleFlatButton(text="Yes",font_size=dp(18), theme_text_color="Custom", line_color=self.app.color_reject, text_color=self.app.color_reject)
no_button = MDRectangleFlatButton(text="No",font_size=dp(18))
2022-04-07 13:03:53 -06:00
dialog = MDDialog(
title="Delete announce?",
2022-04-07 13:03:53 -06:00
buttons=[ yes_button, no_button ],
padding=[0,0,dp(32),0]
2022-10-02 16:56:39 -06:00
# elevation=0,
2022-04-07 13:03:53 -06:00
)
def dl_yes(s):
dialog.dismiss()
2022-10-08 11:55:46 -06:00
def cb(dt):
self.app.sideband.delete_announce(dest)
self.update()
Clock.schedule_once(cb, 0.2)
2022-04-07 13:03:53 -06:00
def dl_no(s):
dialog.dismiss()
yes_button.bind(on_release=dl_yes)
no_button.bind(on_release=dl_no)
item.dmenu.dismiss()
dialog.open()
return x
def gen_conv(dest, item):
def x():
item.dmenu.dismiss()
self.app.conversation_from_announce_action(dest)
return x
def gen_copy_addr(dest, item):
def x():
Clipboard.copy(RNS.hexrep(dest, delimit=False))
item.dmenu.dismiss()
return x
def gen_set_node(dest, item):
def x():
item.dmenu.dismiss()
self.app.sideband.set_active_propagation_node(dest)
self.app.sideband.config["lxmf_propagation_node"] = dest
self.app.sideband.save_configuration()
return x
if dest_type == "lxmf.delivery":
dm_items = [
{
"viewclass": "OneLineListItem",
"text": "Converse",
"height": dp(40),
"on_release": gen_conv(context_dest, item)
},
{
"viewclass": "OneLineListItem",
"text": "Copy address",
"height": dp(40),
"on_release": gen_copy_addr(context_dest, item)
},
2022-10-08 11:55:46 -06:00
{
"text": "Delete Announce",
"viewclass": "OneLineListItem",
"height": dp(40),
"on_release": gen_del(context_dest, item)
}
]
elif dest_type == "lxmf.propagation":
dm_items = [
{
"viewclass": "OneLineListItem",
"text": "Use this Propagation Node",
"height": dp(40),
"on_release": gen_set_node(context_dest, item)
},
{
"viewclass": "OneLineListItem",
"text": "Copy address",
"height": dp(40),
"on_release": gen_copy_addr(context_dest, item)
},
2022-10-08 11:55:46 -06:00
{
"text": "Delete Announce",
"viewclass": "OneLineListItem",
"height": dp(40),
"on_release": gen_del(context_dest, item)
}
]
else:
dm_items = []
2022-04-07 13:03:53 -06:00
item.iconr = IconRightWidget(icon="dots-vertical");
item.dmenu = MDDropdownMenu(
caller=item.iconr,
items=dm_items,
2023-07-10 11:20:24 -06:00
position="auto",
width=dp(256),
elevation=0,
radius=dp(3),
2022-04-07 13:03:53 -06:00
)
2024-03-10 18:21:54 -06:00
item.dmenu.md_bg_color = self.app.color_hover
2022-04-07 13:03:53 -06:00
def callback_factory(ref):
def x(sender):
ref.dmenu.open()
return x
item.iconr.bind(on_release=callback_factory(item))
item.add_widget(item.iconr)
self.added_item_dests.append(context_dest)
self.list.add_widget(item, index=len(self.list.children))
2022-04-07 13:03:53 -06:00
def get_widget(self):
return self.list
layout_announces_screen = """
MDScreen:
name: "announces_screen"
BoxLayout:
orientation: "vertical"
MDTopAppBar:
title: "Announce Stream"
anchor_title: "left"
elevation: 0
left_action_items:
[['menu', lambda x: root.app.nav_drawer.set_state("open")]]
right_action_items:
[
['close', lambda x: root.app.close_settings_action(self)],
]
# [['eye-off', lambda x: root.ids.screen_manager.app.announce_filter_action(self)]]
ScrollView:
id: announces_scrollview
MDBoxLayout:
orientation: "vertical"
spacing: "24dp"
size_hint_y: None
height: self.minimum_height
padding: dp(64)
MDLabel:
id: announces_info
markup: True
text: ""
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
"""