Implemented UI flows for telemetry, own telemetry, maps and conversations.

This commit is contained in:
Mark Qvist 2023-10-28 22:27:56 +02:00
parent 3acf67fc39
commit 54e5256ea4
3 changed files with 193 additions and 24 deletions

View File

@ -811,6 +811,9 @@ class SidebandApp(MDApp):
if self.root.ids.screen_manager.current == "messages_screen": if self.root.ids.screen_manager.current == "messages_screen":
context_dest = self.messages_view.ids.messages_scrollview.active_conversation context_dest = self.messages_view.ids.messages_scrollview.active_conversation
self.map_show_peer_location(context_dest) self.map_show_peer_location(context_dest)
elif self.root.ids.screen_manager.current == "object_details_screen":
context_dest = self.object_details_screen.object_hash
self.map_show_peer_location(context_dest)
else: else:
self.map_action(self) self.map_action(self)
@ -823,16 +826,27 @@ class SidebandApp(MDApp):
if text == "t": if text == "t":
if self.root.ids.screen_manager.current == "messages_screen": if self.root.ids.screen_manager.current == "messages_screen":
self.object_details_action(self.messages_view, from_conv=True) self.object_details_action(self.messages_view, from_conv=True)
elif self.root.ids.screen_manager.current == "object_details_screen":
self.object_details_screen.reload_telemetry()
else: else:
self.telemetry_action(self) self.telemetry_action(self)
if text == "o":
# if self.root.ids.screen_manager.current == "telemetry_screen":
self.map_display_own_telemetry()
if text == "r": if text == "r":
if self.root.ids.screen_manager.current == "conversations_screen": if self.root.ids.screen_manager.current == "conversations_screen":
self.lxmf_sync_action(self) self.lxmf_sync_action(self)
elif self.root.ids.screen_manager.current == "telemetry_screen": elif self.root.ids.screen_manager.current == "telemetry_screen":
self.converse_from_telemetry(self) self.conversations_action(self, direction="right")
elif self.root.ids.screen_manager.current == "object_details_screen":
if not self.object_details_screen.object_hash == self.sideband.lxmf_destination.hash:
self.converse_from_telemetry(self)
else:
self.conversations_action(self, direction="right")
else: else:
self.conversations_action(self) self.conversations_action(self, direction="right")
if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "g"): if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "g"):
self.guide_action(self) self.guide_action(self)
@ -1063,6 +1077,9 @@ class SidebandApp(MDApp):
if self.root.ids.screen_manager.current == "messages_screen": if self.root.ids.screen_manager.current == "messages_screen":
context_dest = self.messages_view.ids.messages_scrollview.active_conversation context_dest = self.messages_view.ids.messages_scrollview.active_conversation
self.map_show_peer_location(context_dest) self.map_show_peer_location(context_dest)
if self.root.ids.screen_manager.current == "object_details_screen":
context_dest = self.object_details_screen.object_hash
self.map_show_peer_location(context_dest)
def peer_show_telemetry_action(self, sender): def peer_show_telemetry_action(self, sender):
if self.root.ids.screen_manager.current == "messages_screen": if self.root.ids.screen_manager.current == "messages_screen":
@ -1124,8 +1141,8 @@ class SidebandApp(MDApp):
### Conversations screen ### Conversations screen
###################################### ######################################
def conversations_action(self, sender=None): def conversations_action(self, sender=None, direction="left"):
self.open_conversations() self.open_conversations(direction=direction)
def open_conversations(self, direction="left"): def open_conversations(self, direction="left"):
self.root.ids.screen_manager.transition.direction = direction self.root.ids.screen_manager.transition.direction = direction
@ -3252,8 +3269,11 @@ class SidebandApp(MDApp):
self.root.ids.nav_drawer.set_state("closed") self.root.ids.nav_drawer.set_state("closed")
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
def converse_from_telemetry(self): def converse_from_telemetry(self, sender=None):
pass if self.object_details_screen != None:
context_dest = self.object_details_screen.object_hash
if not self.object_details_screen.object_hash == self.sideband.lxmf_destination.hash:
self.open_conversation(context_dest)
def telemetry_copy(self, sender=None): def telemetry_copy(self, sender=None):
Clipboard.copy(str(self.sideband.get_telemetry())) Clipboard.copy(str(self.sideband.get_telemetry()))
@ -3425,10 +3445,10 @@ class SidebandApp(MDApp):
maxz = source.max_zoom maxz = source.max_zoom
minz = source.min_zoom minz = source.min_zoom
if self.map.zoom > maxz: if self.map.zoom > maxz:
self.map.zoom = maxz mz = maxz; px, py = self.map_get_zoom_center(); self.map.set_zoom_at(mz, px, py)
if self.map.zoom < minz: if self.map.zoom < minz:
self.map.zoom = minz mz = minz; px, py = self.map_get_zoom_center(); self.map.set_zoom_at(mz, px, py)
m = self.map m = self.map
nlat = self.map.lat nlat = self.map.lat
@ -3552,24 +3572,24 @@ class SidebandApp(MDApp):
delta = (-span/self.map_nav_divisor)*modifier delta = (-span/self.map_nav_divisor)*modifier
self.map.center_on(self.map.lat+delta, self.map.lon) self.map.center_on(self.map.lat+delta, self.map.lon)
def map_get_zoom_center(self):
bb = self.map.get_bbox()
slat = (bb[2]-bb[0])/2; slon = (bb[3]-bb[1])/2
zlat = bb[0]+slat; zlon = bb[1]+slon
return self.map.get_window_xy_from(zlat, zlon, self.map.zoom)
def map_nav_zoom_out(self, sender=None, modifier=1.0): def map_nav_zoom_out(self, sender=None, modifier=1.0):
if self.map != None: if self.map != None:
zd = -self.map_nav_zoom*modifier zd = -self.map_nav_zoom*modifier
if self.map.zoom+zd > self.map.map_source.min_zoom: if self.map.zoom+zd > self.map.map_source.min_zoom:
bb = self.map.get_bbox() px, py = self.map_get_zoom_center()
slat = (bb[2]-bb[0])/2; slon = (bb[3]-bb[1])/2
zlat = bb[0]+slat; zlon = bb[1]+slon
px, py = self.map.get_window_xy_from(zlat, zlon, self.map.zoom)
self.map.animated_diff_scale_at(zd, px, py) self.map.animated_diff_scale_at(zd, px, py)
def map_nav_zoom_in(self, sender=None, modifier=1.0): def map_nav_zoom_in(self, sender=None, modifier=1.0):
if self.map != None: if self.map != None:
zd = self.map_nav_zoom*modifier zd = self.map_nav_zoom*modifier
if self.map.zoom+zd < self.map.map_source.max_zoom or self.map.scale < 3.0: if self.map.zoom+zd < self.map.map_source.max_zoom or self.map.scale < 3.0:
bb = self.map.get_bbox() px, py = self.map_get_zoom_center()
slat = (bb[2]-bb[0])/2; slon = (bb[3]-bb[1])/2
zlat = bb[0]+slat; zlon = bb[1]+slon
px, py = self.map.get_window_xy_from(zlat, zlon, self.map.zoom)
self.map.animated_diff_scale_at(zd, px, py) self.map.animated_diff_scale_at(zd, px, py)
def map_action(self, sender=None, direction="left"): def map_action(self, sender=None, direction="left"):
@ -3608,7 +3628,7 @@ class SidebandApp(MDApp):
def am_job(dt): def am_job(dt):
self.map_update_markers() self.map_update_markers()
Clock.schedule_once(am_job, 0.6) Clock.schedule_once(am_job, 0.15)
def map_settings_load_states(self): def map_settings_load_states(self):
if self.map_settings_screen != None: if self.map_settings_screen != None:
@ -3709,10 +3729,13 @@ class SidebandApp(MDApp):
def map_show(self, location): def map_show(self, location):
if hasattr(self, "map") and self.map: if hasattr(self, "map") and self.map:
self.map.center_on(location["latitude"],location["longtitude"])
# self.map.lat = location["latitude"] # self.map.lat = location["latitude"]
# self.map.lon = location["longtitude"] # self.map.lon = location["longtitude"]
self.map.zoom = 16 mz = 16
if mz > self.map.map_source.max_zoom: mz = self.map.map_source.max_zoom
if mz < self.map.map_source.min_zoom: mz = self.map.map_source.min_zoom
self.map.center_on(location["latitude"],location["longtitude"])
px, py = self.map_get_zoom_center(); self.map.set_zoom_at(mz, px, py)
self.map.trigger_update(True) self.map.trigger_update(True)
def map_show_peer_location(self, context_dest): def map_show_peer_location(self, context_dest):

View File

@ -846,7 +846,27 @@ class SidebandCore():
return [] return []
def owm_location(self):
return self.peer_location(self.lxmf_destination.hash)
def peer_location(self, context_dest): def peer_location(self, context_dest):
if context_dest == None:
return None
if context_dest == self.lxmf_destination.hash:
try:
if self.latest_telemetry != None:
lt = self.latest_telemetry
if "location" in lt and lt["location"] != None:
l = lt["location"]
if "latitude" in l and "longtitude" in l:
if l["latitude"] != None and l["longtitude"] != None:
return l
return None
except Exception as e:
RNS.log("Error while getting own location: "+str(e), RNS.LOG_ERROR)
after_time = time.time()-3*30*24*60*60 after_time = time.time()-3*30*24*60*60
pts = self.peer_telemetry(context_dest, after=after_time) pts = self.peer_telemetry(context_dest, after=after_time)
for pt in pts: for pt in pts:

View File

@ -14,6 +14,10 @@ from sideband.sense import Telemeter
import threading import threading
import webbrowser import webbrowser
from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.toast import toast
from datetime import datetime from datetime import datetime
@ -27,11 +31,13 @@ class ObjectDetails():
self.app = app self.app = app
self.widget = None self.widget = None
self.object_hash = object_hash self.object_hash = object_hash
self.lastest_timestamp = 0
self.coords = None self.coords = None
self.raw_telemetry = None self.raw_telemetry = None
self.from_telemetry = False self.from_telemetry = False
self.from_conv = False self.from_conv = False
self.viewing_self = False self.viewing_self = False
self.delete_dialog = None
if not self.app.root.ids.screen_manager.has_screen("object_details_screen"): if not self.app.root.ids.screen_manager.has_screen("object_details_screen"):
self.screen = Builder.load_string(layou_object_details) self.screen = Builder.load_string(layou_object_details)
@ -46,6 +52,16 @@ class ObjectDetails():
self.telemetry_list.app = self.app self.telemetry_list.app = self.app
self.screen.ids.object_details_container.add_widget(self.telemetry_list) self.screen.ids.object_details_container.add_widget(self.telemetry_list)
Clock.schedule_interval(self.reload_job, 2)
def reload_job(self, dt=None):
if self.app.root.ids.screen_manager.current == "object_details_screen":
latest_telemetry = self.app.sideband.peer_telemetry(self.object_hash, limit=1)
if latest_telemetry != None and len(latest_telemetry) > 0:
telemetry_timestamp = latest_telemetry[0][0]
if telemetry_timestamp > self.lastest_timestamp:
self.reload_telemetry(notoast=True)
def close_action(self, sender=None): def close_action(self, sender=None):
if self.from_telemetry: if self.from_telemetry:
self.app.telemetry_action(direction="right") self.app.telemetry_action(direction="right")
@ -55,7 +71,41 @@ class ObjectDetails():
else: else:
self.app.close_sub_map_action() self.app.close_sub_map_action()
def set_source(self, source_dest, from_conv=False, from_telemetry=False): def confirm_delete_telemetry(self, sender=None):
self.app.sideband.clear_telemetry(self.object_hash)
def delete_telemetry_action(self, sender=None):
if self.delete_dialog == None:
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))
self.delete_dialog = MDDialog(
title="Clear telemetry?",
text="This will permanently delete all collected telemetry for this object.",
buttons=[ yes_button, no_button ],
)
def dl_yes(s):
self.delete_dialog.dismiss()
self.confirm_delete_telemetry()
def cb(dt):
self.reload_telemetry(notoast=True)
Clock.schedule_once(cb, 0.2)
def dl_no(s):
self.delete_dialog.dismiss()
yes_button.bind(on_release=dl_yes)
no_button.bind(on_release=dl_no)
self.delete_dialog.open()
def reload_telemetry(self, sender=None, notoast=False):
if self.object_hash != None:
self.set_source(self.object_hash, from_conv=self.from_conv, from_telemetry=self.from_telemetry)
if not notoast:
toast("Reloaded telemetry for object")
def set_source(self, source_dest, from_conv=False, from_telemetry=False, prefetched=None):
self.object_hash = source_dest self.object_hash = source_dest
if from_telemetry: if from_telemetry:
@ -76,9 +126,27 @@ class ObjectDetails():
self.screen.ids.object_appearance.icon = appearance[0] self.screen.ids.object_appearance.icon = appearance[0]
self.screen.ids.object_appearance.icon_color = appearance[1] self.screen.ids.object_appearance.icon_color = appearance[1]
self.screen.ids.object_appearance.md_bg_color = appearance[2] self.screen.ids.object_appearance.md_bg_color = appearance[2]
# self.screen.ids.delete_button.line_color = self.app.color_reject
# self.screen.ids.delete_button.text_color = self.app.color_reject
# self.screen.ids.delete_button.icon_color = self.app.color_reject
def djob(dt):
if self.viewing_self:
self.screen.ids.request_button.disabled = True
self.screen.ids.send_button.disabled = True
else:
self.screen.ids.request_button.disabled = False
self.screen.ids.send_button.disabled = False
Clock.schedule_once(djob, 0.0)
if prefetched != None:
latest_telemetry = prefetched
else:
latest_telemetry = self.app.sideband.peer_telemetry(source_dest, limit=1)
latest_telemetry = self.app.sideband.peer_telemetry(source_dest, limit=1)
if latest_telemetry != None and len(latest_telemetry) > 0: if latest_telemetry != None and len(latest_telemetry) > 0:
telemetry_timestamp = latest_telemetry[0][0]
self.lastest_timestamp = telemetry_timestamp
own_address = self.app.sideband.lxmf_destination.hash own_address = self.app.sideband.lxmf_destination.hash
telemeter = Telemeter.from_packed(latest_telemetry[0][1]) telemeter = Telemeter.from_packed(latest_telemetry[0][1])
self.raw_telemetry = telemeter.read_all() self.raw_telemetry = telemeter.read_all()
@ -428,6 +496,9 @@ MDScreen:
[['menu', lambda x: root.app.nav_drawer.set_state("open")]] [['menu', lambda x: root.app.nav_drawer.set_state("open")]]
right_action_items: right_action_items:
[ [
['map-search', lambda x: root.app.peer_show_location_action(root.delegate)],
['refresh', lambda x: root.delegate.reload_telemetry()],
['trash-can-outline', lambda x: root.delegate.delete_telemetry_action()],
['close', lambda x: root.delegate.close_action()], ['close', lambda x: root.delegate.close_action()],
] ]
@ -446,6 +517,7 @@ MDScreen:
md_bg_color: [1,1,1,1] md_bg_color: [1,1,1,1]
theme_icon_color: "Custom" theme_icon_color: "Custom"
icon_size: dp(32) icon_size: dp(32)
on_release: root.app.converse_from_telemetry()
MDLabel: MDLabel:
id: name_label id: name_label
@ -454,12 +526,11 @@ MDScreen:
font_style: "H6" font_style: "H6"
MDBoxLayout: MDBoxLayout:
id: object_header
orientation: "horizontal" orientation: "horizontal"
spacing: dp(24) spacing: dp(24)
size_hint_y: None size_hint_y: None
height: self.minimum_height height: self.minimum_height
padding: [dp(24), dp(0), dp(24), dp(12)] padding: [dp(24), dp(0), dp(24), dp(24)]
MDRectangleFlatIconButton: MDRectangleFlatIconButton:
id: telemetry_button id: telemetry_button
@ -483,8 +554,63 @@ MDScreen:
on_release: root.delegate.copy_coordinates(self) on_release: root.delegate.copy_coordinates(self)
disabled: False disabled: False
MDSeparator:
orientation: "horizontal"
height: dp(1)
MDBoxLayout: MDBoxLayout:
orientation: "vertical" orientation: "vertical"
id: object_details_container id: object_details_container
MDSeparator:
orientation: "horizontal"
height: dp(1)
MDBoxLayout:
orientation: "horizontal"
spacing: dp(24)
size_hint_y: None
height: self.minimum_height
padding: [dp(24), dp(24), dp(24), dp(24)]
MDRectangleFlatIconButton:
id: request_button
icon: "arrow-down-bold-hexagon-outline"
text: "Request Update"
padding: [dp(0), dp(14), dp(0), dp(14)]
icon_size: dp(24)
font_size: dp(16)
size_hint: [1.0, None]
on_release: root.delegate.copy_telemetry(self)
disabled: False
MDRectangleFlatIconButton:
id: send_button
icon: "upload-lock"
text: "Send Update Now"
padding: [dp(0), dp(14), dp(0), dp(14)]
icon_size: dp(24)
font_size: dp(16)
size_hint: [1.0, None]
on_release: root.delegate.copy_coordinates(self)
disabled: False
# MDBoxLayout:
# orientation: "horizontal"
# spacing: dp(16)
# size_hint_y: None
# height: self.minimum_height
# padding: [dp(24), dp(16), dp(24), dp(24)]
# MDRectangleFlatIconButton:
# id: delete_button
# icon: "trash-can-outline"
# text: "Delete All Telemetry"
# padding: [dp(0), dp(14), dp(0), dp(14)]
# icon_size: dp(24)
# font_size: dp(16)
# size_hint: [1.0, None]
# on_release: root.delegate.copy_telemetry(self)
# disabled: False
""" """