Added map settings and layer switching

This commit is contained in:
Mark Qvist 2023-10-26 18:54:46 +02:00
parent 0a2a87775e
commit 86e053cdb9
3 changed files with 300 additions and 33 deletions

View File

@ -15,6 +15,7 @@ import RNS
import LXMF import LXMF
import time import time
import os import os
import pathlib
import plyer import plyer
import base64 import base64
import threading import threading
@ -149,7 +150,11 @@ class SidebandApp(MDApp):
self.conversations_view = None self.conversations_view = None
self.messages_view = None self.messages_view = None
self.map = None
self.map_layer = None
self.map_screen = None self.map_screen = None
self.offline_source = None
self.map_settings_screen = None
self.object_details_screen = None self.object_details_screen = None
self.sync_dialog = None self.sync_dialog = None
self.settings_ready = False self.settings_ready = False
@ -3278,71 +3283,155 @@ class SidebandApp(MDApp):
def map_fm_got_path(self, path): def map_fm_got_path(self, path):
self.map_fm_exited() self.map_fm_exited()
# TODO: Remove
toast(path)
###
try: try:
source = MBTilesMapSource(path) source = MBTilesMapSource(path)
self.map_update_source(source) self.map_update_source()
self.sideband.config["map_storage_file"] = path self.sideband.config["map_storage_file"] = path
self.sideband.config["map_storage_path"] = str(pathlib.Path(path).parent.resolve())
self.sideband.save_configuration() self.sideband.save_configuration()
toast("Using \""+os.path.basename(path)+"\" as offline map")
except Exception as e: except Exception as e:
RNS.log(f"Error while loading map \"{path}\": "+str(e), RNS.LOG_ERROR) RNS.log(f"Error while loading map \"{path}\": "+str(e), RNS.LOG_ERROR)
selfmap_update_source() toast("Could not load map \""+os.path.basename(path)+"\"")
self.sideband.config["map_storage_file"] = None
self.sideband.config["map_use_offline"] = False
self.sideband.config["map_use_online"] = True
self.map_settings_load_states()
self.map_update_source()
def map_fm_exited(self, *args): def map_fm_exited(self, *args):
RNS.log("Closing file manager", RNS.LOG_DEBUG)
self.sideband.config["map_storage_file"] = None
self.sideband.save_configuration()
self.manager_open = False self.manager_open = False
self.file_manager.close() self.file_manager.close()
self.map_update_source() self.map_update_source()
def map_get_source(self): def map_get_offline_source(self):
current_map_path = self.sideband.config["map_storage_file"] if self.offline_source != None:
source = None return self.offline_source
else:
if current_map_path:
try: try:
current_map_path = self.sideband.config["map_storage_file"]
if current_map_path == None:
raise ValueError("Map path cannot be None")
source = MBTilesMapSource(current_map_path) source = MBTilesMapSource(current_map_path)
self.offline_source = source
return self.offline_source
except Exception as e: except Exception as e:
RNS.log(f"Error while loading map from \"{current_map_path}\": "+str(e)) RNS.log(f"Error while loading map from \"{current_map_path}\": "+str(e))
self.sideband.config["map_storage_file"] = None self.sideband.config["map_storage_file"] = None
self.sideband.config["map_use_offline"] = False
self.sideband.config["map_use_online"] = True
self.sideband.save_configuration() self.sideband.save_configuration()
self.map_settings_load_states()
return None
def map_get_source(self):
source = None
if self.sideband.config["map_use_offline"]:
source = self.map_get_offline_source()
if source == None: if source == None:
source = MapSource.from_provider("osm") source = MapSource.from_provider("osm", quad_key=False)
return source return source
def map_update_source(self, source=None): def map_update_source(self, source=None):
ns = source or self.map_get_source() ns = source or self.map_get_source()
if self.map != None: if self.map != None:
if source != None:
maxz = source.max_zoom
minz = source.min_zoom
if self.map.zoom > maxz:
self.map.zoom = maxz
if self.map.zoom < minz:
self.map.zoom = minz
m = self.map
RNS.log(f"Map {m.lat} {m.lon} {m.zoom}")
nlat = self.map.lat
nlon = self.map.lon
if nlat < -89: nlat = -89
if nlat > 89: nlat = 89
if nlon < -179: nlon = -179
if nlon > 179: nlon = 179
self.map.center_on(nlat,nlon)
self.map.map_source = ns self.map.map_source = ns
def map_test_action(self, sender=None): def map_layers_action(self, sender=None):
try:
ml = self.map_layer
layers = []
if self.sideband.config["map_use_offline"]:
layers.append("offline")
if self.sideband.config["map_use_online"]:
layers.append("osm")
layers.append("ve")
if ml == None: ml = layers[0]
if not ml in layers:
ml = layers[0]
mli = layers.index(ml)
mli = (mli+1)%len(layers)
ml = layers[mli]
source = None
if ml == "offline": source = self.map_get_offline_source()
if ml == "osm": source = MapSource.from_provider("osm", quad_key=False)
if ml == "ve": source = MapSource.from_provider("ve", quad_key=True)
if source != None:
self.map_layer = ml
self.map_update_source(source)
except Exception as e:
RNS.log("Error while switching map layer: "+str(e), RNS.LOG_ERROR)
def map_select_file_action(self, sender=None):
perm_ok = False perm_ok = False
if RNS.vendor.platformutils.is_android(): if self.sideband.config["map_storage_path"] == None:
perm_ok = self.check_storage_permission() if RNS.vendor.platformutils.is_android():
perm_ok = self.check_storage_permission()
if self.sideband.config["map_storage_external"]:
path = secondary_external_storage_path()
if path == None: path = primary_external_storage_path()
else:
path = primary_external_storage_path()
if self.sideband.config["map_storage_external"]:
path = secondary_external_storage_path()
if path == None: path = primary_external_storage_path()
else: else:
path = primary_external_storage_path() perm_ok = True
if self.sideband.config["map_storage_external"]:
path = "/"
else:
path = os.path.expanduser("~")
else: else:
perm_ok = True perm_ok = True
path = os.path.expanduser("~") path = self.sideband.config["map_storage_path"]
if perm_ok and path != None: if perm_ok and path != None:
self.file_manager = MDFileManager( try:
exit_manager=self.map_fm_exited, self.file_manager = MDFileManager(
select_path=self.map_fm_got_path, exit_manager=self.map_fm_exited,
) select_path=self.map_fm_got_path,
self.file_manager.ext = [".mbtiles"] )
self.file_manager.show(path) self.file_manager.ext = [".mbtiles"]
self.file_manager.show(path)
except Exception as e:
self.sideband.config["map_storage_path"] = None
self.sideband.save_configuration()
toast("Error reading directory, check permissions!")
else: else:
self.sideband.config["map_storage_path"] = None
self.sideband.save_configuration()
toast("No file access, check permissions!") toast("No file access, check permissions!")
def map_action(self, sender=None, direction="left"): def map_action(self, sender=None, direction="left"):
@ -3371,6 +3460,60 @@ class SidebandApp(MDApp):
self.map_update_markers() self.map_update_markers()
Clock.schedule_once(am_job, 0.6) Clock.schedule_once(am_job, 0.6)
def map_settings_load_states(self):
if self.map_settings_screen != None:
self.map_settings_screen.ids.map_use_online.active = self.sideband.config["map_use_online"]
self.map_settings_screen.ids.map_use_offline.active = self.sideband.config["map_use_offline"]
self.map_settings_screen.ids.map_storage_external.active = self.sideband.config["map_storage_external"]
def map_settings_init(self):
self.map_settings_load_states()
def map_settings_save(sender=None, event=None):
self.sideband.config["map_storage_external"] = self.map_settings_screen.ids.map_storage_external.active
self.sideband.config["map_use_online"] = self.map_settings_screen.ids.map_use_online.active
self.sideband.config["map_use_offline"] = self.map_settings_screen.ids.map_use_offline.active
self.sideband.save_configuration()
def external_toggle(sender=None, event=None):
self.sideband.config["map_storage_path"] = None
map_settings_save()
def offline_toggle(sender=None, event=None):
if self.map_settings_screen.ids.map_use_offline.active:
# self.map_settings_screen.ids.map_use_online.active = False
if self.sideband.config["map_storage_file"] == None:
self.map_select_file_action()
else:
self.map_settings_screen.ids.map_use_online.active = True
map_settings_save(); self.map_update_source()
def online_toggle(sender=None, event=None):
if self.map_settings_screen.ids.map_use_online.active:
# self.map_settings_screen.ids.map_use_offline.active = False
pass
else:
self.map_settings_screen.ids.map_use_offline.active = True
map_settings_save(); self.map_update_source()
self.map_settings_screen.ids.map_use_offline.bind(active=offline_toggle)
self.map_settings_screen.ids.map_use_online.bind(active=online_toggle)
self.map_settings_screen.ids.map_storage_external.bind(active=external_toggle)
def map_settings_action(self, sender=None, direction="left"):
if not self.root.ids.screen_manager.has_screen("map_settings_screen"):
self.map_settings_screen = Builder.load_string(layout_map_settings_screen)
self.map_settings_screen.app = self
self.root.ids.screen_manager.add_widget(self.map_settings_screen)
self.map_settings_screen.ids.map_config_info.text = "\n\nSideband can use map sources from the Internet, or a map source stored locally on this device in MBTiles format."
self.map_settings_screen.ids.map_settings_scrollview.effect_cls = ScrollEffect
self.map_settings_init()
self.root.ids.screen_manager.transition.direction = direction
self.root.ids.screen_manager.current = "map_settings_screen"
self.root.ids.nav_drawer.set_state("closed")
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
def close_location_error_dialog(self, sender=None): def close_location_error_dialog(self, sender=None):
if hasattr(self, "location_error_dialog") and self.location_error_dialog != None: if hasattr(self, "location_error_dialog") and self.location_error_dialog != None:
self.location_error_dialog.dismiss() self.location_error_dialog.dismiss()
@ -3391,7 +3534,7 @@ class SidebandApp(MDApp):
if not location: if not location:
self.location_error_dialog = MDDialog( self.location_error_dialog = MDDialog(
title="No Location", title="No Location",
text="During the last 24 hours, no location updates have been received from this peer. You can use the the [b]Situation Map[/b] to manually search for earlier telemetry.", text="No location updates have been received from this peer. You can use the the [b]Situation Map[/b] to manually search for earlier telemetry.",
buttons=[ buttons=[
MDRectangleFlatButton( MDRectangleFlatButton(
text="OK", text="OK",

View File

@ -171,8 +171,13 @@ class SidebandCore():
try: try:
if not os.path.isfile(self.config_path): if not os.path.isfile(self.config_path):
self.__init_config() self.__init_config()
else:
self.__load_config() self.__load_config()
else:
try:
self.__load_config()
except Exception as e:
self.__init_config()
self.__load_config()
self.first_run = False self.first_run = False
if self.config["debug"]: if self.config["debug"]:
@ -533,6 +538,13 @@ class SidebandCore():
self.config["map_zoom"] = 3 self.config["map_zoom"] = 3
if not "map_storage_external" in self.config: if not "map_storage_external" in self.config:
self.config["map_storage_external"] = False self.config["map_storage_external"] = False
if not "map_use_offline" in self.config:
self.config["map_use_offline"] = False
if not "map_use_online" in self.config:
self.config["map_use_online"] = True
if not "map_layer" in self.config:
self.config["map_layer"] = None
if not "map_storage_path" in self.config: if not "map_storage_path" in self.config:
self.config["map_storage_path"] = None self.config["map_storage_path"] = None
if not "map_storage_file" in self.config: if not "map_storage_file" in self.config:
@ -814,7 +826,7 @@ class SidebandCore():
return [] return []
def peer_location(self, context_dest): def peer_location(self, context_dest):
after_time = time.time()-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:
try: try:

View File

@ -851,6 +851,117 @@ MDScreen:
height: dp(256) height: dp(256)
""" """
layout_map_settings_screen = """
MDScreen:
name: "map_settings_screen"
BoxLayout:
orientation: "vertical"
MDTopAppBar:
title: "Map Configuration"
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_sub_map_action(self)],
]
ScrollView:
id: map_settings_scrollview
MDBoxLayout:
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
padding: [dp(28), dp(48), dp(28), dp(16)]
MDLabel:
text: "Configure Map"
font_style: "H6"
MDLabel:
id: map_config_info
markup: True
text: ""
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
MDLabel:
markup: True
text: "\\n"
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
MDBoxLayout:
orientation: "horizontal"
padding: [0,0,dp(24),0]
size_hint_y: None
height: dp(48)
MDLabel:
text: "Use online map sources"
font_style: "H6"
MDSwitch:
id: map_use_online
pos_hint: {"center_y": 0.3}
active: False
MDBoxLayout:
orientation: "horizontal"
padding: [0,0,dp(24),0]
size_hint_y: None
height: dp(48)
MDLabel:
text: "Use offline map source"
font_style: "H6"
MDSwitch:
id: map_use_offline
pos_hint: {"center_y": 0.3}
active: False
MDBoxLayout:
orientation: "horizontal"
padding: [0,0,dp(24),0]
size_hint_y: None
height: dp(48)
MDLabel:
id: map_storage_external_label
text: "Use external storage path"
font_style: "H6"
MDSwitch:
id: map_storage_external
pos_hint: {"center_y": 0.3}
active: False
MDBoxLayout:
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
padding: [0, dp(24), 0, 0]
MDRectangleFlatIconButton:
id: telemetry_icons_button
icon: "list-box-outline"
text: "Select MBTiles Map"
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.app.map_select_file_action(self)
disabled: False
"""
layout_map_screen = """ layout_map_screen = """
MDScreen: MDScreen:
name: "map_screen" name: "map_screen"
@ -869,7 +980,8 @@ MDScreen:
['format-list-bulleted-type', lambda x: root.app.map_object_list(self)], ['format-list-bulleted-type', lambda x: root.app.map_object_list(self)],
['arrow-down-bold-hexagon-outline', lambda x: root.app.telemetry_request_action(self)], ['arrow-down-bold-hexagon-outline', lambda x: root.app.telemetry_request_action(self)],
['upload-lock', lambda x: root.app.telemetry_send_update(self)], ['upload-lock', lambda x: root.app.telemetry_send_update(self)],
['wrench-cog', lambda x: root.app.map_test_action(self)], ['layers', lambda x: root.app.map_layers_action(self)],
['wrench-cog', lambda x: root.app.map_settings_action(self)],
['close', lambda x: root.app.close_any_action(self)], ['close', lambda x: root.app.close_any_action(self)],
] ]