diff --git a/sbapp/main.py b/sbapp/main.py index f5745bd..91d811a 100644 --- a/sbapp/main.py +++ b/sbapp/main.py @@ -1,3 +1,11 @@ +import RNS.vendor.umsgpack as msgpack +import threading +import base64 +import pathlib +import os +import time +import LXMF +import RNS __debug_build__ = False __disable_shaders__ = False __version__ = "1.2.0" @@ -6,54 +14,57 @@ __variant__ = "" import sys import argparse parser = argparse.ArgumentParser(description="Sideband LXMF Client") -parser.add_argument("-v", "--verbose", action='store_true', default=False, help="increase logging verbosity") -parser.add_argument("-c", "--config", action='store', default=None, help="specify path of config directory") -parser.add_argument("-d", "--daemon", action='store_true', default=False, help="run as a daemon, without user interface") -parser.add_argument("--export-settings", action='store', default=None, help="export application settings to file") -parser.add_argument("--import-settings", action='store', default=None, help="import application settings from file") -parser.add_argument("--version", action="version", version="sideband {version}".format(version=__version__)) +parser.add_argument("-v", "--verbose", action='store_true', + default=False, help="increase logging verbosity") +parser.add_argument("-c", "--config", action='store', + default=None, help="specify path of config directory") +parser.add_argument("-d", "--daemon", action='store_true', + default=False, help="run as a daemon, without user interface") +parser.add_argument("--export-settings", action='store', + default=None, help="export application settings to file") +parser.add_argument("--import-settings", action='store', + default=None, help="import application settings from file") +parser.add_argument("--version", action="version", + version="sideband {version}".format(version=__version__)) args = parser.parse_args() sys.argv = [sys.argv[0]] -import RNS -import LXMF -import time -import os -import pathlib -import base64 -import threading -import RNS.vendor.umsgpack as msgpack -WINDOW_DEFAULT_WIDTH = "494" +WINDOW_DEFAULT_WIDTH = "494" WINDOW_DEFAULT_HEIGHT = "800" app_ui_scaling_path = None + + def apply_ui_scale(): global app_ui_scaling_path default_scale = os.environ["KIVY_METRICS_DENSITY"] if "KIVY_METRICS_DENSITY" in os.environ else "unknown" config_path = None ui_scale_path = None - + try: if RNS.vendor.platformutils.is_android(): import plyer - ui_scale_path = plyer.storagepath.get_application_dir()+"/io.unsigned.sideband/files/app_storage/ui_scale" + ui_scale_path = plyer.storagepath.get_application_dir( + )+"/io.unsigned.sideband/files/app_storage/ui_scale" else: if config_path == None: import sbapp.plyer as plyer - ui_scale_path = plyer.storagepath.get_home_dir()+"/.config/sideband/app_storage/ui_scale" + ui_scale_path = plyer.storagepath.get_home_dir( + )+"/.config/sideband/app_storage/ui_scale" if ui_scale_path.startswith("file://"): ui_scale_path = ui_scale_path.replace("file://", "") else: ui_scale_path = config_path+"/app_storage/ui_scale" app_ui_scaling_path = ui_scale_path - + except Exception as e: RNS.log(f"Error while locating UI scale file: {e}", RNS.LOG_ERROR) if ui_scale_path != None: - RNS.log("Default scaling factor on this platform is "+str(default_scale), RNS.LOG_NOTICE) + RNS.log("Default scaling factor on this platform is " + + str(default_scale), RNS.LOG_NOTICE) try: RNS.log("Looking for scaling info in "+str(ui_scale_path)) if os.path.isfile(ui_scale_path): @@ -64,13 +75,16 @@ def apply_ui_scale(): if scale_factor != None: if scale_factor >= 0.3 and scale_factor <= 5.0: os.environ["KIVY_METRICS_DENSITY"] = str(scale_factor) - RNS.log("UI scaling factor set to "+str(os.environ["KIVY_METRICS_DENSITY"]), RNS.LOG_NOTICE) + RNS.log("UI scaling factor set to " + + str(os.environ["KIVY_METRICS_DENSITY"]), RNS.LOG_NOTICE) elif scale_factor == 0.0: - RNS.log("Using default UI scaling factor", RNS.LOG_NOTICE) - + RNS.log("Using default UI scaling factor", + RNS.LOG_NOTICE) except Exception as e: - RNS.log(f"Error while reading UI scaling factor: {e}", RNS.LOG_ERROR) + RNS.log( + f"Error while reading UI scaling factor: {e}", RNS.LOG_ERROR) + if args.export_settings: from .sideband.core import SidebandCore @@ -98,7 +112,8 @@ if args.export_settings: exit(0) except Exception as e: - print(f"Could not write application settings to {export_path}. The contained exception was:\n{e}") + print( + f"Could not write application settings to {export_path}. The contained exception was:\n{e}") exit(1) elif args.import_settings: @@ -115,7 +130,8 @@ elif args.import_settings: sideband.version_str = "v"+__version__+" "+__variant__ import json - addr_fields = ["lxmf_propagation_node", "last_lxmf_propagation_node", "nn_home_node", "telemetry_collector"] + addr_fields = ["lxmf_propagation_node", "last_lxmf_propagation_node", + "nn_home_node", "telemetry_collector"] try: import_path = os.path.expanduser(args.import_settings) imported = None @@ -126,7 +142,8 @@ elif args.import_settings: if k in addr_fields and imported[k] != None: imported[k] = bytes.fromhex(imported[k]) if len(imported[k]) != RNS.Reticulum.TRUNCATED_HASHLENGTH//8: - raise ValueError(f"Invalid hash length for {RNS.prettyhexrep(imported[k])}") + raise ValueError( + f"Invalid hash length for {RNS.prettyhexrep(imported[k])}") if imported: sideband.config = imported @@ -137,7 +154,8 @@ elif args.import_settings: exit(0) except Exception as e: - print(f"Could not import application settings from {import_path}. The contained exception was:\n{e}") + print( + f"Could not import application settings from {import_path}. The contained exception was:\n{e}") exit(1) if not args.daemon: @@ -149,17 +167,22 @@ if not args.daemon: class redirect_log(): def isEnabledFor(self, arg): return False + def debug(self, arg): pass + def trace(self, arg): pass + def warning(self, arg): RNS.log("Kivy error: "+str(arg), RNS.LOG_WARNING) + def critical(self, arg): RNS.log("Kivy error: "+str(arg), RNS.LOG_ERROR) if RNS.vendor.platformutils.get_platform() == "android": import jnius.reflect + def mod(method, name, signature): pass jnius.reflect.log_method = mod @@ -181,22 +204,59 @@ if not args.daemon: if args.daemon: from .sideband.core import SidebandCore + class DaemonElement(): pass + class DaemonApp(): pass - MDApp = DaemonApp; OneLineIconListItem = DaemonElement; Window = DaemonElement; Clipboard = DaemonElement; - EventLoop = DaemonElement; Clock = DaemonElement; Builder = DaemonElement; ScrollEffect = DaemonElement; SlideTransition = DaemonElement; - ScreenManager = DaemonElement; FadeTransition = DaemonElement; NoTransition = DaemonElement; OneLineIconListItem = DaemonElement; - StringProperty = DaemonElement; BaseButton = DaemonElement; MDIconButton = DaemonElement; MDFileManager = DaemonElement; - toast = DaemonElement; dp = DaemonElement; sp = DaemonElement; MDRectangleFlatButton = DaemonElement; MDDialog = DaemonElement; - colors = DaemonElement; Telemeter = DaemonElement; CustomMapMarker = DaemonElement; MBTilesMapSource = DaemonElement; - MapSource = DaemonElement; webbrowser = DaemonElement; Conversations = DaemonElement; MsgSync = DaemonElement; IconLeftWidget = DaemonElement; - NewConv = DaemonElement; Telemetry = DaemonElement; ObjectDetails = DaemonElement; Announces = DaemonElement; - Messages = DaemonElement; ts_format = DaemonElement; messages_screen_kv = DaemonElement; plyer = DaemonElement; multilingual_markup = DaemonElement; - ContentNavigationDrawer = DaemonElement; DrawerList = DaemonElement; IconListItem = DaemonElement; escape_markup = DaemonElement; - SoundLoader = DaemonElement; BoxLayout = DaemonElement; + MDApp = DaemonApp + OneLineIconListItem = DaemonElement + Window = DaemonElement + Clipboard = DaemonElement + EventLoop = DaemonElement + Clock = DaemonElement + Builder = DaemonElement + ScrollEffect = DaemonElement + SlideTransition = DaemonElement + ScreenManager = DaemonElement + FadeTransition = DaemonElement + NoTransition = DaemonElement + OneLineIconListItem = DaemonElement + StringProperty = DaemonElement + BaseButton = DaemonElement + MDIconButton = DaemonElement + MDFileManager = DaemonElement + toast = DaemonElement + dp = DaemonElement + sp = DaemonElement + MDRectangleFlatButton = DaemonElement + MDDialog = DaemonElement + colors = DaemonElement + Telemeter = DaemonElement + CustomMapMarker = DaemonElement + MBTilesMapSource = DaemonElement + MapSource = DaemonElement + webbrowser = DaemonElement + Conversations = DaemonElement + MsgSync = DaemonElement + IconLeftWidget = DaemonElement + NewConv = DaemonElement + Telemetry = DaemonElement + ObjectDetails = DaemonElement + Announces = DaemonElement + Messages = DaemonElement + ts_format = DaemonElement + messages_screen_kv = DaemonElement + plyer = DaemonElement + multilingual_markup = DaemonElement + ContentNavigationDrawer = DaemonElement + DrawerList = DaemonElement + IconListItem = DaemonElement + escape_markup = DaemonElement + SoundLoader = DaemonElement + BoxLayout = DaemonElement else: apply_ui_scale() @@ -295,18 +355,19 @@ else: ll_ot = 0.4 ll_ft = 0.275 + class SidebandApp(MDApp): STARTING = 0x00 - ACTIVE = 0x01 - PAUSED = 0x02 + ACTIVE = 0x01 + PAUSED = 0x02 STOPPING = 0x03 - PKGNAME = "io.unsigned.sideband" + PKGNAME = "io.unsigned.sideband" SERVICE_TIMEOUT = 30 EINK_BG_STR = "1,0,0,1" - EINK_BG_ARR = [1,0,0,1] + EINK_BG_ARR = [1, 0, 0, 1] def __init__(self, **kwargs): super().__init__(**kwargs) @@ -326,9 +387,11 @@ class SidebandApp(MDApp): self.config_path = None if RNS.vendor.platformutils.get_platform() == "android": - self.sideband = SidebandCore(self, config_path=self.config_path, is_client=True, android_app_dir=self.app_dir, verbose=__debug_build__) + self.sideband = SidebandCore(self, config_path=self.config_path, + is_client=True, android_app_dir=self.app_dir, verbose=__debug_build__) else: - self.sideband = SidebandCore(self, config_path=self.config_path, is_client=False, verbose=(args.verbose or __debug_build__)) + self.sideband = SidebandCore(self, config_path=self.config_path, is_client=False, verbose=( + args.verbose or __debug_build__)) self.sideband.version_str = "v"+__version__+" "+__variant__ @@ -385,8 +448,7 @@ class SidebandApp(MDApp): self.connectivity_updater = None self.last_map_update = 0 self.last_telemetry_received = 0 - self.reposository_url = None - + self.repository_url = None ################################################# # Application Startup # @@ -406,12 +468,13 @@ class SidebandApp(MDApp): self.loading_updater.cancel() def start_core(self, dt): - self.loading_updater = Clock.schedule_interval(self.update_init_status, 0.1) + self.loading_updater = Clock.schedule_interval( + self.update_init_status, 0.1) self.check_permissions() self.check_bluetooth_permissions() self.start_service() - + Clock.schedule_interval(self.jobs, 1.5) def dismiss_splash(dt): @@ -428,14 +491,15 @@ class SidebandApp(MDApp): self.sideband.setstate("app.running", True) self.sideband.setstate("app.foreground", True) Clock.schedule_once(sjob, 6.5) - + def start_service(self): if RNS.vendor.platformutils.is_android(): RNS.log("Running on Android API level "+str(android_api_version)) RNS.log("Launching platform-specific service for RNS and LXMF") if RNS.vendor.platformutils.get_platform() == "android": - self.android_service = autoclass('io.unsigned.sideband.ServiceSidebandservice') + self.android_service = autoclass( + 'io.unsigned.sideband.ServiceSidebandservice') mActivity = autoclass('org.kivy.android.PythonActivity').mActivity argument = self.app_dir self.android_service.start(mActivity, argument) @@ -446,7 +510,7 @@ class SidebandApp(MDApp): # Pre-load announce stream widgets self.update_loading_text() - + self.loader_init() if not RNS.vendor.platformutils.is_android(): self.telemetry_init() @@ -462,6 +526,7 @@ class SidebandApp(MDApp): if self.sideband.first_run: self.guide_action() + def fp(delta_time): self.request_permissions() Clock.schedule_once(fp, 5) @@ -470,15 +535,19 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.is_android(): if self.sideband.getstate("android.power_restricted", allow_cache=False): - RNS.log("Android power restrictions detected, background connectivity will not work. Asking for permissions.", RNS.LOG_DEBUG) + RNS.log( + "Android power restrictions detected, background connectivity will not work. Asking for permissions.", RNS.LOG_DEBUG) + def pm_job(dt): Settings = autoclass("android.provider.Settings") Intent = autoclass("android.content.Intent") Uri = autoclass("android.net.Uri") requestIntent = Intent() - requestIntent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) - requestIntent.setData(Uri.parse("package:io.unsigned.sideband")) + requestIntent.setAction( + Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) + requestIntent.setData( + Uri.parse("package:io.unsigned.sideband")) mActivity.startActivity(requestIntent) Clock.schedule_once(pm_job, 1.5) @@ -495,7 +564,8 @@ class SidebandApp(MDApp): def check_errors(dt): if self.sideband.getpersistent("startup.errors.rnode") != None: if self.hw_error_dialog == None or (self.hw_error_dialog != None and not self.hw_error_dialog.is_open): - description = self.sideband.getpersistent("startup.errors.rnode")["description"] + description = self.sideband.getpersistent( + "startup.errors.rnode")["description"] self.sideband.setpersistent("startup.errors.rnode", None) yes_button = MDRectangleFlatButton( text="OK", @@ -503,10 +573,12 @@ class SidebandApp(MDApp): ) self.hw_error_dialog = MDDialog( title="Hardware Error", - text="When starting a connected RNode, Reticulum reported the following error:\n\n[i]"+str(description)+"[/i]", - buttons=[ yes_button ], + text="When starting a connected RNode, Reticulum reported the following error:\n\n[i]"+str( + description)+"[/i]", + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): self.hw_error_dialog.is_open = False self.hw_error_dialog.dismiss() @@ -516,7 +588,6 @@ class SidebandApp(MDApp): Clock.schedule_once(check_errors, 1.5) - ################################################# # General helpers # ################################################# @@ -542,38 +613,38 @@ class SidebandApp(MDApp): from kivy.core.text import LabelBase, DEFAULT_FONT fb_path = self.sideband.asset_dir+"/fonts/" LabelBase.register(name="hebrew", - fn_regular=fb_path+"NotoSansHebrew-Regular.ttf", - fn_bold=fb_path+"NotoSansHebrew-Bold.ttf",) + fn_regular=fb_path+"NotoSansHebrew-Regular.ttf", + fn_bold=fb_path+"NotoSansHebrew-Bold.ttf",) LabelBase.register(name="japanese", - fn_regular=fb_path+"NotoSansJP-Regular.ttf") + fn_regular=fb_path+"NotoSansJP-Regular.ttf") LabelBase.register(name="chinese", - fn_regular=fb_path+"NotoSansSC-Regular.ttf") + fn_regular=fb_path+"NotoSansSC-Regular.ttf") LabelBase.register(name="korean", - fn_regular=fb_path+"NotoSansKR-Regular.ttf") + fn_regular=fb_path+"NotoSansKR-Regular.ttf") LabelBase.register(name="emoji", - fn_regular=fb_path+"NotoEmoji-Regular.ttf") + fn_regular=fb_path+"NotoEmoji-Regular.ttf") LabelBase.register(name="defaultinput", - fn_regular=fb_path+"DefaultInput.ttf") + fn_regular=fb_path+"DefaultInput.ttf") LabelBase.register(name="combined", - fn_regular=fb_path+"NotoSans-Regular.ttf", - fn_bold=fb_path+"NotoSans-Bold.ttf", - fn_italic=fb_path+"NotoSans-Italic.ttf", - fn_bolditalic=fb_path+"NotoSans-BoldItalic.ttf") + fn_regular=fb_path+"NotoSans-Regular.ttf", + fn_bold=fb_path+"NotoSans-Bold.ttf", + fn_italic=fb_path+"NotoSans-Italic.ttf", + fn_bolditalic=fb_path+"NotoSans-BoldItalic.ttf") LabelBase.register(name="mono", - fn_regular=fb_path+"RobotoMonoNerdFont-Regular.ttf") + fn_regular=fb_path+"RobotoMonoNerdFont-Regular.ttf") LabelBase.register(name="term", - fn_regular=fb_path+"BigBlueTerm437NerdFont-Regular.ttf") + fn_regular=fb_path+"BigBlueTerm437NerdFont-Regular.ttf") LabelBase.register(name="nf", - fn_regular=fb_path+"RobotoMonoNerdFont-Regular.ttf") + fn_regular=fb_path+"RobotoMonoNerdFont-Regular.ttf") def update_input_language(self): language = self.sideband.config["input_language"] @@ -581,8 +652,9 @@ class SidebandApp(MDApp): self.input_font = "defaultinput" else: self.input_font = language - - RNS.log("Setting input language to "+str(self.input_font), RNS.LOG_DEBUG) + + RNS.log("Setting input language to " + + str(self.input_font), RNS.LOG_DEBUG) # def modify_input_font(self, ids): # BIND_CLASSES = ["kivymd.uix.textfield.textfield.MDTextField",] @@ -598,17 +670,17 @@ class SidebandApp(MDApp): self.color_reject = colors["DeepOrange"]["900"] self.color_accept = colors["LightGreen"]["700"] if not self.sideband.config["eink_mode"]: - self.color_hover = colors["Dark"]["CardsDialogs"] + self.color_hover = colors["Dark"]["CardsDialogs"] else: - self.color_hover = colors["Gray"]["800"] + self.color_hover = colors["Gray"]["800"] else: self.color_reject = colors["DeepOrange"]["800"] self.color_accept = colors["LightGreen"]["700"] if not self.sideband.config["eink_mode"]: - self.color_hover = colors["Light"]["CardsDialogs"] + self.color_hover = colors["Light"]["CardsDialogs"] else: - self.color_hover = colors["Light"]["AppBar"] - + self.color_hover = colors["Light"]["AppBar"] + self.apply_eink_mods() self.set_bars_colors() @@ -633,20 +705,24 @@ class SidebandApp(MDApp): def set_bars_colors(self): if RNS.vendor.platformutils.get_platform() == "android": - def set_navicons(set_dark_icons = False): + def set_navicons(set_dark_icons=False): from android.runnable import run_on_ui_thread from jnius import autoclass - WindowManager = autoclass("android.view.WindowManager$LayoutParams") - activity = autoclass("org.kivy.android.PythonActivity").mActivity + WindowManager = autoclass( + "android.view.WindowManager$LayoutParams") + activity = autoclass( + "org.kivy.android.PythonActivity").mActivity View = autoclass("android.view.View") def uit_exec(): window = activity.getWindow() window.clearFlags(WindowManager.FLAG_TRANSLUCENT_STATUS) - window.addFlags(WindowManager.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) + window.addFlags( + WindowManager.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) if set_dark_icons: - window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) + window.getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) else: window.getDecorView().setSystemUiVisibility(0) @@ -718,24 +794,28 @@ class SidebandApp(MDApp): image.save(file_path) i_file = File(file_path) - image_uri = FileProvider.getUriForFile(mActivity, "io.unsigned.sideband.provider", i_file) + image_uri = FileProvider.getUriForFile( + mActivity, "io.unsigned.sideband.provider", i_file) shareIntent = Intent() shareIntent.setAction(Intent.ACTION_SEND) shareIntent.setType("image/png") - shareIntent.putExtra(Intent.EXTRA_STREAM, cast('android.os.Parcelable', image_uri)) + shareIntent.putExtra(Intent.EXTRA_STREAM, cast( + 'android.os.Parcelable', image_uri)) mActivity.startActivity(shareIntent) except Exception as e: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Export Error", - text="The resource could not be exported and shared:\n\n"+str(e), - buttons=[ ok_button ], + text="The resource could not be exported and shared:\n\n" + + str(e), + buttons=[ok_button], ) + def dl_ok(s): dialog.dismiss() - + ok_button.bind(on_release=dl_ok) dialog.open() @@ -765,12 +845,13 @@ class SidebandApp(MDApp): if self.conversations_view != None: self.conversations_view.ids.conversations_scrollview.effect_cls = ScrollEffect self.conversations_view.ids.conversations_scrollview.scroll = 1 - + else: RNS.log("Conversations view did not exist", RNS.LOG_DEBUG) def ui_update_job(): time.sleep(0.05) + def cb(dt): self.perform_wake_update() Clock.schedule_once(cb, 0.1) @@ -801,16 +882,16 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.is_android(): RNS.log("Performing app wake UI update", RNS.LOG_DEBUG) self.root.ids.nav_drawer.set_state("open") + def cb(dt): self.root.ids.nav_drawer.set_state("closed") Clock.schedule_once(cb, 0) - def check_bluetooth_permissions(self): if RNS.vendor.platformutils.get_platform() == "android": mActivity = autoclass('org.kivy.android.PythonActivity').mActivity Context = autoclass('android.content.Context') - + if android_api_version > 30: bt_permission_name = "android.permission.BLUETOOTH_CONNECT" else: @@ -822,11 +903,13 @@ class SidebandApp(MDApp): if android_api_version > 30: if check_permission("android.permission.BLUETOOTH_SCAN"): RNS.log("Have bluetooth scan permissions", RNS.LOG_DEBUG) - self.sideband.setpersistent("permissions.bluetooth", True) + self.sideband.setpersistent( + "permissions.bluetooth", True) else: RNS.log("Do not have bluetooth scan permissions") - self.sideband.setpersistent("permissions.bluetooth", False) + self.sideband.setpersistent( + "permissions.bluetooth", False) else: self.sideband.setpersistent("permissions.bluetooth", True) @@ -841,17 +924,20 @@ class SidebandApp(MDApp): mActivity = autoclass('org.kivy.android.PythonActivity').mActivity Context = autoclass('android.content.Context') NotificationManager = autoclass('android.app.NotificationManager') - notification_service = cast(NotificationManager, mActivity.getSystemService(Context.NOTIFICATION_SERVICE)) + notification_service = cast( + NotificationManager, mActivity.getSystemService(Context.NOTIFICATION_SERVICE)) if notification_service.areNotificationsEnabled(): self.sideband.setpersistent("permissions.notifications", True) else: if check_permission("android.permission.POST_NOTIFICATIONS"): RNS.log("Have notification permissions", RNS.LOG_DEBUG) - self.sideband.setpersistent("permissions.notifications", True) + self.sideband.setpersistent( + "permissions.notifications", True) else: RNS.log("Do not have notification permissions") - self.sideband.setpersistent("permissions.notifications", False) + self.sideband.setpersistent( + "permissions.notifications", False) else: self.sideband.setpersistent("permissions.notifications", True) @@ -863,7 +949,7 @@ class SidebandApp(MDApp): if not check_permission("android.permission.POST_NOTIFICATIONS"): RNS.log("Requesting notification permission", RNS.LOG_DEBUG) request_permissions(["android.permission.POST_NOTIFICATIONS"]) - + self.check_permissions() def request_microphone_permission(self): @@ -886,16 +972,17 @@ class SidebandApp(MDApp): if Environment.isExternalStorageManager(): storage_permissions_ok = True else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Storage Permission", text="Sideband needs external storage permission to read offline map files.\n\nOn this Android version, the Manage All Files permission is needed, since normal external storage permission is no longer supported.\n\nSideband will only ever read and write to files you select, and does not read any other data from your system.", - buttons=[ ok_button ], + buttons=[ok_button], ) + def dl_ok(s): dialog.dismiss() self.request_storage_permission() - + ok_button.bind(on_release=dl_ok) dialog.open() @@ -906,23 +993,27 @@ class SidebandApp(MDApp): if android_api_version < 30: if not check_permission("android.permission.WRITE_EXTERNAL_STORAGE"): RNS.log("Requesting storage write permission", RNS.LOG_DEBUG) - request_permissions(["android.permission.WRITE_EXTERNAL_STORAGE"]) - + request_permissions( + ["android.permission.WRITE_EXTERNAL_STORAGE"]) + if not check_permission("android.permission.READ_EXTERNAL_STORAGE"): RNS.log("Requesting storage read permission", RNS.LOG_DEBUG) - request_permissions(["android.permission.READ_EXTERNAL_STORAGE"]) + request_permissions( + ["android.permission.READ_EXTERNAL_STORAGE"]) else: Intent = autoclass('android.content.Intent') Settings = autoclass('android.provider.Settings') pIntent = Intent() - pIntent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) + pIntent.setAction( + Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) mActivity.startActivity(pIntent) def request_bluetooth_permissions(self): if RNS.vendor.platformutils.get_platform() == "android": if not check_permission("android.permission.BLUETOOTH_CONNECT") or not check_permission("android.permission.BLUETOOTH_SCAN"): RNS.log("Requesting Bluetooth permissions", RNS.LOG_DEBUG) - request_permissions(["android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_SCAN"]) + request_permissions( + ["android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_SCAN"]) self.check_bluetooth_permissions() @@ -941,19 +1032,22 @@ class SidebandApp(MDApp): if extras: data = extras.getString("intent_action", "undefined") if data.startswith("conversation."): - conv_hexhash = bytes.fromhex(data.replace("conversation.", "")) + conv_hexhash = bytes.fromhex( + data.replace("conversation.", "")) + def cb(dt): self.open_conversation(conv_hexhash) Clock.schedule_once(cb, 0.2) except Exception as e: - RNS.log(f"Error while getting intent action data: {e}", RNS.LOG_ERROR) + RNS.log( + f"Error while getting intent action data: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) if intent_action == "android.intent.action.WEB_SEARCH": SearchManager = autoclass('android.app.SearchManager') data = intent.getStringExtra(SearchManager.QUERY) - + if data.lower().startswith(LXMF.LXMessage.URI_SCHEMA): action = "lxm_uri" @@ -972,25 +1066,30 @@ class SidebandApp(MDApp): target_path = target.getPath() target_filename = target.getLastPathSegment() - RNS.log(f"Received share intent: {target_uri} / {target_path} / {target_filename}", RNS.LOG_DEBUG) + RNS.log( + f"Received share intent: {target_uri} / {target_path} / {target_filename}", RNS.LOG_DEBUG) for cf in os.listdir(self.sideband.share_cache): rt = os.path.join(self.sideband.share_cache, cf) os.unlink(rt) - RNS.log("Removed previously cached data: "+str(rt), RNS.LOG_DEBUG) + RNS.log("Removed previously cached data: " + + str(rt), RNS.LOG_DEBUG) ContentResolver = autoclass("android.content.ContentResolver") cr = mActivity.getContentResolver() - cache_path = os.path.join(self.sideband.share_cache, target_filename) + cache_path = os.path.join( + self.sideband.share_cache, target_filename) input_stream = cr.openInputStream(target) with open(cache_path, "wb") as cache_file: cache_file.write(bytes(input_stream.readAllBytes())) - RNS.log("Cached shared data from Android intent", RNS.LOG_DEBUG) + RNS.log("Cached shared data from Android intent", + RNS.LOG_DEBUG) action = "shared_data" data = {"filename": target_filename, "data_path": cache_path} except Exception as e: - RNS.log(f"Error while getting intent action data: {e}", RNS.LOG_ERROR) + RNS.log( + f"Error while getting intent action data: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) if action != None: @@ -1002,18 +1101,21 @@ class SidebandApp(MDApp): if action == "shared_data": RNS.log("Got shared data: "+str(data)) + def cb(dt): try: self.shared_attachment_action(data) except Exception as e: - RNS.log("Error while handling external message attachment", RNS.LOG_ERROR) + RNS.log( + "Error while handling external message attachment", RNS.LOG_ERROR) RNS.trace_exception(e) Clock.schedule_once(cb, 0.1) def ingest_lxm_uri(self, lxm_uri): - RNS.log("Ingesting LXMF paper message from URI: "+str(lxm_uri), RNS.LOG_DEBUG) + RNS.log("Ingesting LXMF paper message from URI: " + + str(lxm_uri), RNS.LOG_DEBUG) self.sideband.lxm_ingest_uri(lxm_uri) - + def build(self): FONT_PATH = self.sideband.asset_dir+"/fonts" if RNS.vendor.platformutils.is_darwin(): @@ -1026,13 +1128,15 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.is_android(): ActivityInfo = autoclass('android.content.pm.ActivityInfo') activity = autoclass('org.kivy.android.PythonActivity').mActivity - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) + activity.setRequestedOrientation( + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) from android import activity as a_activity a_activity.bind(on_new_intent=self.on_new_intent) if self.sideband.config["eink_mode"] == True: - screen = Builder.load_string(root_layout.replace("app.theme_cls.bg_darkest", "app.theme_cls.bg_light")) + screen = Builder.load_string(root_layout.replace( + "app.theme_cls.bg_darkest", "app.theme_cls.bg_light")) else: screen = Builder.load_string(root_layout) @@ -1049,17 +1153,19 @@ class SidebandApp(MDApp): if time.time() - self.service_last_available > SidebandApp.SERVICE_TIMEOUT: if self.app_state == SidebandApp.ACTIVE: info_text = "The Reticulum and LXMF service seem to have disappeared, and Sideband is no longer connected. This should not happen, and probably indicates a bug in the background service. Please restart Sideband to regain connectivity." - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton( + text="OK", font_size=dp(18)) dialog = MDDialog( title="Error", text=info_text, - buttons=[ ok_button ], + buttons=[ok_button], # elevation=0, ) + def dl_ok(s): dialog.dismiss() self.quit_action(s) - + ok_button.bind(on_release=dl_ok) self.final_load_completed = False dialog.open() @@ -1071,21 +1177,25 @@ class SidebandApp(MDApp): self.service_last_available = time.time() if RNS.vendor.platformutils.is_android(): - rnode_errors = self.sideband.getpersistent("runtime.errors.rnode") + rnode_errors = self.sideband.getpersistent( + "runtime.errors.rnode") if rnode_errors != None: if self.hw_error_dialog == None or (self.hw_error_dialog != None and not self.hw_error_dialog.is_open): description = rnode_errors["description"] - self.sideband.setpersistent("runtime.errors.rnode", None) + self.sideband.setpersistent( + "runtime.errors.rnode", None) yes_button = MDRectangleFlatButton( text="OK", font_size=dp(18), ) self.hw_error_dialog = MDDialog( title="Hardware Error", - text="While communicating with an RNode, Reticulum reported the following error:\n\n[i]"+str(description)+"[/i]", - buttons=[ yes_button ], + text="While communicating with an RNode, Reticulum reported the following error:\n\n[i]"+str( + description)+"[/i]", + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): self.hw_error_dialog.dismiss() self.hw_error_dialog.is_open = False @@ -1093,7 +1203,6 @@ class SidebandApp(MDApp): self.hw_error_dialog.open() self.hw_error_dialog.is_open = True - if self.root.ids.screen_manager.current == "messages_screen": self.messages_view.update() @@ -1108,7 +1217,8 @@ class SidebandApp(MDApp): if self.sideband.getstate("app.flags.lxmf_sync_dialog_open", allow_cache=True) and self.sync_dialog != None: state = self.sideband.message_router.propagation_transfer_state - dlg_sp = self.sideband.get_sync_progress()*100; dlg_ss = self.sideband.get_sync_status() + dlg_sp = self.sideband.get_sync_progress()*100 + dlg_ss = self.sideband.get_sync_status() if state > LXMF.LXMRouter.PR_IDLE and state <= LXMF.LXMRouter.PR_COMPLETE: self.sync_dialog.ids.sync_progress.value = dlg_sp else: @@ -1132,7 +1242,8 @@ class SidebandApp(MDApp): self.sideband.config["map_lon"] = self.map_screen.ids.map_layout.map.lon self.sideband.config["map_zoom"] = self.map_screen.ids.map_layout.map.zoom - self.last_telemetry_received = self.sideband.getstate("app.flags.last_telemetry", allow_cache=True) or 0 + self.last_telemetry_received = self.sideband.getstate( + "app.flags.last_telemetry", allow_cache=True) or 0 if self.last_telemetry_received > self.last_map_update: self.map_update_markers() @@ -1158,37 +1269,40 @@ class SidebandApp(MDApp): else: info_text = str(imr) self.sideband.setstate("lxm_uri_ingest.result", False) - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Message Scan", text=info_text, - buttons=[ ok_button ], + buttons=[ok_button], # elevation=0, ) + def dl_ok(s): dialog.dismiss() - + ok_button.bind(on_release=dl_ok) dialog.open() invalid_values = ["None", "False", "True", True, False, None] - hwe = self.sideband.getstate("hardware_operation.error", allow_cache=True) + hwe = self.sideband.getstate( + "hardware_operation.error", allow_cache=True) if hwe: if hwe in invalid_values: self.sideband.setstate("hardware_operation.error", False) else: info_text = str(hwe) self.sideband.setstate("hardware_operation.error", False) - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Error", text=info_text, - buttons=[ ok_button ], + buttons=[ok_button], # elevation=0, ) + def dl_ok(s): dialog.dismiss() - + ok_button.bind(on_release=dl_ok) dialog.open() @@ -1204,7 +1318,8 @@ class SidebandApp(MDApp): self.last_exit_event = time.time() self.root.ids.screen_manager.transition = self.slide_transition self.root.ids.screen_manager.transition.duration = TRANSITION_DURATION - self.root.ids.screen_manager.transition.bind(on_complete=self.screen_transition_complete) + self.root.ids.screen_manager.transition.bind( + on_complete=self.screen_transition_complete) EventLoop.window.bind(on_keyboard=self.keyboard_event) EventLoop.window.bind(on_key_down=self.keydown_event) @@ -1232,7 +1347,6 @@ class SidebandApp(MDApp): self.key_ptt_down = False self.message_ptt_up_action() - def keydown_event(self, instance, keyboard, keycode, text, modifiers): if self.keyboard_enabled: if self.root.ids.screen_manager.current == "map_screen": @@ -1244,12 +1358,18 @@ class SidebandApp(MDApp): else: nav_mod = 1.0 - if keycode == 79 or text == "d" or text == "l": self.map_nav_right(modifier=nav_mod) - if keycode == 80 or text == "a" or text == "h": self.map_nav_left(modifier=nav_mod) - if keycode == 81 or text == "s" or text == "j": self.map_nav_down(modifier=nav_mod) - if keycode == 82 or text == "w" or text == "k": self.map_nav_up(modifier=nav_mod) - if text == "q" or text == "-": self.map_nav_zoom_out(modifier=nav_mod) - if text == "e" or text == "+": self.map_nav_zoom_in(modifier=nav_mod) + if keycode == 79 or text == "d" or text == "l": + self.map_nav_right(modifier=nav_mod) + if keycode == 80 or text == "a" or text == "h": + self.map_nav_left(modifier=nav_mod) + if keycode == 81 or text == "s" or text == "j": + self.map_nav_down(modifier=nav_mod) + if keycode == 82 or text == "w" or text == "k": + self.map_nav_up(modifier=nav_mod) + if text == "q" or text == "-": + self.map_nav_zoom_out(modifier=nav_mod) + if text == "e" or text == "+": + self.map_nav_zoom_in(modifier=nav_mod) if True or self.root.ids.screen_manager.current == "conversations_screen": if len(modifiers) > 0 and "ctrl" in modifiers: @@ -1262,15 +1382,16 @@ class SidebandApp(MDApp): if not self.messages_view.ids.message_text.focus: self.messages_view.ids.message_text.write_tab = False self.messages_view.ids.message_text.focus = True + def tab_job(delta): self.messages_view.ids.message_text.write_tab = True Clock.schedule_once(tab_job, 0.15) elif self.rec_dialog != None and self.rec_dialog_is_open: - if text == " ": - self.msg_rec_a_rec(None) - elif keycode == 40: - self.msg_rec_a_save(None) + if text == " ": + self.msg_rec_a_rec(None) + elif keycode == 40: + self.msg_rec_a_save(None) elif not self.rec_dialog_is_open and not self.messages_view.ids.message_text.focus and self.messages_view.ptt_enabled and keycode == 44: if not self.key_ptt_down: @@ -1284,11 +1405,14 @@ class SidebandApp(MDApp): self.attach_type = None self.update_message_widgets() if text == "a": - clear_att(); self.message_attachment_action(None) + clear_att() + self.message_attachment_action(None) if text == "i": - clear_att(); self.message_attach_action(attach_type="defimg") + clear_att() + self.message_attach_action(attach_type="defimg") if text == "f": - clear_att(); self.message_attach_action(attach_type="file") + clear_att() + self.message_attach_action(attach_type="file") if text == "v": clear_att() self.audio_msg_mode = LXMF.AM_OPUS_OGG @@ -1302,7 +1426,7 @@ class SidebandApp(MDApp): if modifiers[0] == "ctrl": if text == "q": self.quit_action(self) - + if text == "w": if self.root.ids.screen_manager.current == "conversations_screen": if self.include_conversations and not self.include_objects: @@ -1321,11 +1445,11 @@ class SidebandApp(MDApp): self.close_sub_utilities_action() else: self.open_conversations(direction="right") - + if text == "s" or text == "d": if self.root.ids.screen_manager.current == "messages_screen": self.message_send_action() - + if text == "l": if self.root.ids.screen_manager.current == "messages_screen": self.message_propagation_action(self) @@ -1333,7 +1457,7 @@ class SidebandApp(MDApp): self.map_layers_action() else: self.announces_action(self) - + if text == "m": if self.root.ids.screen_manager.current == "messages_screen": context_dest = self.messages_view.ids.messages_scrollview.active_conversation @@ -1343,16 +1467,17 @@ class SidebandApp(MDApp): self.map_show_peer_location(context_dest) else: self.map_action(self) - + if text == "p": if self.root.ids.screen_manager.current == "map_screen": self.map_settings_action() else: self.settings_action(self) - + if text == "t": 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: @@ -1370,7 +1495,8 @@ class SidebandApp(MDApp): if text == "r": if self.root.ids.screen_manager.current == "conversations_screen": if self.include_objects: - self.conversations_action(self, direction="right") + self.conversations_action( + self, direction="right") else: self.lxmf_sync_action(self) elif self.root.ids.screen_manager.current == "telemetry_screen": @@ -1381,18 +1507,19 @@ class SidebandApp(MDApp): 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") + self.conversations_action( + self, direction="right") else: self.conversations_action(self, direction="right") - + if len(modifiers) > 0 and modifiers[0] == 'ctrl' and (text == "g"): self.guide_action(self) - + if text == "n": if self.root.ids.screen_manager.current == "conversations_screen": if not hasattr(self, "dialog_open") or not self.dialog_open: self.new_conversation_action(self) - + def keyboard_event(self, window, key, *largs): if self.keyboard_enabled: # Handle escape/back @@ -1446,9 +1573,11 @@ class SidebandApp(MDApp): else: Clipboard.copy(sender.text) action = "tap" if RNS.vendor.platformutils.is_android() else "click" - toast(f"Field copied, double-{action} any empty field to paste") + toast( + f"Field copied, double-{action} any empty field to paste") except Exception as e: - RNS.log("An error occurred while handling clipboard action: "+str(e), RNS.LOG_ERROR) + RNS.log( + "An error occurred while handling clipboard action: "+str(e), RNS.LOG_ERROR) def loader_init(self, sender=None): if not self.root.ids.screen_manager.has_screen("loader_screen"): @@ -1476,7 +1605,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition = NoTransition() self.root.ids.screen_manager.current = "exit_screen" - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) self.sideband.setstate("app.running", False) self.sideband.setstate("app.foreground", False) @@ -1491,7 +1621,8 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.is_android(): RNS.log("Finishing activity") - activity = autoclass('org.kivy.android.PythonActivity').mActivity + activity = autoclass( + 'org.kivy.android.PythonActivity').mActivity activity.finishAndRemoveTask() else: RNS.exit() @@ -1503,27 +1634,28 @@ class SidebandApp(MDApp): def announce_now_action(self, sender=None): self.sideband.lxmf_announce() - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Announce Sent", text="Your LXMF address has been announced on all available interfaces", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() - + yes_button.bind(on_release=dl_yes) dialog.open() - ################################################# # Screens # ################################################# - ### Messages (conversation) screen + # Messages (conversation) screen ###################################### + def conversation_from_announce_action(self, context_dest): if self.sideband.has_conversation(context_dest): pass @@ -1543,8 +1675,10 @@ class SidebandApp(MDApp): def conversation_action(self, sender): context_dest = sender.sb_uid + def cb(dt): self.open_conversation(context_dest) + def cbu(dt): self.conversations_view.update() Clock.schedule_once(cb, 0.15) @@ -1576,7 +1710,8 @@ class SidebandApp(MDApp): self.messages_view.ids.messages_scrollview.add_widget(list_widget) self.messages_view.ids.messages_scrollview.scroll_y = 0.0 - conv_title = multilingual_markup(escape_markup(str(self.sideband.peer_display_name(context_dest))).encode("utf-8")).decode("utf-8") + conv_title = multilingual_markup(escape_markup(str( + self.sideband.peer_display_name(context_dest))).encode("utf-8")).decode("utf-8") self.messages_view.ids.messages_toolbar.title = conv_title self.messages_view.ids.messages_scrollview.active_conversation = context_dest self.sideband.setstate("app.active_conversation", context_dest) @@ -1586,10 +1721,10 @@ class SidebandApp(MDApp): self.update_message_widgets() self.messages_view.ids.message_text.disabled = False - self.root.ids.screen_manager.current = "messages_screen" - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) - + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) + self.sideband.read_conversation(context_dest) self.sideband.setstate("app.flags.unread_conversations", True) @@ -1616,6 +1751,7 @@ class SidebandApp(MDApp): def message_send_dispatch(self, sender=None): self.messages_view.ids.message_send_button.disabled = True + def cb(dt): self.messages_view.ids.message_send_button.disabled = False Clock.schedule_once(cb, 0.5) @@ -1649,9 +1785,10 @@ class SidebandApp(MDApp): if not self.outbound_mode_command and not self.outbound_mode_paper: if self.attach_type != None and self.attach_path != None: try: - RNS.log("Processing "+str(self.attach_type)+" attachment \""+str(self.attach_path)+"\"", RNS.LOG_DEBUG) + RNS.log("Processing "+str(self.attach_type) + + " attachment \""+str(self.attach_path)+"\"", RNS.LOG_DEBUG) fbn = os.path.basename(self.attach_path) - + if self.attach_type == "file": with open(self.attach_path, "rb") as af: attachment = [fbn, af.read()] @@ -1659,10 +1796,12 @@ class SidebandApp(MDApp): if self.attach_type == "audio": if self.audio_msg_mode == LXMF.AM_OPUS_OGG: with open(self.attach_path, "rb") as af: - audio = [self.audio_msg_mode, af.read()] + audio = [ + self.audio_msg_mode, af.read()] elif self.audio_msg_mode >= LXMF.AM_CODEC2_700C and self.audio_msg_mode <= LXMF.AM_CODEC2_3200: with open(self.attach_path, "rb") as af: - audio = [self.audio_msg_mode, af.read()] + audio = [ + self.audio_msg_mode, af.read()] elif self.attach_type == "lbimg": max_size = 320, 320 @@ -1691,7 +1830,8 @@ class SidebandApp(MDApp): except Exception as e: self.messages_view.send_error_dialog = MDDialog( title="Attachment Error", - text="An error occurred while processing the attachment:\n\n[i]"+str(e)+"[/i]", + text="An error occurred while processing the attachment:\n\n[i]"+str( + e)+"[/i]", buttons=[ MDRectangleFlatButton( text="OK", @@ -1734,8 +1874,8 @@ class SidebandApp(MDApp): self.messages_view.ids.message_text.text = "" self.messages_view.ids.messages_scrollview.scroll_y = 0 self.jobs(0) - - elif self.sideband.send_message(msg_content, context_dest, self.outbound_mode_propagation, attachment = attachment, image = image, audio = audio): + + elif self.sideband.send_message(msg_content, context_dest, self.outbound_mode_propagation, attachment=attachment, image=image, audio=audio): self.messages_view.ids.message_text.text = "" self.messages_view.ids.messages_scrollview.scroll_y = 0 self.jobs(0) @@ -1795,15 +1935,16 @@ class SidebandApp(MDApp): tf = open(path, "rb") tf.close() self.attach_path = path - + if RNS.vendor.platformutils.is_android(): toast("Attached \""+str(fbn)+"\"") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="File Attached", - text="The file \""+str(fbn)+"\" was attached, and will be included with the next message sent.", - buttons=[ ok_button ], + text="The file \"" + + str(fbn)+"\" was attached, and will be included with the next message sent.", + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() @@ -1813,18 +1954,18 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.get_platform() == "android": toast("Could not attach \""+str(fbn)+"\"") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Attachment Error", - text="The specified file could not be attached:\n\n[i]"+str(e)+"[/i]", - buttons=[ ok_button ], + text="The specified file could not be attached:\n\n[i]"+str( + e)+"[/i]", + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() self.update_message_widgets() - def message_fm_exited(self, *args): self.manager_open = False if self.file_manager != None: @@ -1840,7 +1981,6 @@ class SidebandApp(MDApp): perm_ok = True path = os.path.expanduser("~") - if perm_ok and path != None: try: if self.attach_type in ["lbimg", "defimg", "hqimg"]: @@ -1863,24 +2003,25 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.get_platform() == "android": toast("Error reading directory, check permissions!") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton( + text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Attachment Error", text="Error reading directory, check permissions!", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() - + else: if RNS.vendor.platformutils.get_platform() == "android": toast("No file access, check permissions!") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Attachment Error", text="No file access, check permissions!", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() @@ -1956,21 +2097,22 @@ class SidebandApp(MDApp): elif audio_field[0] >= LXMF.AM_CODEC2_700C and audio_field[0] <= LXMF.AM_CODEC2_3200: temp_path = self.sideband.rec_cache+"/msg.ogg" from sideband.audioproc import samples_to_ogg, decode_codec2, detect_codec2 - + target_rate = 8000 if RNS.vendor.platformutils.is_linux(): target_rate = 48000 if detect_codec2(): if samples_to_ogg(decode_codec2(audio_field[1], audio_field[0]), temp_path, input_rate=8000, output_rate=target_rate): - RNS.log("Wrote OGG file to: "+temp_path, RNS.LOG_DEBUG) + RNS.log("Wrote OGG file to: " + + temp_path, RNS.LOG_DEBUG) else: RNS.log("OGG write failed", RNS.LOG_DEBUG) else: self.last_msg_audio = None self.display_codec2_error() return - + else: raise NotImplementedError(audio_field[0]) @@ -1980,7 +2122,7 @@ class SidebandApp(MDApp): self.request_microphone_permission() else: from sbapp.plyer import audio - + self.msg_sound = audio self.msg_sound._file_path = temp_path @@ -1994,7 +2136,8 @@ class SidebandApp(MDApp): RNS.log("Starting playback", RNS.LOG_DEBUG) self.msg_sound.play() else: - RNS.log("Playback was requested, but no audio data was loaded for playback", RNS.LOG_ERROR) + RNS.log( + "Playback was requested, but no audio data was loaded for playback", RNS.LOG_ERROR) except Exception as e: RNS.log("Error while playing message audio:"+str(e)) @@ -2016,15 +2159,15 @@ class SidebandApp(MDApp): self.rec_dialog.recording = True el_button = self.messages_view.ids.message_ptt_button el_icon = self.messages_view.ids.message_ptt_button.children[0].children[1] - el_button.theme_text_color="Custom" - el_button.text_color=mdc("Orange","400") - el_button.line_color=mdc("Orange","400") - el_icon.theme_text_color="Custom" - el_icon.text_color=mdc("Orange","400") + el_button.theme_text_color = "Custom" + el_button.text_color = mdc("Orange", "400") + el_button.line_color = mdc("Orange", "400") + el_icon.theme_text_color = "Custom" + el_icon.text_color = mdc("Orange", "400") + def cb(dt): self.msg_audio.start() Clock.schedule_once(cb, 0.15) - def message_ptt_up_action(self, sender=None): if not self.sideband.ui_recording: @@ -2033,16 +2176,18 @@ class SidebandApp(MDApp): self.rec_dialog.recording = False el_button = self.messages_view.ids.message_ptt_button el_icon = self.messages_view.ids.message_ptt_button.children[0].children[1] - el_button.theme_text_color="Custom" - el_button.text_color=mdc("BlueGray","500") - el_button.line_color=mdc("BlueGray","500") - el_icon.theme_text_color="Custom" - el_icon.text_color=mdc("BlueGray","500") + el_button.theme_text_color = "Custom" + el_button.text_color = mdc("BlueGray", "500") + el_button.line_color = mdc("BlueGray", "500") + el_icon.theme_text_color = "Custom" + el_icon.text_color = mdc("BlueGray", "500") + def cb_s(dt): try: self.msg_audio.stop() except Exception as e: - RNS.log("An error occurred while stopping recording: "+str(e), RNS.LOG_ERROR) + RNS.log("An error occurred while stopping recording: " + + str(e), RNS.LOG_ERROR) RNS.trace_exception(e) self.sideband.ui_stopped_recording() @@ -2057,10 +2202,12 @@ class SidebandApp(MDApp): if proc_path: self.attach_path = proc_path os.unlink(self.msg_audio._file_path) - RNS.log("Using voice-processed OPUS data in OGG container", RNS.LOG_DEBUG) + RNS.log( + "Using voice-processed OPUS data in OGG container", RNS.LOG_DEBUG) else: self.attach_path = self.msg_audio._file_path - RNS.log("Using unmodified OPUS data in OGG container", RNS.LOG_DEBUG) + RNS.log("Using unmodified OPUS data in OGG container", + RNS.LOG_DEBUG) else: ap_start = time.time() from sideband.audioproc import voice_processing @@ -2068,22 +2215,25 @@ class SidebandApp(MDApp): if proc_path: opus_file = pyogg.OpusFile(proc_path) - RNS.log("Using voice-processed audio for codec2 encoding", RNS.LOG_DEBUG) + RNS.log( + "Using voice-processed audio for codec2 encoding", RNS.LOG_DEBUG) else: opus_file = pyogg.OpusFile(self.msg_audio._file_path) - RNS.log("Using unprocessed audio data for codec2 encoding", RNS.LOG_DEBUG) + RNS.log( + "Using unprocessed audio data for codec2 encoding", RNS.LOG_DEBUG) - RNS.log(f"OPUS LOAD {opus_file.frequency}Hz {opus_file.bytes_per_sample*8}bit {opus_file.channels}ch") + RNS.log( + f"OPUS LOAD {opus_file.frequency}Hz {opus_file.bytes_per_sample*8}bit {opus_file.channels}ch") audio = AudioSegment( bytes(opus_file.as_array()), frame_rate=opus_file.frequency, - sample_width=opus_file.bytes_per_sample, + sample_width=opus_file.bytes_per_sample, channels=opus_file.channels, ) audio = audio.split_to_mono()[0] audio = audio.apply_gain(-audio.max_dBFS) - + if self.audio_msg_mode >= LXMF.AM_CODEC2_700C and self.audio_msg_mode <= LXMF.AM_CODEC2_3200: audio = audio.set_frame_rate(8000) audio = audio.set_sample_width(2) @@ -2094,7 +2244,8 @@ class SidebandApp(MDApp): encoded = encode_codec2(samples, self.audio_msg_mode) ap_duration = time.time() - ap_start - RNS.log("Audio processing complete in "+RNS.prettytime(ap_duration), RNS.LOG_DEBUG) + RNS.log("Audio processing complete in " + + RNS.prettytime(ap_duration), RNS.LOG_DEBUG) export_path = self.sideband.rec_cache+"/recording.enc" with open(export_path, "wb") as export_file: @@ -2121,23 +2272,27 @@ class SidebandApp(MDApp): def a_rec_action(sender): if not self.rec_dialog.recording: self.sideband.ui_started_recording() - RNS.log("Starting recording...") # TODO: Remove + RNS.log("Starting recording...") # TODO: Remove self.rec_dialog.recording = True el = self.rec_dialog.rec_item.children[0].children[0] - el.ttc = el.theme_text_color; el.tc = el.text_color - el.theme_text_color="Custom" - el.text_color=mdc("Red","400") + el.ttc = el.theme_text_color + el.tc = el.text_color + el.theme_text_color = "Custom" + el.text_color = mdc("Red", "400") el.icon = "stop-circle" - self.rec_dialog.rec_item.text = "[size="+str(ss)+"]Stop Recording[/size]" + self.rec_dialog.rec_item.text = "[size=" + \ + str(ss)+"]Stop Recording[/size]" + def cb(dt): self.msg_audio.start() Clock.schedule_once(cb, 0.10) else: self.sideband.ui_stopped_recording() - RNS.log("Stopping recording...") # TODO: Remove + RNS.log("Stopping recording...") # TODO: Remove self.rec_dialog.recording = False - self.rec_dialog.rec_item.text = "[size="+str(ss)+"]Start Recording[/size]" + self.rec_dialog.rec_item.text = "[size=" + \ + str(ss)+"]Start Recording[/size]" el = self.rec_dialog.rec_item.children[0].children[0] el.icon = "record" el.text_color = self.theme_cls._get_text_color() @@ -2155,13 +2310,15 @@ class SidebandApp(MDApp): RNS.log("Playing recording...", RNS.LOG_DEBUG) self.rec_dialog.playing = True self.rec_dialog.play_item.children[0].children[0].icon = "stop" - self.rec_dialog.play_item.text = "[size="+str(ss)+"]Stop[/size]" + self.rec_dialog.play_item.text = "[size=" + \ + str(ss)+"]Stop[/size]" self.msg_audio.play() else: RNS.log("Stopping playback...", RNS.LOG_DEBUG) self.rec_dialog.playing = False self.rec_dialog.play_item.children[0].children[0].icon = "play" - self.rec_dialog.play_item.text = "[size="+str(ss)+"]Play[/size]" + self.rec_dialog.play_item.text = "[size=" + \ + str(ss)+"]Play[/size]" self.msg_audio.stop() self.msg_rec_a_play = a_play @@ -2171,9 +2328,9 @@ class SidebandApp(MDApp): self.rec_dialog.playing = False self.rec_dialog.play_item.children[0].children[0].icon = "play" self.rec_dialog.play_item.text = "[size="+str(ss)+"]Play[/size]" - + self.msg_audio._finished_callback = a_finished - + def a_save(sender): if self.rec_dialog.recording: a_rec_action(sender) @@ -2187,25 +2344,30 @@ class SidebandApp(MDApp): if proc_path: self.attach_path = proc_path os.unlink(self.msg_audio._file_path) - RNS.log("Using voice-processed OPUS data in OGG container", RNS.LOG_DEBUG) + RNS.log( + "Using voice-processed OPUS data in OGG container", RNS.LOG_DEBUG) else: self.attach_path = self.msg_audio._file_path - RNS.log("Using unmodified OPUS data in OGG container", RNS.LOG_DEBUG) + RNS.log( + "Using unmodified OPUS data in OGG container", RNS.LOG_DEBUG) else: self.message_process_audio() self.update_message_widgets() toast("Added recorded audio to message") - + except Exception as e: RNS.trace_exception(e) self.msg_rec_a_save = a_save cancel_button = MDRectangleFlatButton(text="Cancel", font_size=dp(18)) - rec_item = DialogItem(IconLeftWidget(icon="record", on_release=a_rec_action), text="[size="+str(ss)+"]Start Recording[/size]", on_release=a_rec_action) - play_item = DialogItem(IconLeftWidget(icon="play", on_release=a_play), text="[size="+str(ss)+"]Play[/size]", on_release=a_play, disabled=True) - save_item = DialogItem(IconLeftWidget(icon="content-save-move-outline", on_release=a_save), text="[size="+str(ss)+"]Save to message[/size]", on_release=a_save, disabled=True) + rec_item = DialogItem(IconLeftWidget(icon="record", on_release=a_rec_action), + text="[size="+str(ss)+"]Start Recording[/size]", on_release=a_rec_action) + play_item = DialogItem(IconLeftWidget(icon="play", on_release=a_play), + text="[size="+str(ss)+"]Play[/size]", on_release=a_play, disabled=True) + save_item = DialogItem(IconLeftWidget(icon="content-save-move-outline", on_release=a_save), + text="[size="+str(ss)+"]Save to message[/size]", on_release=a_save, disabled=True) self.rec_dialog = MDDialog( title="Record Audio", type="simple", @@ -2215,7 +2377,7 @@ class SidebandApp(MDApp): play_item, save_item, ], - buttons=[ cancel_button ], + buttons=[cancel_button], width_offset=dp(32), ) cancel_button.bind(on_release=self.rec_dialog.dismiss) @@ -2234,7 +2396,8 @@ class SidebandApp(MDApp): self.rec_dialog.play_item.disabled = True self.rec_dialog.save_item.disabled = True self.rec_dialog.recording = False - self.rec_dialog.rec_item.text = "[size="+str(ss)+"]Start Recording[/size]" + self.rec_dialog.rec_item.text = "[size=" + \ + str(ss)+"]Start Recording[/size]" self.rec_dialog.rec_item.children[0].children[0].icon = "record" self.rec_dialog.open() @@ -2243,7 +2406,7 @@ class SidebandApp(MDApp): def message_attach_action(self, attach_type=None, nodialog=False): file_attach_types = ["lbimg", "defimg", "hqimg", "file"] rec_attach_types = ["audio"] - + self.attach_path = None self.rec_dialog_is_open = False if attach_type in file_attach_types: @@ -2261,19 +2424,24 @@ class SidebandApp(MDApp): def a_img_lb(sender): self.attach_dialog.dismiss() self.message_attach_action(attach_type="lbimg") + def a_img_def(sender): self.attach_dialog.dismiss() self.message_attach_action(attach_type="defimg") + def a_img_hq(sender): self.attach_dialog.dismiss() self.message_attach_action(attach_type="hqimg") + def a_file(sender): self.attach_dialog.dismiss() self.message_attach_action(attach_type="file") + def a_audio_hq(sender): self.attach_dialog.dismiss() self.audio_msg_mode = LXMF.AM_OPUS_OGG self.message_attach_action(attach_type="audio") + def a_audio_lb(sender): self.attach_dialog.dismiss() self.audio_msg_mode = LXMF.AM_CODEC2_2400 @@ -2281,15 +2449,21 @@ class SidebandApp(MDApp): if self.attach_dialog == None: ss = int(dp(18)) - cancel_button = MDRectangleFlatButton(text="Cancel", font_size=dp(18)) + cancel_button = MDRectangleFlatButton( + text="Cancel", font_size=dp(18)) ad_items = [ - DialogItem(IconLeftWidget(icon="message-image-outline", on_release=a_img_lb), text="[size="+str(ss)+"]Low-bandwidth Image[/size]", on_release=a_img_lb), - DialogItem(IconLeftWidget(icon="file-image", on_release=a_img_def), text="[size="+str(ss)+"]Medium Image[/size]", on_release=a_img_def), - DialogItem(IconLeftWidget(icon="image-outline", on_release=a_img_hq), text="[size="+str(ss)+"]High-res Image[/size]", on_release=a_img_hq), - DialogItem(IconLeftWidget(icon="account-voice", on_release=a_audio_lb), text="[size="+str(ss)+"]Low-bandwidth Voice[/size]", on_release=a_audio_lb), - DialogItem(IconLeftWidget(icon="microphone-message", on_release=a_audio_hq), text="[size="+str(ss)+"]High-quality Voice[/size]", on_release=a_audio_hq), - DialogItem(IconLeftWidget(icon="file-outline", on_release=a_file), text="[size="+str(ss)+"]File Attachment[/size]", on_release=a_file)] - + DialogItem(IconLeftWidget(icon="message-image-outline", on_release=a_img_lb), + text="[size="+str(ss)+"]Low-bandwidth Image[/size]", on_release=a_img_lb), + DialogItem(IconLeftWidget(icon="file-image", on_release=a_img_def), + text="[size="+str(ss)+"]Medium Image[/size]", on_release=a_img_def), + DialogItem(IconLeftWidget(icon="image-outline", on_release=a_img_hq), + text="[size="+str(ss)+"]High-res Image[/size]", on_release=a_img_hq), + DialogItem(IconLeftWidget(icon="account-voice", on_release=a_audio_lb), + text="[size="+str(ss)+"]Low-bandwidth Voice[/size]", on_release=a_audio_lb), + DialogItem(IconLeftWidget(icon="microphone-message", on_release=a_audio_hq), + text="[size="+str(ss)+"]High-quality Voice[/size]", on_release=a_audio_hq), + DialogItem(IconLeftWidget(icon="file-outline", on_release=a_file), text="[size="+str(ss)+"]File Attachment[/size]", on_release=a_file)] + if RNS.vendor.platformutils.is_windows(): ad_items.pop(3) ad_items.pop(3) @@ -2307,7 +2481,7 @@ class SidebandApp(MDApp): type="simple", text="Select the type of attachment you want to send with this message\n", items=ad_items, - buttons=[ cancel_button ], + buttons=[cancel_button], width_offset=dp(32), ) @@ -2323,26 +2497,25 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.get_platform() == "android": toast("Attachment removed") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Attachment Removed", text="The attached resource was removed from the message", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() - def shared_attachment_action(self, attachment_data): if not self.root.ids.screen_manager.current == "messages_screen": if RNS.vendor.platformutils.is_android(): toast("Please select a conversation first") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="No active conversation", text="To drop files as attachments, please open a conversation first", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() @@ -2350,41 +2523,49 @@ class SidebandApp(MDApp): self.rec_dialog_is_open = False def a_img_lb(sender): - self.attach_type="lbimg" + self.attach_type = "lbimg" self.shared_attach_dialog.dismiss() self.shared_attach_dialog.att_exc() + def a_img_def(sender): - self.attach_type="defimg" + self.attach_type = "defimg" self.shared_attach_dialog.dismiss() self.shared_attach_dialog.att_exc() + def a_img_hq(sender): - self.attach_type="hqimg" + self.attach_type = "hqimg" self.shared_attach_dialog.dismiss() self.shared_attach_dialog.att_exc() + def a_file(sender): - self.attach_type="file" + self.attach_type = "file" self.shared_attach_dialog.dismiss() self.shared_attach_dialog.att_exc() if self.shared_attach_dialog == None: ss = int(dp(18)) - cancel_button = MDRectangleFlatButton(text="Cancel", font_size=dp(18)) + cancel_button = MDRectangleFlatButton( + text="Cancel", font_size=dp(18)) ad_items = [ - DialogItem(IconLeftWidget(icon="message-image-outline", on_release=a_img_lb), text="[size="+str(ss)+"]Low-bandwidth Image[/size]", on_release=a_img_lb), - DialogItem(IconLeftWidget(icon="file-image", on_release=a_img_def), text="[size="+str(ss)+"]Medium Image[/size]", on_release=a_img_def), - DialogItem(IconLeftWidget(icon="image-outline", on_release=a_img_hq), text="[size="+str(ss)+"]High-res Image[/size]", on_release=a_img_hq), - DialogItem(IconLeftWidget(icon="file-outline", on_release=a_file), text="[size="+str(ss)+"]File Attachment[/size]", on_release=a_file)] - + DialogItem(IconLeftWidget(icon="message-image-outline", on_release=a_img_lb), + text="[size="+str(ss)+"]Low-bandwidth Image[/size]", on_release=a_img_lb), + DialogItem(IconLeftWidget(icon="file-image", on_release=a_img_def), + text="[size="+str(ss)+"]Medium Image[/size]", on_release=a_img_def), + DialogItem(IconLeftWidget(icon="image-outline", on_release=a_img_hq), + text="[size="+str(ss)+"]High-res Image[/size]", on_release=a_img_hq), + DialogItem(IconLeftWidget(icon="file-outline", on_release=a_file), text="[size="+str(ss)+"]File Attachment[/size]", on_release=a_file)] + self.shared_attach_dialog = MDDialog( title="Add Attachment", type="simple", text="Select how you want to attach this data to the next message sent\n", items=ad_items, - buttons=[ cancel_button ], + buttons=[cancel_button], width_offset=dp(32), ) - cancel_button.bind(on_release=self.shared_attach_dialog.dismiss) + cancel_button.bind( + on_release=self.shared_attach_dialog.dismiss) def att_exc(): self.message_fm_got_path(attachment_data["data_path"]) @@ -2417,11 +2598,12 @@ class SidebandApp(MDApp): mode_item.icon = "upload-network" self.messages_view.ids.message_text.hint_text = "Message for propagation" # self.root.ids.message_text.hint_text = "Write message for delivery via propagation nodes" - + def key_query_action(self, sender): context_dest = self.messages_view.ids.messages_scrollview.active_conversation if self.sideband.request_key(context_dest): - keys_str = "Public key information for "+RNS.prettyhexrep(context_dest)+" was requested from the network. Waiting for request to be answered." + keys_str = "Public key information for "+RNS.prettyhexrep( + context_dest)+" was requested from the network. Waiting for request to be answered." self.messages_view.ids.nokeys_text.text = keys_str else: keys_str = "Could not send request. Check your connectivity and addresses." @@ -2442,9 +2624,9 @@ class SidebandApp(MDApp): self.widget_hide(self.messages_view.ids.message_ptt, True) self.widget_hide(self.messages_view.ids.no_keys_part, False) + # Conversations screen + ###################################### - ### Conversations screen - ###################################### def conversations_action(self, sender=None, direction="left", no_transition=False): self.rec_dialog_is_open = False if self.include_objects: @@ -2483,22 +2665,25 @@ class SidebandApp(MDApp): def open_conversations(self, direction="left"): self.root.ids.screen_manager.transition.direction = direction self.root.ids.nav_drawer.set_state("closed") - + if not self.conversations_view: self.conversations_view = Conversations(self) for child in self.conversations_view.ids.conversations_scrollview.children: - self.conversations_view.ids.conversations_scrollview.remove_widget(child) + self.conversations_view.ids.conversations_scrollview.remove_widget( + child) self.conversations_view.ids.conversations_scrollview.effect_cls = ScrollEffect - self.conversations_view.ids.conversations_scrollview.add_widget(self.conversations_view.get_widget()) + self.conversations_view.ids.conversations_scrollview.add_widget( + self.conversations_view.get_widget()) self.root.ids.screen_manager.current = "conversations_screen" if self.messages_view: self.messages_view.ids.messages_scrollview.active_conversation = None def cb(dt): - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) self.sideband.setstate("wants.clear_notifications", True) Clock.schedule_once(cb, 0.10) @@ -2506,7 +2691,8 @@ class SidebandApp(MDApp): try: connectivity_status = "" if RNS.vendor.platformutils.get_platform() == "android": - connectivity_status = str(self.sideband.getstate("service.connectivity_status")) + connectivity_status = str( + self.sideband.getstate("service.connectivity_status")) else: if self.sideband.reticulum.is_connected_to_shared_instance: @@ -2516,21 +2702,24 @@ class SidebandApp(MDApp): return connectivity_status except Exception as e: - RNS.log("An error occurred while retrieving connectivity status: "+str(e), RNS.LOG_ERROR) + RNS.log( + "An error occurred while retrieving connectivity status: "+str(e), RNS.LOG_ERROR) return "Could not retrieve connectivity status" - + def connectivity_status(self, sender): if RNS.vendor.platformutils.is_android(): hs = dp(22) - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Connectivity Status", text=str(self.get_connectivity_text()), - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def cs_updater(dt): dialog.text = str(self.get_connectivity_text()) + def dl_yes(s): self.connectivity_updater.cancel() dialog.dismiss() @@ -2543,7 +2732,8 @@ class SidebandApp(MDApp): if self.connectivity_updater != None: self.connectivity_updater.cancel() - self.connectivity_updater = Clock.schedule_interval(cs_updater, 2.0) + self.connectivity_updater = Clock.schedule_interval( + cs_updater, 2.0) else: if not self.utilities_ready: @@ -2557,14 +2747,17 @@ class SidebandApp(MDApp): def open_ingest_lxm_dialog(self, sender=None): try: - cancel_button = MDRectangleFlatButton(text="Cancel",font_size=dp(18)) - ingest_button = MDRectangleFlatButton(text="Read LXM",font_size=dp(18), theme_text_color="Custom", line_color=self.color_accept, text_color=self.color_accept) - + cancel_button = MDRectangleFlatButton( + text="Cancel", font_size=dp(18)) + ingest_button = MDRectangleFlatButton(text="Read LXM", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_accept, text_color=self.color_accept) + dialog = MDDialog( title="Ingest Paper Message", text="You can read LXMF paper messages into this program by scanning a QR-code containing the message with your device camera or QR-scanner app, and then opening the resulting link in Sideband.\n\nAlternatively, you can copy an [b]lxm://[/b] link from any source to your clipboard, and ingest it using the [i]Read LXM[/i] button below.", - buttons=[ ingest_button, cancel_button ], + buttons=[ingest_button, cancel_button], ) + def dl_yes(s): try: lxm_uri = Clipboard.paste() @@ -2594,7 +2787,8 @@ class SidebandApp(MDApp): self.dialog_open = True except Exception as e: - RNS.log("Error while creating ingest LXM dialog: "+str(e), RNS.LOG_ERROR) + RNS.log("Error while creating ingest LXM dialog: " + + str(e), RNS.LOG_ERROR) def lxmf_sync_action(self, sender): def cb(dt): @@ -2603,17 +2797,18 @@ class SidebandApp(MDApp): def lxmf_sync_request(self, sender): if self.sideband.message_router.get_outbound_propagation_node() == None: - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Can't Sync", text="No active LXMF propagation nodes were found. Cannot fetch messages. Wait for a Propagation Node to announce on the network, or manually specify one in the settings.", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() - + yes_button.bind(on_release=dl_yes) dialog.open() else: @@ -2624,30 +2819,35 @@ class SidebandApp(MDApp): sync_title = "LXMF Sync" if not hasattr(self, "message_sync_dialog") or self.message_sync_dialog == None: - close_button = MDRectangleFlatButton(text="Close",font_size=dp(18)) - stop_button = MDRectangleFlatButton(text="Stop",font_size=dp(18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) + close_button = MDRectangleFlatButton( + text="Close", font_size=dp(18)) + stop_button = MDRectangleFlatButton(text="Stop", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) dialog_content = MsgSync() dialog = MDDialog( title=sync_title, type="custom", content_cls=dialog_content, - buttons=[ stop_button, close_button ], + buttons=[stop_button, close_button], # elevation=0, ) dialog.d_content = dialog_content - def dl_close(s): - self.sideband.setstate("app.flags.lxmf_sync_dialog_open", False) + + def dl_close(s): + self.sideband.setstate( + "app.flags.lxmf_sync_dialog_open", False) dialog.dismiss() self.message_sync_dialog.d_content.ids.sync_progress.value = 0.1 self.message_sync_dialog.d_content.ids.sync_status.text = "" # self.sideband.cancel_lxmf_sync() - def dl_stop(s): + def dl_stop(s): # self.sideband.setstate("app.flags.lxmf_sync_dialog_open", False) # dialog.dismiss() self.sideband.cancel_lxmf_sync() + def cb(dt): self.widget_hide(self.sync_dialog.stop_button, True) Clock.schedule_once(cb, 0.25) @@ -2658,7 +2858,7 @@ class SidebandApp(MDApp): self.message_sync_dialog = dialog self.sync_dialog = dialog_content self.sync_dialog.stop_button = stop_button - + s_state = self.sideband.message_router.propagation_transfer_state if s_state > LXMF.LXMRouter.PR_PATH_REQUESTED and s_state <= LXMF.LXMRouter.PR_COMPLETE: dsp = self.sideband.get_sync_progress()*100 @@ -2687,28 +2887,33 @@ class SidebandApp(MDApp): def new_conversation_request(self, sender=None): try: - cancel_button = MDRectangleFlatButton(text="Cancel",font_size=dp(18)) - create_button = MDRectangleFlatButton(text="Create",font_size=dp(18), theme_text_color="Custom", line_color=self.color_accept, text_color=self.color_accept) - + cancel_button = MDRectangleFlatButton( + text="Cancel", font_size=dp(18)) + create_button = MDRectangleFlatButton(text="Create", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_accept, text_color=self.color_accept) + dialog_content = NewConv() dialog = MDDialog( title="New Conversation", type="custom", content_cls=dialog_content, - buttons=[ create_button, cancel_button ], + buttons=[create_button, cancel_button], # elevation=0, ) dialog.d_content = dialog_content + def dl_yes(s): new_result = False try: n_address = dialog.d_content.ids["n_address_field"].text n_name = dialog.d_content.ids["n_name_field"].text n_trusted = dialog.d_content.ids["n_trusted"].active - new_result = self.sideband.new_conversation(n_address, n_name, n_trusted) + new_result = self.sideband.new_conversation( + n_address, n_name, n_trusted) except Exception as e: - RNS.log("Error while creating conversation: "+str(e), RNS.LOG_ERROR) + RNS.log("Error while creating conversation: " + + str(e), RNS.LOG_ERROR) if new_result: dialog.d_content.ids["n_address_field"].helper_text = "" @@ -2737,17 +2942,20 @@ class SidebandApp(MDApp): self.dialog_open = True except Exception as e: - RNS.log("Error while creating new conversation dialog: "+str(e), RNS.LOG_ERROR) + RNS.log("Error while creating new conversation dialog: " + + str(e), RNS.LOG_ERROR) - ### Information/version screen + # Information/version screen ###################################### def information_action(self, sender=None, direction="left"): if self.root.ids.screen_manager.has_screen("information_screen"): self.information_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.information_init() + def o(dt): self.information_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -2755,7 +2963,8 @@ class SidebandApp(MDApp): def information_init(self): if not self.root.ids.screen_manager.has_screen("information_screen"): - self.information_screen = Builder.load_string(layout_information_screen) + self.information_screen = Builder.load_string( + layout_information_screen) self.information_screen.app = self self.root.ids.screen_manager.add_widget(self.information_screen) @@ -2767,14 +2976,17 @@ class SidebandApp(MDApp): self.information_screen.ids.information_scrollview.effect_cls = ScrollEffect self.information_screen.ids.information_logo.icon = self.sideband.asset_dir+"/rns_256.png" - str_comps = " - [b]Reticulum[/b] (MIT License)\n - [b]LXMF[/b] (MIT License)\n - [b]KivyMD[/b] (MIT License)" + str_comps = " - [b]Reticulum[/b] (MIT License)\n - [b]LXMF[/b] (MIT License)\n - [b]KivyMD[/b] (MIT License)" str_comps += "\n - [b]Kivy[/b] (MIT License)\n - [b]Codec2[/b] (LGPL License)\n - [b]PyCodec2[/b] (BSD-3 License)" str_comps += "\n - [b]PyDub[/b] (MIT License)\n - [b]PyOgg[/b] (Public Domain)" str_comps += "\n - [b]GeoidHeight[/b] (LGPL License)\n - [b]Python[/b] (PSF License)" - str_comps += "\n\nGo to [u][ref=link]https://unsigned.io/donate[/ref][/u] to support the project.\n\nThe Sideband app is Copyright (c) 2024 Mark Qvist / unsigned.io\n\nPermission is granted to freely share and distribute binary copies of "+self.root.ids.app_version_info.text+", so long as no payment or compensation is charged for said distribution or sharing.\n\nIf you were charged or paid anything for this copy of Sideband, please report it to [b]license@unsigned.io[/b].\n\nTHIS IS EXPERIMENTAL SOFTWARE - SIDEBAND COMES WITH ABSOLUTELY NO WARRANTY - USE AT YOUR OWN RISK AND RESPONSIBILITY" - info = "This is "+self.root.ids.app_version_info.text+", on RNS v"+RNS.__version__+" and LXMF v"+LXMF.__version__+".\n\nHumbly build using the following open components:\n\n"+str_comps + str_comps += "\n\nGo to [u][ref=link]https://unsigned.io/donate[/ref][/u] to support the project.\n\nThe Sideband app is Copyright (c) 2024 Mark Qvist / unsigned.io\n\nPermission is granted to freely share and distribute binary copies of "+self.root.ids.app_version_info.text + \ + ", so long as no payment or compensation is charged for said distribution or sharing.\n\nIf you were charged or paid anything for this copy of Sideband, please report it to [b]license@unsigned.io[/b].\n\nTHIS IS EXPERIMENTAL SOFTWARE - SIDEBAND COMES WITH ABSOLUTELY NO WARRANTY - USE AT YOUR OWN RISK AND RESPONSIBILITY" + info = "This is "+self.root.ids.app_version_info.text+", on RNS v"+RNS.__version__+" and LXMF v" + \ + LXMF.__version__+".\n\nHumbly build using the following open components:\n\n"+str_comps self.information_screen.ids.information_info.text = info - self.information_screen.ids.information_info.bind(on_ref_press=link_exec) + self.information_screen.ids.information_info.bind( + on_ref_press=link_exec) def information_open(self, sender=None, direction="left", no_transition=False): if no_transition: @@ -2786,7 +2998,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = "left" self.root.ids.screen_manager.current = "information_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -2794,9 +3007,9 @@ class SidebandApp(MDApp): def close_information_action(self, sender=None): self.open_conversations(direction="right") - - ### Settings screen + # Settings screen ###################################### + def settings_open(self, sender=None, direction="left", no_transition=False): if no_transition: self.root.ids.screen_manager.transition = self.no_transition @@ -2806,9 +3019,11 @@ class SidebandApp(MDApp): self.root.ids.nav_drawer.set_state("closed") if self.sideband.active_propagation_node != None: - self.settings_screen.ids.settings_propagation_node_address.text = RNS.hexrep(self.sideband.active_propagation_node, delimit=False) + self.settings_screen.ids.settings_propagation_node_address.text = RNS.hexrep( + self.sideband.active_propagation_node, delimit=False) self.root.ids.screen_manager.current = "settings_screen" - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -2816,19 +3031,23 @@ class SidebandApp(MDApp): def configure_ui_scaling_action(self, sender=None): global app_ui_scaling_path try: - cancel_button = MDRectangleFlatButton(text="Cancel",font_size=dp(18)) - set_button = MDRectangleFlatButton(text="Set",font_size=dp(18), theme_text_color="Custom", line_color=self.color_accept, text_color=self.color_accept) - + cancel_button = MDRectangleFlatButton( + text="Cancel", font_size=dp(18)) + set_button = MDRectangleFlatButton(text="Set", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_accept, text_color=self.color_accept) + dialog_content = UIScaling() dialog = MDDialog( title="UI Scaling", type="custom", content_cls=dialog_content, - buttons=[ set_button, cancel_button ], + buttons=[set_button, cancel_button], # elevation=0, ) dialog.d_content = dialog_content - dialog.d_content.ids["scaling_factor"].text = os.environ["KIVY_METRICS_DENSITY"] if "KIVY_METRICS_DENSITY" in os.environ else "0.0" + dialog.d_content.ids["scaling_factor"].text = os.environ[ + "KIVY_METRICS_DENSITY"] if "KIVY_METRICS_DENSITY" in os.environ else "0.0" + def dl_yes(s): new_sf = 1.0 scaling_ok = False @@ -2840,7 +3059,8 @@ class SidebandApp(MDApp): scaling_ok = True except Exception as e: - RNS.log("Error while getting scaling factor from user: "+str(e), RNS.LOG_ERROR) + RNS.log( + "Error while getting scaling factor from user: "+str(e), RNS.LOG_ERROR) if scaling_ok: dialog.d_content.ids["scaling_factor"].helper_text = "" @@ -2848,14 +3068,17 @@ class SidebandApp(MDApp): dialog.d_content.ids["scaling_factor"].error = False dialog.dismiss() if app_ui_scaling_path == None: - RNS.log("No path to UI scaling factor file could be found, cannot save scaling factor", RNS.LOG_ERROR) + RNS.log( + "No path to UI scaling factor file could be found, cannot save scaling factor", RNS.LOG_ERROR) else: try: with open(app_ui_scaling_path, "w") as sfile: sfile.write(str(new_sf)) - RNS.log(f"Saved configured scaling factor {new_sf} to {app_ui_scaling_path}", RNS.LOG_DEBUG) + RNS.log( + f"Saved configured scaling factor {new_sf} to {app_ui_scaling_path}", RNS.LOG_DEBUG) except Exception as e: - RNS.log(f"Error while saving scaling factor {new_sf} to {app_ui_scaling_path}: {e}", RNS.LOG_ERROR) + RNS.log( + f"Error while saving scaling factor {new_sf} to {app_ui_scaling_path}: {e}", RNS.LOG_ERROR) else: dialog.d_content.ids["scaling_factor"].helper_text = "Invalid scale factor, check your input" @@ -2876,16 +3099,18 @@ class SidebandApp(MDApp): self.dialog_open = True except Exception as e: - RNS.log("Error while creating UI scaling dialog: "+str(e), RNS.LOG_ERROR) - + RNS.log("Error while creating UI scaling dialog: " + + str(e), RNS.LOG_ERROR) def settings_action(self, sender=None, direction="left"): if self.settings_ready: self.settings_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.settings_init() + def o(dt): self.settings_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -2893,8 +3118,11 @@ class SidebandApp(MDApp): def interval_to_slider_val(self, interval): try: - mseg = 72; hseg = 84; sv = 0 - mm = mseg*5*60; hm = hseg*60*30+mm + mseg = 72 + hseg = 84 + sv = 0 + mm = mseg*5*60 + hm = hseg*60*30+mm if interval <= mm: sv = interval/60/5 @@ -2921,7 +3149,8 @@ class SidebandApp(MDApp): def settings_init(self, sender=None): if not self.settings_ready: if not self.root.ids.screen_manager.has_screen("settings_screen"): - self.settings_screen = Builder.load_string(layout_settings_screen) + self.settings_screen = Builder.load_string( + layout_settings_screen) self.settings_screen.app = self self.root.ids.screen_manager.add_widget(self.settings_screen) self.bind_clipboard_actions(self.settings_screen.ids) @@ -2930,7 +3159,7 @@ class SidebandApp(MDApp): self.settings_screen.ids.settings_info_lang.text = "\nIf you write messages in another script than Latin, Greek or Cyrillic, you can configure the text input language for messages and other fields below.\n" - info1_text = "\nYou can set your [b]Display Name[/b] to a custom value, or leave it as the default unspecified value. " + info1_text = "\nYou can set your [b]Display Name[/b] to a custom value, or leave it as the default unspecified value. " info1_text += "This name will be included in any announces you send, and will be visible to others on the network. " info1_text += "\n\nYou can manually specify which [b]Propagation Node[/b] to use, but if none is specified, Sideband will " info1_text += "automatically select one nearby." @@ -2939,7 +3168,6 @@ class SidebandApp(MDApp): self.settings_screen.ids.settings_info1.text = info1_text - def save_disp_name(sender=None, event=None): if not sender.focus: in_name = self.settings_screen.ids.settings_display_name.text @@ -2973,30 +3201,30 @@ class SidebandApp(MDApp): else: self.settings_screen.ids.settings_propagation_node_address.error = False - self.sideband.config["lxmf_propagation_node"] = new_addr - self.sideband.set_active_propagation_node(self.sideband.config["lxmf_propagation_node"]) + self.sideband.set_active_propagation_node( + self.sideband.config["lxmf_propagation_node"]) def save_input_lang(sender=None, event=None): if sender.active: if sender != self.settings_screen.ids.settings_lang_default: self.settings_screen.ids.settings_lang_default.active = False - + if sender != self.settings_screen.ids.settings_lang_chinese: self.settings_screen.ids.settings_lang_chinese.active = False - + if sender != self.settings_screen.ids.settings_lang_japanese: self.settings_screen.ids.settings_lang_japanese.active = False - + if sender != self.settings_screen.ids.settings_lang_korean: self.settings_screen.ids.settings_lang_korean.active = False - + if sender != self.settings_screen.ids.settings_lang_devangari: self.settings_screen.ids.settings_lang_devangari.active = False - + if sender != self.settings_screen.ids.settings_lang_hebrew: self.settings_screen.ids.settings_lang_hebrew.active = False - + if self.settings_screen.ids.settings_lang_default.active: self.sideband.config["input_language"] = None self.settings_screen.ids.settings_display_name.font_name = "defaultinput" @@ -3019,7 +3247,6 @@ class SidebandApp(MDApp): self.sideband.config["input_language"] = None self.settings_screen.ids.settings_display_name.font_name = "defaultinput" - self.sideband.save_configuration() self.update_input_language() @@ -3092,7 +3319,8 @@ class SidebandApp(MDApp): def save_debug(sender=None, event=None): self.sideband.config["debug"] = self.settings_screen.ids.settings_debug.active self.sideband.save_configuration() - self.sideband._reticulum_log_debug(self.sideband.config["debug"]) + self.sideband._reticulum_log_debug( + self.sideband.config["debug"]) def save_block_predictive_text(sender=None, event=None): self.sideband.config["block_predictive_text"] = self.settings_screen.ids.settings_block_predictive_text.active @@ -3111,14 +3339,17 @@ class SidebandApp(MDApp): new_cmd = in_cmd self.sideband.config["print_command"] = new_cmd.strip() - self.settings_screen.ids.settings_print_command.text = self.sideband.config["print_command"] + self.settings_screen.ids.settings_print_command.text = self.sideband.config[ + "print_command"] self.sideband.save_configuration() def save_lxmf_stamp_cost(sender=None, event=None, save=True): if self.settings_screen.ids.settings_lxmf_require_stamps.active: - self.widget_hide(self.settings_screen.ids.lxmf_costslider_container, False) + self.widget_hide( + self.settings_screen.ids.lxmf_costslider_container, False) else: - self.widget_hide(self.settings_screen.ids.lxmf_costslider_container, True) + self.widget_hide( + self.settings_screen.ids.lxmf_costslider_container, True) if save: self.sideband.config["lxmf_require_stamps"] = self.settings_screen.ids.settings_lxmf_require_stamps.active @@ -3126,25 +3357,31 @@ class SidebandApp(MDApp): def save_lxmf_periodic_sync(sender=None, event=None, save=True): if self.settings_screen.ids.settings_lxmf_periodic_sync.active: - self.widget_hide(self.settings_screen.ids.lxmf_syncslider_container, False) + self.widget_hide( + self.settings_screen.ids.lxmf_syncslider_container, False) else: - self.widget_hide(self.settings_screen.ids.lxmf_syncslider_container, True) + self.widget_hide( + self.settings_screen.ids.lxmf_syncslider_container, True) if save: self.sideband.config["lxmf_periodic_sync"] = self.settings_screen.ids.settings_lxmf_periodic_sync.active self.sideband.save_configuration() def sync_interval_change(sender=None, event=None, save=True): - slider_val = int(self.settings_screen.ids.settings_lxmf_sync_interval.value) - mseg = 72; hseg = 84 + slider_val = int( + self.settings_screen.ids.settings_lxmf_sync_interval.value) + mseg = 72 + hseg = 84 if slider_val <= mseg: interval = slider_val*5*60 elif slider_val > mseg and slider_val <= mseg+hseg: - h = (slider_val-mseg)/2; mm = mseg*5*60 + h = (slider_val-mseg)/2 + mm = mseg*5*60 interval = h*60*60+mm else: d = slider_val-hseg-mseg - hm = (hseg/2)*60*60; mm = mseg*5*60 + hm = (hseg/2)*60*60 + mm = mseg*5*60 interval = d*86400+hm+mm interval_text = RNS.prettytime(interval) @@ -3156,7 +3393,8 @@ class SidebandApp(MDApp): self.sideband.save_configuration() def stamp_cost_change(sender=None, event=None, save=True): - slider_val = int(self.settings_screen.ids.settings_lxmf_require_stamps_cost.value) + slider_val = int( + self.settings_screen.ids.settings_lxmf_require_stamps_cost.value) cost_text = str(slider_val) self.settings_screen.ids.settings_lxmf_require_stamps_label.text = f"Require stamp cost {cost_text} for incoming messages" @@ -3169,30 +3407,40 @@ class SidebandApp(MDApp): if (event == None or not hasattr(event, "button") or not event.button) or not "scroll" in event.button: self.sideband.save_configuration() - self.settings_screen.ids.settings_lxmf_address.text = RNS.hexrep(self.sideband.lxmf_destination.hash, delimit=False) - self.settings_screen.ids.settings_identity_hash.text = RNS.hexrep(self.sideband.lxmf_destination.identity.hash, delimit=False) + self.settings_screen.ids.settings_lxmf_address.text = RNS.hexrep( + self.sideband.lxmf_destination.hash, delimit=False) + self.settings_screen.ids.settings_identity_hash.text = RNS.hexrep( + self.sideband.lxmf_destination.identity.hash, delimit=False) - self.settings_screen.ids.settings_display_name.text = self.sideband.config["display_name"] - self.settings_screen.ids.settings_display_name.bind(focus=save_disp_name) + self.settings_screen.ids.settings_display_name.text = self.sideband.config[ + "display_name"] + self.settings_screen.ids.settings_display_name.bind( + focus=save_disp_name) if RNS.vendor.platformutils.is_android(): pass # self.widget_hide(self.settings_screen.ids.settings_print_command, True) else: - self.settings_screen.ids.settings_print_command.text = self.sideband.config["print_command"] - self.settings_screen.ids.settings_print_command.bind(focus=save_print_command) + self.settings_screen.ids.settings_print_command.text = self.sideband.config[ + "print_command"] + self.settings_screen.ids.settings_print_command.bind( + focus=save_print_command) if self.sideband.config["lxmf_propagation_node"] == None: prop_node_addr = "" else: - prop_node_addr = RNS.hexrep(self.sideband.config["lxmf_propagation_node"], delimit=False) + prop_node_addr = RNS.hexrep( + self.sideband.config["lxmf_propagation_node"], delimit=False) self.settings_screen.ids.settings_propagation_node_address.text = prop_node_addr - self.settings_screen.ids.settings_propagation_node_address.bind(focus=save_prop_addr) + self.settings_screen.ids.settings_propagation_node_address.bind( + focus=save_prop_addr) if not RNS.vendor.platformutils.is_android() or android_api_version >= 26: - self.settings_screen.ids.settings_notifications_on.active = self.sideband.config["notifications_on"] - self.settings_screen.ids.settings_notifications_on.bind(active=save_notifications_on) + self.settings_screen.ids.settings_notifications_on.active = self.sideband.config[ + "notifications_on"] + self.settings_screen.ids.settings_notifications_on.bind( + active=save_notifications_on) else: self.settings_screen.ids.settings_notifications_on.active = False self.settings_screen.ids.settings_notifications_on.disabled = True @@ -3200,58 +3448,89 @@ class SidebandApp(MDApp): self.settings_screen.ids.settings_dark_ui.active = self.sideband.config["dark_ui"] self.settings_screen.ids.settings_dark_ui.bind(active=save_dark_ui) - self.settings_screen.ids.settings_eink_mode.active = self.sideband.config["eink_mode"] - self.settings_screen.ids.settings_eink_mode.bind(active=save_eink_mode) + self.settings_screen.ids.settings_eink_mode.active = self.sideband.config[ + "eink_mode"] + self.settings_screen.ids.settings_eink_mode.bind( + active=save_eink_mode) - self.settings_screen.ids.settings_classic_message_colors.active = self.sideband.config["classic_message_colors"] - self.settings_screen.ids.settings_classic_message_colors.bind(active=save_classic_message_colors) + self.settings_screen.ids.settings_classic_message_colors.active = self.sideband.config[ + "classic_message_colors"] + self.settings_screen.ids.settings_classic_message_colors.bind( + active=save_classic_message_colors) - self.settings_screen.ids.display_style_in_contact_list.active = self.sideband.config["display_style_in_contact_list"] - self.settings_screen.ids.display_style_in_contact_list.bind(active=save_display_style_in_contact_list) + self.settings_screen.ids.display_style_in_contact_list.active = self.sideband.config[ + "display_style_in_contact_list"] + self.settings_screen.ids.display_style_in_contact_list.bind( + active=save_display_style_in_contact_list) - self.settings_screen.ids.display_style_from_trusted_only.active = not self.sideband.config["display_style_from_all"] - self.settings_screen.ids.display_style_from_trusted_only.bind(active=save_display_style_from_trusted_only) + self.settings_screen.ids.display_style_from_trusted_only.active = not self.sideband.config[ + "display_style_from_all"] + self.settings_screen.ids.display_style_from_trusted_only.bind( + active=save_display_style_from_trusted_only) - self.settings_screen.ids.settings_advanced_statistics.active = self.sideband.config["advanced_stats"] - self.settings_screen.ids.settings_advanced_statistics.bind(active=save_advanced_stats) + self.settings_screen.ids.settings_advanced_statistics.active = self.sideband.config[ + "advanced_stats"] + self.settings_screen.ids.settings_advanced_statistics.bind( + active=save_advanced_stats) - self.settings_screen.ids.settings_start_announce.active = self.sideband.config["start_announce"] - self.settings_screen.ids.settings_start_announce.bind(active=save_start_announce) + self.settings_screen.ids.settings_start_announce.active = self.sideband.config[ + "start_announce"] + self.settings_screen.ids.settings_start_announce.bind( + active=save_start_announce) - self.settings_screen.ids.settings_lxmf_delivery_by_default.active = self.sideband.config["propagation_by_default"] - self.settings_screen.ids.settings_lxmf_delivery_by_default.bind(active=save_lxmf_delivery_by_default) + self.settings_screen.ids.settings_lxmf_delivery_by_default.active = self.sideband.config[ + "propagation_by_default"] + self.settings_screen.ids.settings_lxmf_delivery_by_default.bind( + active=save_lxmf_delivery_by_default) - self.settings_screen.ids.settings_lxmf_try_propagation_on_fail.active = self.sideband.config["lxmf_try_propagation_on_fail"] - self.settings_screen.ids.settings_lxmf_try_propagation_on_fail.bind(active=save_lxmf_try_propagation_on_fail) + self.settings_screen.ids.settings_lxmf_try_propagation_on_fail.active = self.sideband.config[ + "lxmf_try_propagation_on_fail"] + self.settings_screen.ids.settings_lxmf_try_propagation_on_fail.bind( + active=save_lxmf_try_propagation_on_fail) - self.settings_screen.ids.settings_lxmf_ignore_unknown.active = self.sideband.config["lxmf_ignore_unknown"] - self.settings_screen.ids.settings_lxmf_ignore_unknown.bind(active=save_lxmf_ignore_unknown) + self.settings_screen.ids.settings_lxmf_ignore_unknown.active = self.sideband.config[ + "lxmf_ignore_unknown"] + self.settings_screen.ids.settings_lxmf_ignore_unknown.bind( + active=save_lxmf_ignore_unknown) - self.settings_screen.ids.settings_trusted_markup_only.active = self.sideband.config["trusted_markup_only"] - self.settings_screen.ids.settings_trusted_markup_only.bind(active=save_trusted_markup_only) + self.settings_screen.ids.settings_trusted_markup_only.active = self.sideband.config[ + "trusted_markup_only"] + self.settings_screen.ids.settings_trusted_markup_only.bind( + active=save_trusted_markup_only) - self.settings_screen.ids.settings_ignore_invalid_stamps.active = self.sideband.config["lxmf_ignore_invalid_stamps"] - self.settings_screen.ids.settings_ignore_invalid_stamps.bind(active=save_lxmf_ignore_invalid_stamps) + self.settings_screen.ids.settings_ignore_invalid_stamps.active = self.sideband.config[ + "lxmf_ignore_invalid_stamps"] + self.settings_screen.ids.settings_ignore_invalid_stamps.bind( + active=save_lxmf_ignore_invalid_stamps) - self.settings_screen.ids.settings_lxmf_periodic_sync.active = self.sideband.config["lxmf_periodic_sync"] - self.settings_screen.ids.settings_lxmf_periodic_sync.bind(active=save_lxmf_periodic_sync) + self.settings_screen.ids.settings_lxmf_periodic_sync.active = self.sideband.config[ + "lxmf_periodic_sync"] + self.settings_screen.ids.settings_lxmf_periodic_sync.bind( + active=save_lxmf_periodic_sync) save_lxmf_periodic_sync(save=False) def sync_interval_change_cb(sender=None, event=None): sync_interval_change(sender=sender, event=event, save=False) - self.settings_screen.ids.settings_lxmf_sync_interval.bind(value=sync_interval_change_cb) - self.settings_screen.ids.settings_lxmf_sync_interval.bind(on_touch_up=sync_interval_change) - self.settings_screen.ids.settings_lxmf_sync_interval.value = self.interval_to_slider_val(self.sideband.config["lxmf_sync_interval"]) + self.settings_screen.ids.settings_lxmf_sync_interval.bind( + value=sync_interval_change_cb) + self.settings_screen.ids.settings_lxmf_sync_interval.bind( + on_touch_up=sync_interval_change) + self.settings_screen.ids.settings_lxmf_sync_interval.value = self.interval_to_slider_val( + self.sideband.config["lxmf_sync_interval"]) sync_interval_change(save=False) - self.settings_screen.ids.settings_lxmf_require_stamps.active = self.sideband.config["lxmf_require_stamps"] - self.settings_screen.ids.settings_lxmf_require_stamps.bind(active=save_lxmf_stamp_cost) + self.settings_screen.ids.settings_lxmf_require_stamps.active = self.sideband.config[ + "lxmf_require_stamps"] + self.settings_screen.ids.settings_lxmf_require_stamps.bind( + active=save_lxmf_stamp_cost) save_lxmf_stamp_cost(save=False) def stamp_cost_change_cb(sender=None, event=None): stamp_cost_change(sender=sender, event=event, save=False) - self.settings_screen.ids.settings_lxmf_require_stamps_cost.bind(value=stamp_cost_change_cb) - self.settings_screen.ids.settings_lxmf_require_stamps_cost.bind(on_touch_up=stamp_cost_change) + self.settings_screen.ids.settings_lxmf_require_stamps_cost.bind( + value=stamp_cost_change_cb) + self.settings_screen.ids.settings_lxmf_require_stamps_cost.bind( + on_touch_up=stamp_cost_change) cost_val = self.sideband.config["lxmf_inbound_stamp_cost"] if cost_val == None or cost_val < 1: cost_val = 1 @@ -3266,10 +3545,13 @@ class SidebandApp(MDApp): sync_limit = True self.settings_screen.ids.settings_lxmf_sync_limit.active = sync_limit - self.settings_screen.ids.settings_lxmf_sync_limit.bind(active=save_lxmf_sync_limit) + self.settings_screen.ids.settings_lxmf_sync_limit.bind( + active=save_lxmf_sync_limit) - self.settings_screen.ids.settings_lxm_limit_1mb.active = self.sideband.config["lxm_limit_1mb"] - self.settings_screen.ids.settings_lxm_limit_1mb.bind(active=save_lxm_limit_1mb) + self.settings_screen.ids.settings_lxm_limit_1mb.active = self.sideband.config[ + "lxm_limit_1mb"] + self.settings_screen.ids.settings_lxm_limit_1mb.bind( + active=save_lxm_limit_1mb) self.settings_screen.ids.settings_hq_ptt.active = self.sideband.config["hq_ptt"] self.settings_screen.ids.settings_hq_ptt.bind(active=save_hq_ptt) @@ -3277,20 +3559,28 @@ class SidebandApp(MDApp): self.settings_screen.ids.settings_debug.active = self.sideband.config["debug"] self.settings_screen.ids.settings_debug.bind(active=save_debug) - self.settings_screen.ids.settings_block_predictive_text.active = self.sideband.config["block_predictive_text"] - self.settings_screen.ids.settings_block_predictive_text.bind(active=save_block_predictive_text) + self.settings_screen.ids.settings_block_predictive_text.active = self.sideband.config[ + "block_predictive_text"] + self.settings_screen.ids.settings_block_predictive_text.bind( + active=save_block_predictive_text) self.settings_screen.ids.settings_lang_default.active = False self.settings_screen.ids.settings_lang_chinese.active = False self.settings_screen.ids.settings_lang_japanese.active = False self.settings_screen.ids.settings_lang_korean.active = False self.settings_screen.ids.settings_lang_devangari.active = False - self.settings_screen.ids.settings_lang_default.bind(active=save_input_lang) - self.settings_screen.ids.settings_lang_chinese.bind(active=save_input_lang) - self.settings_screen.ids.settings_lang_japanese.bind(active=save_input_lang) - self.settings_screen.ids.settings_lang_korean.bind(active=save_input_lang) - self.settings_screen.ids.settings_lang_devangari.bind(active=save_input_lang) - self.settings_screen.ids.settings_lang_hebrew.bind(active=save_input_lang) + self.settings_screen.ids.settings_lang_default.bind( + active=save_input_lang) + self.settings_screen.ids.settings_lang_chinese.bind( + active=save_input_lang) + self.settings_screen.ids.settings_lang_japanese.bind( + active=save_input_lang) + self.settings_screen.ids.settings_lang_korean.bind( + active=save_input_lang) + self.settings_screen.ids.settings_lang_devangari.bind( + active=save_input_lang) + self.settings_screen.ids.settings_lang_hebrew.bind( + active=save_input_lang) input_lang = self.sideband.config["input_language"] if input_lang == None: self.settings_screen.ids.settings_lang_default.active = True @@ -3318,9 +3608,9 @@ class SidebandApp(MDApp): def close_settings_action(self, sender=None): self.open_conversations(direction="right") - - ### Connectivity screen + # Connectivity screen ###################################### + def connectivity_open(self, sender=None, direction="left", no_transition=False): if no_transition: self.root.ids.screen_manager.transition = self.no_transition @@ -3332,7 +3622,8 @@ class SidebandApp(MDApp): self.root.ids.nav_drawer.set_state("closed") self.connectivity_init() self.root.ids.screen_manager.current = "connectivity_screen" - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -3342,8 +3633,10 @@ class SidebandApp(MDApp): self.connectivity_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.connectivity_init() + def o(dt): self.connectivity_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -3352,81 +3645,119 @@ class SidebandApp(MDApp): def connectivity_init(self, sender=None): if not self.connectivity_ready: if not self.root.ids.screen_manager.has_screen("connectivity_screen"): - self.connectivity_screen = Builder.load_string(layout_connectivity_screen) + self.connectivity_screen = Builder.load_string( + layout_connectivity_screen) self.connectivity_screen.app = self - self.root.ids.screen_manager.add_widget(self.connectivity_screen) + self.root.ids.screen_manager.add_widget( + self.connectivity_screen) self.bind_clipboard_actions(self.connectivity_screen.ids) self.connectivity_screen.ids.connectivity_scrollview.effect_cls = ScrollEffect + def con_hide_settings(): - self.widget_hide(self.connectivity_screen.ids.connectivity_use_local) - self.widget_hide(self.connectivity_screen.ids.connectivity_local_groupid) - self.widget_hide(self.connectivity_screen.ids.connectivity_local_ifac_netname) - self.widget_hide(self.connectivity_screen.ids.connectivity_local_ifac_passphrase) - self.widget_hide(self.connectivity_screen.ids.connectivity_use_tcp) - self.widget_hide(self.connectivity_screen.ids.connectivity_tcp_host) - self.widget_hide(self.connectivity_screen.ids.connectivity_tcp_port) - self.widget_hide(self.connectivity_screen.ids.connectivity_tcp_ifac_netname) - self.widget_hide(self.connectivity_screen.ids.connectivity_tcp_ifac_passphrase) - self.widget_hide(self.connectivity_screen.ids.connectivity_use_i2p) - self.widget_hide(self.connectivity_screen.ids.connectivity_i2p_b32) - self.widget_hide(self.connectivity_screen.ids.connectivity_i2p_ifac_netname) - self.widget_hide(self.connectivity_screen.ids.connectivity_i2p_ifac_passphrase) - self.widget_hide(self.connectivity_screen.ids.connectivity_tcp_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_local_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_i2p_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_rnode_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_rnode_ifac_netname) - self.widget_hide(self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase) - self.widget_hide(self.connectivity_screen.ids.connectivity_use_rnode) - self.widget_hide(self.connectivity_screen.ids.connectivity_modem_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_use_modem) - self.widget_hide(self.connectivity_screen.ids.connectivity_modem_fields) - self.widget_hide(self.connectivity_screen.ids.connectivity_transport_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_enable_transport) - self.widget_hide(self.connectivity_screen.ids.connectivity_serial_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_use_serial) - self.widget_hide(self.connectivity_screen.ids.connectivity_serial_fields) - self.widget_hide(self.connectivity_screen.ids.connectivity_shared_access) - self.widget_hide(self.connectivity_screen.ids.connectivity_shared_access_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_shared_access_fields) - self.widget_hide(self.connectivity_screen.ids.connectivity_transport_label) - self.widget_hide(self.connectivity_screen.ids.connectivity_enable_transport) - self.widget_hide(self.connectivity_screen.ids.connectivity_transport_info) - self.widget_hide(self.connectivity_screen.ids.connectivity_transport_fields) + self.widget_hide( + self.connectivity_screen.ids.connectivity_use_local) + self.widget_hide( + self.connectivity_screen.ids.connectivity_local_groupid) + self.widget_hide( + self.connectivity_screen.ids.connectivity_local_ifac_netname) + self.widget_hide( + self.connectivity_screen.ids.connectivity_local_ifac_passphrase) + self.widget_hide( + self.connectivity_screen.ids.connectivity_use_tcp) + self.widget_hide( + self.connectivity_screen.ids.connectivity_tcp_host) + self.widget_hide( + self.connectivity_screen.ids.connectivity_tcp_port) + self.widget_hide( + self.connectivity_screen.ids.connectivity_tcp_ifac_netname) + self.widget_hide( + self.connectivity_screen.ids.connectivity_tcp_ifac_passphrase) + self.widget_hide( + self.connectivity_screen.ids.connectivity_use_i2p) + self.widget_hide( + self.connectivity_screen.ids.connectivity_i2p_b32) + self.widget_hide( + self.connectivity_screen.ids.connectivity_i2p_ifac_netname) + self.widget_hide( + self.connectivity_screen.ids.connectivity_i2p_ifac_passphrase) + self.widget_hide( + self.connectivity_screen.ids.connectivity_tcp_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_local_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_i2p_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_rnode_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_rnode_ifac_netname) + self.widget_hide( + self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase) + self.widget_hide( + self.connectivity_screen.ids.connectivity_use_rnode) + self.widget_hide( + self.connectivity_screen.ids.connectivity_modem_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_use_modem) + self.widget_hide( + self.connectivity_screen.ids.connectivity_modem_fields) + self.widget_hide( + self.connectivity_screen.ids.connectivity_transport_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_enable_transport) + self.widget_hide( + self.connectivity_screen.ids.connectivity_serial_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_use_serial) + self.widget_hide( + self.connectivity_screen.ids.connectivity_serial_fields) + self.widget_hide( + self.connectivity_screen.ids.connectivity_shared_access) + self.widget_hide( + self.connectivity_screen.ids.connectivity_shared_access_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_shared_access_fields) + self.widget_hide( + self.connectivity_screen.ids.connectivity_transport_label) + self.widget_hide( + self.connectivity_screen.ids.connectivity_enable_transport) + self.widget_hide( + self.connectivity_screen.ids.connectivity_transport_info) + self.widget_hide( + self.connectivity_screen.ids.connectivity_transport_fields) def con_collapse_local(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_local_fields, collapse) pass - + def con_collapse_tcp(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_tcp_fields, collapse) pass - + def con_collapse_i2p(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_i2p_fields, collapse) pass - + def con_collapse_bluetooth(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_bluetooth_fields, collapse) pass - + def con_collapse_rnode(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_rnode_fields, collapse) pass - + def con_collapse_modem(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_modem_fields, collapse) pass - + def con_collapse_serial(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_serial_fields, collapse) pass - + def con_collapse_transport(collapse=True): # self.widget_hide(self.connectivity_screen.ids.connectivity_transport_fields, collapse) pass - + def save_connectivity(sender=None, event=None): self.sideband.config["connect_transport"] = self.connectivity_screen.ids.connectivity_enable_transport.active self.sideband.config["connect_local"] = self.connectivity_screen.ids.connectivity_use_local.active @@ -3454,33 +3785,48 @@ class SidebandApp(MDApp): self.sideband.config["connect_modem_ifac_netname"] = self.connectivity_screen.ids.connectivity_modem_ifac_netname.text self.sideband.config["connect_modem_ifac_passphrase"] = self.connectivity_screen.ids.connectivity_modem_ifac_passphrase.text - self.sideband.config["connect_ifmode_local"] = self.connectivity_screen.ids.connectivity_local_ifmode.text.lower() - self.sideband.config["connect_ifmode_tcp"] = self.connectivity_screen.ids.connectivity_tcp_ifmode.text.lower() - self.sideband.config["connect_ifmode_i2p"] = self.connectivity_screen.ids.connectivity_i2p_ifmode.text.lower() - self.sideband.config["connect_ifmode_rnode"] = self.connectivity_screen.ids.connectivity_rnode_ifmode.text.lower() - self.sideband.config["connect_ifmode_modem"] = self.connectivity_screen.ids.connectivity_modem_ifmode.text.lower() - self.sideband.config["connect_ifmode_serial"] = self.connectivity_screen.ids.connectivity_serial_ifmode.text.lower() + self.sideband.config["connect_ifmode_local"] = self.connectivity_screen.ids.connectivity_local_ifmode.text.lower( + ) + self.sideband.config["connect_ifmode_tcp"] = self.connectivity_screen.ids.connectivity_tcp_ifmode.text.lower( + ) + self.sideband.config["connect_ifmode_i2p"] = self.connectivity_screen.ids.connectivity_i2p_ifmode.text.lower( + ) + self.sideband.config["connect_ifmode_rnode"] = self.connectivity_screen.ids.connectivity_rnode_ifmode.text.lower( + ) + self.sideband.config["connect_ifmode_modem"] = self.connectivity_screen.ids.connectivity_modem_ifmode.text.lower( + ) + self.sideband.config["connect_ifmode_serial"] = self.connectivity_screen.ids.connectivity_serial_ifmode.text.lower( + ) - con_collapse_local(collapse=not self.connectivity_screen.ids.connectivity_use_local.active) - con_collapse_tcp(collapse=not self.connectivity_screen.ids.connectivity_use_tcp.active) - con_collapse_i2p(collapse=not self.connectivity_screen.ids.connectivity_use_i2p.active) - con_collapse_rnode(collapse=not self.connectivity_screen.ids.connectivity_use_rnode.active) - con_collapse_modem(collapse=not self.connectivity_screen.ids.connectivity_use_modem.active) - con_collapse_serial(collapse=not self.connectivity_screen.ids.connectivity_use_serial.active) - con_collapse_transport(collapse=not self.sideband.config["connect_transport"]) + con_collapse_local( + collapse=not self.connectivity_screen.ids.connectivity_use_local.active) + con_collapse_tcp( + collapse=not self.connectivity_screen.ids.connectivity_use_tcp.active) + con_collapse_i2p( + collapse=not self.connectivity_screen.ids.connectivity_use_i2p.active) + con_collapse_rnode( + collapse=not self.connectivity_screen.ids.connectivity_use_rnode.active) + con_collapse_modem( + collapse=not self.connectivity_screen.ids.connectivity_use_modem.active) + con_collapse_serial( + collapse=not self.connectivity_screen.ids.connectivity_use_serial.active) + con_collapse_transport( + collapse=not self.sideband.config["connect_transport"]) self.sideband.save_configuration() if sender == self.connectivity_screen.ids.connectivity_enable_transport: if sender.active: def cb(dt): - yes_button = MDRectangleFlatButton(text="Understood",font_size=dp(18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) + yes_button = MDRectangleFlatButton(text="Understood", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) dialog = MDDialog( title="Warning!", text="You have enabled [i]Reticulum Transport[/i] for this device.\n\nFor normal operation, and for most users, this is [b]not[/b] necessary, and might even degrade your network performance.\n\nWhen Transport is enabled, your device will route traffic between all connected interfaces and for all reachable devices on the network.\n\nThis should only be done if you intend to keep your device in a fixed position and for it to remain available continously.\n\nIf this is not the case, or you don't understand any of this, turn off Transport.", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) @@ -3489,16 +3835,22 @@ class SidebandApp(MDApp): def serial_connectivity_save(sender=None, event=None): if sender.active: - self.connectivity_screen.ids.connectivity_use_rnode.unbind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_use_modem.unbind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_use_serial.unbind(active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_use_rnode.unbind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_use_modem.unbind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_use_serial.unbind( + active=serial_connectivity_save) self.connectivity_screen.ids.connectivity_use_rnode.active = False self.connectivity_screen.ids.connectivity_use_modem.active = False self.connectivity_screen.ids.connectivity_use_serial.active = False sender.active = True - self.connectivity_screen.ids.connectivity_use_rnode.bind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_use_modem.bind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_use_serial.bind(active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_use_rnode.bind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_use_modem.bind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_use_serial.bind( + active=serial_connectivity_save) save_connectivity(sender, event) def focus_save(sender=None, event=None): @@ -3508,10 +3860,13 @@ class SidebandApp(MDApp): def ifmode_validate(sender=None, event=None): if not sender.focus: all_valid = True - iftypes = ["local", "tcp", "i2p", "rnode", "modem", "serial"] + iftypes = ["local", "tcp", "i2p", + "rnode", "modem", "serial"] for iftype in iftypes: - element = self.connectivity_screen.ids["connectivity_"+iftype+"_ifmode"] - modes = ["full", "gateway", "access point", "roaming", "boundary"] + element = self.connectivity_screen.ids["connectivity_" + + iftype+"_ifmode"] + modes = ["full", "gateway", + "access point", "roaming", "boundary"] value = element.text.lower() if value in ["", "f"] or value.startswith("fu"): value = "full" @@ -3538,106 +3893,171 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.get_platform() == "android": if not self.sideband.getpersistent("service.is_controlling_connectivity"): - info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" + info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" info += "To configure connectivity, edit the relevant configuration file for the instance." self.connectivity_screen.ids.connectivity_info.text = info con_hide_settings() else: - info = "By default, Sideband will try to discover and connect to any available Reticulum networks via active WiFi and/or Ethernet interfaces. If any Reticulum Transport Instances are found, Sideband will use these to connect to wider Reticulum networks. You can disable this behaviour if you don't want it.\n\n" + info = "By default, Sideband will try to discover and connect to any available Reticulum networks via active WiFi and/or Ethernet interfaces. If any Reticulum Transport Instances are found, Sideband will use these to connect to wider Reticulum networks. You can disable this behaviour if you don't want it.\n\n" info += "You can also connect to a network via a remote or local Reticulum instance using TCP or I2P. [b]Please Note![/b] Connecting via I2P requires that you already have I2P running on your device, and that the SAM API is enabled.\n\n" info += "For changes to connectivity to take effect, you must shut down and restart Sideband.\n" self.connectivity_screen.ids.connectivity_info.text = info - self.connectivity_screen.ids.connectivity_use_local.active = self.sideband.config["connect_local"] - con_collapse_local(collapse=not self.connectivity_screen.ids.connectivity_use_local.active) - self.connectivity_screen.ids.connectivity_local_groupid.text = self.sideband.config["connect_local_groupid"] - self.connectivity_screen.ids.connectivity_local_ifac_netname.text = self.sideband.config["connect_local_ifac_netname"] - self.connectivity_screen.ids.connectivity_local_ifac_passphrase.text = self.sideband.config["connect_local_ifac_passphrase"] + self.connectivity_screen.ids.connectivity_use_local.active = self.sideband.config[ + "connect_local"] + con_collapse_local( + collapse=not self.connectivity_screen.ids.connectivity_use_local.active) + self.connectivity_screen.ids.connectivity_local_groupid.text = self.sideband.config[ + "connect_local_groupid"] + self.connectivity_screen.ids.connectivity_local_ifac_netname.text = self.sideband.config[ + "connect_local_ifac_netname"] + self.connectivity_screen.ids.connectivity_local_ifac_passphrase.text = self.sideband.config[ + "connect_local_ifac_passphrase"] - self.connectivity_screen.ids.connectivity_use_tcp.active = self.sideband.config["connect_tcp"] - con_collapse_tcp(collapse=not self.connectivity_screen.ids.connectivity_use_tcp.active) - self.connectivity_screen.ids.connectivity_tcp_host.text = self.sideband.config["connect_tcp_host"] - self.connectivity_screen.ids.connectivity_tcp_port.text = self.sideband.config["connect_tcp_port"] - self.connectivity_screen.ids.connectivity_tcp_ifac_netname.text = self.sideband.config["connect_tcp_ifac_netname"] - self.connectivity_screen.ids.connectivity_tcp_ifac_passphrase.text = self.sideband.config["connect_tcp_ifac_passphrase"] + self.connectivity_screen.ids.connectivity_use_tcp.active = self.sideband.config[ + "connect_tcp"] + con_collapse_tcp( + collapse=not self.connectivity_screen.ids.connectivity_use_tcp.active) + self.connectivity_screen.ids.connectivity_tcp_host.text = self.sideband.config[ + "connect_tcp_host"] + self.connectivity_screen.ids.connectivity_tcp_port.text = self.sideband.config[ + "connect_tcp_port"] + self.connectivity_screen.ids.connectivity_tcp_ifac_netname.text = self.sideband.config[ + "connect_tcp_ifac_netname"] + self.connectivity_screen.ids.connectivity_tcp_ifac_passphrase.text = self.sideband.config[ + "connect_tcp_ifac_passphrase"] - self.connectivity_screen.ids.connectivity_use_i2p.active = self.sideband.config["connect_i2p"] - con_collapse_i2p(collapse=not self.connectivity_screen.ids.connectivity_use_i2p.active) - self.connectivity_screen.ids.connectivity_i2p_b32.text = self.sideband.config["connect_i2p_b32"] - self.connectivity_screen.ids.connectivity_i2p_ifac_netname.text = self.sideband.config["connect_i2p_ifac_netname"] - self.connectivity_screen.ids.connectivity_i2p_ifac_passphrase.text = self.sideband.config["connect_i2p_ifac_passphrase"] + self.connectivity_screen.ids.connectivity_use_i2p.active = self.sideband.config[ + "connect_i2p"] + con_collapse_i2p( + collapse=not self.connectivity_screen.ids.connectivity_use_i2p.active) + self.connectivity_screen.ids.connectivity_i2p_b32.text = self.sideband.config[ + "connect_i2p_b32"] + self.connectivity_screen.ids.connectivity_i2p_ifac_netname.text = self.sideband.config[ + "connect_i2p_ifac_netname"] + self.connectivity_screen.ids.connectivity_i2p_ifac_passphrase.text = self.sideband.config[ + "connect_i2p_ifac_passphrase"] - self.connectivity_screen.ids.connectivity_use_rnode.active = self.sideband.config["connect_rnode"] - con_collapse_rnode(collapse=not self.connectivity_screen.ids.connectivity_use_rnode.active) - self.connectivity_screen.ids.connectivity_rnode_ifac_netname.text = self.sideband.config["connect_rnode_ifac_netname"] - self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase.text = self.sideband.config["connect_rnode_ifac_passphrase"] + self.connectivity_screen.ids.connectivity_use_rnode.active = self.sideband.config[ + "connect_rnode"] + con_collapse_rnode( + collapse=not self.connectivity_screen.ids.connectivity_use_rnode.active) + self.connectivity_screen.ids.connectivity_rnode_ifac_netname.text = self.sideband.config[ + "connect_rnode_ifac_netname"] + self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase.text = self.sideband.config[ + "connect_rnode_ifac_passphrase"] - self.connectivity_screen.ids.connectivity_use_modem.active = self.sideband.config["connect_modem"] - con_collapse_modem(collapse=not self.connectivity_screen.ids.connectivity_use_modem.active) - self.connectivity_screen.ids.connectivity_modem_ifac_netname.text = self.sideband.config["connect_modem_ifac_netname"] - self.connectivity_screen.ids.connectivity_modem_ifac_passphrase.text = self.sideband.config["connect_modem_ifac_passphrase"] + self.connectivity_screen.ids.connectivity_use_modem.active = self.sideband.config[ + "connect_modem"] + con_collapse_modem( + collapse=not self.connectivity_screen.ids.connectivity_use_modem.active) + self.connectivity_screen.ids.connectivity_modem_ifac_netname.text = self.sideband.config[ + "connect_modem_ifac_netname"] + self.connectivity_screen.ids.connectivity_modem_ifac_passphrase.text = self.sideband.config[ + "connect_modem_ifac_passphrase"] - self.connectivity_screen.ids.connectivity_use_serial.active = self.sideband.config["connect_serial"] - con_collapse_serial(collapse=not self.connectivity_screen.ids.connectivity_use_serial.active) - self.connectivity_screen.ids.connectivity_serial_ifac_netname.text = self.sideband.config["connect_serial_ifac_netname"] - self.connectivity_screen.ids.connectivity_serial_ifac_passphrase.text = self.sideband.config["connect_serial_ifac_passphrase"] + self.connectivity_screen.ids.connectivity_use_serial.active = self.sideband.config[ + "connect_serial"] + con_collapse_serial( + collapse=not self.connectivity_screen.ids.connectivity_use_serial.active) + self.connectivity_screen.ids.connectivity_serial_ifac_netname.text = self.sideband.config[ + "connect_serial_ifac_netname"] + self.connectivity_screen.ids.connectivity_serial_ifac_passphrase.text = self.sideband.config[ + "connect_serial_ifac_passphrase"] - self.connectivity_screen.ids.connectivity_enable_transport.active = self.sideband.config["connect_transport"] - con_collapse_transport(collapse=not self.sideband.config["connect_transport"]) - self.connectivity_screen.ids.connectivity_enable_transport.bind(active=save_connectivity) - self.connectivity_screen.ids.connectivity_local_ifmode.text = self.sideband.config["connect_ifmode_local"].capitalize() - self.connectivity_screen.ids.connectivity_tcp_ifmode.text = self.sideband.config["connect_ifmode_tcp"].capitalize() - self.connectivity_screen.ids.connectivity_i2p_ifmode.text = self.sideband.config["connect_ifmode_i2p"].capitalize() - self.connectivity_screen.ids.connectivity_rnode_ifmode.text = self.sideband.config["connect_ifmode_rnode"].capitalize() - self.connectivity_screen.ids.connectivity_modem_ifmode.text = self.sideband.config["connect_ifmode_modem"].capitalize() - self.connectivity_screen.ids.connectivity_serial_ifmode.text = self.sideband.config["connect_ifmode_serial"].capitalize() + self.connectivity_screen.ids.connectivity_enable_transport.active = self.sideband.config[ + "connect_transport"] + con_collapse_transport( + collapse=not self.sideband.config["connect_transport"]) + self.connectivity_screen.ids.connectivity_enable_transport.bind( + active=save_connectivity) + self.connectivity_screen.ids.connectivity_local_ifmode.text = self.sideband.config["connect_ifmode_local"].capitalize( + ) + self.connectivity_screen.ids.connectivity_tcp_ifmode.text = self.sideband.config["connect_ifmode_tcp"].capitalize( + ) + self.connectivity_screen.ids.connectivity_i2p_ifmode.text = self.sideband.config["connect_ifmode_i2p"].capitalize( + ) + self.connectivity_screen.ids.connectivity_rnode_ifmode.text = self.sideband.config["connect_ifmode_rnode"].capitalize( + ) + self.connectivity_screen.ids.connectivity_modem_ifmode.text = self.sideband.config["connect_ifmode_modem"].capitalize( + ) + self.connectivity_screen.ids.connectivity_serial_ifmode.text = self.sideband.config["connect_ifmode_serial"].capitalize( + ) - self.connectivity_screen.ids.connectivity_use_local.bind(active=save_connectivity) - self.connectivity_screen.ids.connectivity_local_groupid.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_local_ifac_netname.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_local_ifac_passphrase.bind(focus=focus_save) + self.connectivity_screen.ids.connectivity_use_local.bind( + active=save_connectivity) + self.connectivity_screen.ids.connectivity_local_groupid.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_local_ifac_netname.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_local_ifac_passphrase.bind( + focus=focus_save) - self.connectivity_screen.ids.connectivity_use_tcp.bind(active=save_connectivity) - self.connectivity_screen.ids.connectivity_tcp_host.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_tcp_port.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_tcp_ifac_netname.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_tcp_ifac_passphrase.bind(focus=focus_save) - - self.connectivity_screen.ids.connectivity_use_i2p.bind(active=save_connectivity) - self.connectivity_screen.ids.connectivity_i2p_b32.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_i2p_ifac_netname.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_i2p_ifac_passphrase.bind(focus=focus_save) - - self.connectivity_screen.ids.connectivity_use_rnode.bind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_rnode_ifac_netname.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase.bind(focus=focus_save) + self.connectivity_screen.ids.connectivity_use_tcp.bind( + active=save_connectivity) + self.connectivity_screen.ids.connectivity_tcp_host.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_tcp_port.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_tcp_ifac_netname.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_tcp_ifac_passphrase.bind( + focus=focus_save) - self.connectivity_screen.ids.connectivity_use_modem.bind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_modem_ifac_netname.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_modem_ifac_passphrase.bind(focus=focus_save) + self.connectivity_screen.ids.connectivity_use_i2p.bind( + active=save_connectivity) + self.connectivity_screen.ids.connectivity_i2p_b32.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_i2p_ifac_netname.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_i2p_ifac_passphrase.bind( + focus=focus_save) - self.connectivity_screen.ids.connectivity_use_serial.bind(active=serial_connectivity_save) - self.connectivity_screen.ids.connectivity_serial_ifac_netname.bind(focus=focus_save) - self.connectivity_screen.ids.connectivity_serial_ifac_passphrase.bind(focus=focus_save) + self.connectivity_screen.ids.connectivity_use_rnode.bind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_rnode_ifac_netname.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase.bind( + focus=focus_save) - self.connectivity_screen.ids.connectivity_local_ifmode.bind(focus=ifmode_validate) - self.connectivity_screen.ids.connectivity_tcp_ifmode.bind(focus=ifmode_validate) - self.connectivity_screen.ids.connectivity_i2p_ifmode.bind(focus=ifmode_validate) - self.connectivity_screen.ids.connectivity_rnode_ifmode.bind(focus=ifmode_validate) - self.connectivity_screen.ids.connectivity_modem_ifmode.bind(focus=ifmode_validate) - self.connectivity_screen.ids.connectivity_serial_ifmode.bind(focus=ifmode_validate) + self.connectivity_screen.ids.connectivity_use_modem.bind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_modem_ifac_netname.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_modem_ifac_passphrase.bind( + focus=focus_save) + + self.connectivity_screen.ids.connectivity_use_serial.bind( + active=serial_connectivity_save) + self.connectivity_screen.ids.connectivity_serial_ifac_netname.bind( + focus=focus_save) + self.connectivity_screen.ids.connectivity_serial_ifac_passphrase.bind( + focus=focus_save) + + self.connectivity_screen.ids.connectivity_local_ifmode.bind( + focus=ifmode_validate) + self.connectivity_screen.ids.connectivity_tcp_ifmode.bind( + focus=ifmode_validate) + self.connectivity_screen.ids.connectivity_i2p_ifmode.bind( + focus=ifmode_validate) + self.connectivity_screen.ids.connectivity_rnode_ifmode.bind( + focus=ifmode_validate) + self.connectivity_screen.ids.connectivity_modem_ifmode.bind( + focus=ifmode_validate) + self.connectivity_screen.ids.connectivity_serial_ifmode.bind( + focus=ifmode_validate) else: info = "" if self.sideband.reticulum.is_connected_to_shared_instance: - info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" + info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" info += "To get connectivity status, use the [b]rnstatus[/b] utility.\n\n" info += "To configure connectivity, edit the configuration file located at:\n\n" info += str(RNS.Reticulum.configpath) else: - info = "Sideband is currently running a standalone or master Reticulum instance on this system.\n\n" + info = "Sideband is currently running a standalone or master Reticulum instance on this system.\n\n" info += "To get connectivity status, use the [b]rnstatus[/b] utility.\n\n" info += "To configure connectivity, edit the configuration file located at:\n\n" info += str(RNS.Reticulum.configpath) @@ -3650,31 +4070,38 @@ class SidebandApp(MDApp): def close_connectivity_action(self, sender=None): self.open_conversations(direction="right") - + def rpc_copy_action(self, sender=None): - c_yes_button = MDRectangleFlatButton(text="Yes",font_size=dp(18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) - c_no_button = MDRectangleFlatButton(text="No, go back",font_size=dp(18)) - c_dialog = MDDialog(text="[b]Caution![/b]\n\nA configuration line containing your Reticulum RPC key will be copied to the system clipboard.\n\nWhile the key can only be used by other programs running locally on this system, it is still recommended to take care in not exposing it to unwanted programs.\n\nAre you sure that you wish to proceed?", buttons=[ c_no_button, c_yes_button ]) + c_yes_button = MDRectangleFlatButton(text="Yes", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) + c_no_button = MDRectangleFlatButton( + text="No, go back", font_size=dp(18)) + c_dialog = MDDialog(text="[b]Caution![/b]\n\nA configuration line containing your Reticulum RPC key will be copied to the system clipboard.\n\nWhile the key can only be used by other programs running locally on this system, it is still recommended to take care in not exposing it to unwanted programs.\n\nAre you sure that you wish to proceed?", buttons=[c_no_button, c_yes_button]) + def c_dl_no(s): c_dialog.dismiss() + def c_dl_yes(s): c_dialog.dismiss() yes_button = MDRectangleFlatButton(text="OK") - dialog = MDDialog(text="The RPC configuration was copied to the system clipboard. Paste in into the [b][reticulum][/b] section of the relevant Reticulum configuration file to allow access to this instance.", buttons=[ yes_button ]) + dialog = MDDialog( + text="The RPC configuration was copied to the system clipboard. Paste in into the [b][reticulum][/b] section of the relevant Reticulum configuration file to allow access to this instance.", buttons=[yes_button]) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) - rpc_string = "rpc_key = "+RNS.hexrep(self.sideband.reticulum.rpc_key, delimit=False) + rpc_string = "rpc_key = " + \ + RNS.hexrep(self.sideband.reticulum.rpc_key, delimit=False) Clipboard.copy(rpc_string) dialog.open() - + c_yes_button.bind(on_release=c_dl_yes) c_no_button.bind(on_release=c_dl_no) c_dialog.open() - ### Repository screen + # Repository screen ###################################### def repository_action(self, sender=None, direction="left"): if self.repository_ready: @@ -3682,8 +4109,10 @@ class SidebandApp(MDApp): self.repository_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.repository_init() + def o(dt): self.repository_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -3699,19 +4128,20 @@ class SidebandApp(MDApp): self.repository_screen.ids.repository_update.text = "" self.root.ids.screen_manager.current = "repository_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition def repository_link_action(self, sender=None, event=None): - if self.reposository_url != None: + if self.repository_url != None: def lj(): - webbrowser.open(self.reposository_url) + webbrowser.open(self.repository_url) threading.Thread(target=lj, daemon=True).start() def repository_update_info(self, sender=None): - info = "Sideband includes a small repository of useful software and guides related to the Sideband and Reticulum ecosystem. You can start this repository to allow other people on your local network to download software and information directly from this device, without needing an Internet connection.\n\n" + info = "Sideband includes a small repository of useful software and guides related to the Sideband and Reticulum ecosystem. You can start this repository to allow other people on your local network to download software and information directly from this device, without needing an Internet connection.\n\n" info += "If you want to share the Sideband application itself via the repository server, you must first download it into the local repository, using the \"Update Content\" button below.\n\n" info += "To make the repository available on your local network, simply start it below, and it will become browsable on a local IP address for anyone connected to the same WiFi or wired network.\n\n" if self.sideband.webshare_server != None: @@ -3721,10 +4151,13 @@ class SidebandApp(MDApp): try: from jnius import autoclass import ipaddress - mActivity = autoclass('org.kivy.android.PythonActivity').mActivity - SystemProperties = autoclass('android.os.SystemProperties') + mActivity = autoclass( + 'org.kivy.android.PythonActivity').mActivity + SystemProperties = autoclass( + 'android.os.SystemProperties') Context = autoclass('android.content.Context') - connectivity_manager = mActivity.getSystemService(Context.CONNECTIVITY_SERVICE) + connectivity_manager = mActivity.getSystemService( + Context.CONNECTIVITY_SERVICE) ns = connectivity_manager.getAllNetworks() if not ns == None and len(ns) > 0: for n in ns: @@ -3737,7 +4170,8 @@ class SidebandApp(MDApp): adrs.append(ha) except Exception as e: - RNS.log("Error while getting repository IP address: "+str(e), RNS.LOG_ERROR) + RNS.log( + "Error while getting repository IP address: "+str(e), RNS.LOG_ERROR) return None else: @@ -3749,16 +4183,19 @@ class SidebandApp(MDApp): ips = getIP() if ips == None or len(ips) == 0: info += "The repository server is running, but the local device IP address could not be determined.\n\nYou can access the repository by pointing a browser to: https://DEVICE_IP:4444/" - self.reposository_url = None + self.repository_url = None else: ipstr = "" for ip in ips: - ipstr += "https://"+str(ip)+":4444/" - self.reposository_url = ipstr + ipstr += "[u][ref=link]https://" + \ + str(ip)+":4444/[/ref][u]\n" + self.repository_url = ipstr ms = "" if len(ips) == 1 else "es" - info += "The repository server is running at the following address"+ms+":\n [u][ref=link]"+ipstr+"[/ref][u]\n" - self.repository_screen.ids.repository_info.bind(on_ref_press=self.repository_link_action) + info += "The repository server is running at the following address" + \ + ms+":\n"+ipstr + self.repository_screen.ids.repository_info.bind( + on_ref_press=self.repository_link_action) def cb(dt): self.repository_screen.ids.repository_enable_button.disabled = True @@ -3777,8 +4214,8 @@ class SidebandApp(MDApp): Clock.schedule_once(self.repository_update_info, 1.0) def repository_stop_action(self, sender=None): - self.reposository_url = None - self.sideband.stop_webshare() + self.repository_url = None + self.sideband.stop_webshare() Clock.schedule_once(self.repository_update_info, 0.75) def repository_download_action(self, sender=None): @@ -3799,18 +4236,22 @@ class SidebandApp(MDApp): fw_url = asset["browser_download_url"] pkgname = asset["name"] fw_version = release["tag_name"] - RNS.log(f"Found version {fw_version} artefact {pkgname} at {fw_url}", RNS.LOG_DEBUG) - downloads.append([fw_url, pkgname, fw_version]) + RNS.log( + f"Found version {fw_version} artefact {pkgname} at {fw_url}", RNS.LOG_DEBUG) + downloads.append( + [fw_url, pkgname, fw_version]) except Exception as e: - self.repository_screen.ids.repository_update.text = f"Downloading RNode firmware release info failed with the error:\n"+str(e) + self.repository_screen.ids.repository_update.text = f"Downloading RNode firmware release info failed with the error:\n" + \ + str(e) return try: for download in downloads: fw_url = download[0] pkgname = download[1] - self.repository_screen.ids.repository_update.text = "Downloading: "+str(pkgname) + self.repository_screen.ids.repository_update.text = "Downloading: " + \ + str(pkgname) with requests.get(fw_url, stream=True) as response: with open("./dl_tmp", "wb") as tmp_file: cs = 32*1024 @@ -3818,13 +4259,17 @@ class SidebandApp(MDApp): for chunk in response.iter_content(chunk_size=cs): tmp_file.write(chunk) tds += cs - self.repository_screen.ids.repository_update.text = "Downloaded "+RNS.prettysize(tds)+" of "+str(pkgname) + self.repository_screen.ids.repository_update.text = "Downloaded " + \ + RNS.prettysize( + tds)+" of "+str(pkgname) - os.rename("./dl_tmp", f"{self.sideband.webshare_dir}/pkg/{pkgname}") + os.rename( + "./dl_tmp", f"{self.sideband.webshare_dir}/pkg/{pkgname}") self.repository_screen.ids.repository_update.text = f"Added {pkgname} to the repository!" except Exception as e: - self.repository_screen.ids.repository_update.text = f"Downloading RNode firmware failed with the error:\n"+str(e) + self.repository_screen.ids.repository_update.text = f"Downloading RNode firmware failed with the error:\n" + \ + str(e) return ### Sideband APK File ######### @@ -3844,12 +4289,15 @@ class SidebandApp(MDApp): apk_url = asset["browser_download_url"] pkgname = asset["name"] apk_version = release["tag_name"] - RNS.log(f"Found version {apk_version} artefact {pkgname} at {apk_url}", RNS.LOG_DEBUG) + RNS.log( + f"Found version {apk_version} artefact {pkgname} at {apk_url}", RNS.LOG_DEBUG) except Exception as e: - self.repository_screen.ids.repository_update.text = f"Downloading Sideband APK release info failed with the error:\n"+str(e) + self.repository_screen.ids.repository_update.text = f"Downloading Sideband APK release info failed with the error:\n" + \ + str(e) return - self.repository_screen.ids.repository_update.text = "Downloading: "+str(pkgname) + self.repository_screen.ids.repository_update.text = "Downloading: " + \ + str(pkgname) with requests.get(apk_url, stream=True) as response: with open("./dl_tmp", "wb") as tmp_file: cs = 32*1024 @@ -3857,17 +4305,21 @@ class SidebandApp(MDApp): for chunk in response.iter_content(chunk_size=cs): tmp_file.write(chunk) tds += cs - self.repository_screen.ids.repository_update.text = "Downloaded "+RNS.prettysize(tds)+" of "+str(pkgname) + self.repository_screen.ids.repository_update.text = "Downloaded " + \ + RNS.prettysize(tds)+" of "+str(pkgname) - os.rename("./dl_tmp", f"{self.sideband.webshare_dir}/pkg/{pkgname}") + os.rename( + "./dl_tmp", f"{self.sideband.webshare_dir}/pkg/{pkgname}") self.repository_screen.ids.repository_update.text = f"Added {pkgname} to the repository!" self.repository_screen.ids.repository_update.text = f"Repository contents updated successfully!" except Exception as e: - self.repository_screen.ids.repository_update.text = f"Downloading contents failed with the error:\n"+str(e) + self.repository_screen.ids.repository_update.text = f"Downloading contents failed with the error:\n" + \ + str(e) self.repository_screen.ids.repository_update.text = "Starting package download..." + def start_update_job(sender=None): threading.Thread(target=update_job, daemon=True).start() Clock.schedule_once(start_update_job, 0.5) @@ -3875,7 +4327,8 @@ class SidebandApp(MDApp): def repository_init(self, sender=None): if not self.repository_ready: if not self.root.ids.screen_manager.has_screen("repository_screen"): - self.repository_screen = Builder.load_string(layout_repository_screen) + self.repository_screen = Builder.load_string( + layout_repository_screen) self.repository_screen.app = self self.root.ids.screen_manager.add_widget(self.repository_screen) @@ -3886,15 +4339,17 @@ class SidebandApp(MDApp): def close_repository_action(self, sender=None): self.open_conversations(direction="right") - ### Hardware screen + # Hardware screen ###################################### def hardware_action(self, sender=None, direction="left"): if self.hardware_ready: self.hardware_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.hardware_init() + def o(dt): self.hardware_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -3911,37 +4366,42 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = direction self.root.ids.screen_manager.current = "hardware_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition def close_sub_hardware_action(self, sender=None): self.hardware_action(direction="right") - + def hardware_init(self, sender=None): if not self.hardware_ready: if not self.root.ids.screen_manager.has_screen("hardware_screen"): - self.hardware_screen = Builder.load_string(layout_hardware_screen) + self.hardware_screen = Builder.load_string( + layout_hardware_screen) self.hardware_screen.app = self self.root.ids.screen_manager.add_widget(self.hardware_screen) self.hardware_screen.ids.hardware_scrollview.effect_cls = ScrollEffect def con_hide_settings(): - self.widget_hide(self.hardware_screen.ids.hardware_rnode_button) - self.widget_hide(self.hardware_screen.ids.hardware_modem_button) - self.widget_hide(self.hardware_screen.ids.hardware_serial_button) + self.widget_hide( + self.hardware_screen.ids.hardware_rnode_button) + self.widget_hide( + self.hardware_screen.ids.hardware_modem_button) + self.widget_hide( + self.hardware_screen.ids.hardware_serial_button) if RNS.vendor.platformutils.get_platform() == "android": if not self.sideband.getpersistent("service.is_controlling_connectivity"): - info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" + info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" info += "To configure hardware parameters, edit the relevant configuration file for the instance." self.hardware_screen.ids.hardware_info.text = info con_hide_settings() else: - info = "When using external hardware for communicating, you may configure various parameters, such as channel settings, modulation schemes, interface speeds and access parameters. You can set up these parameters per device type, and Sideband will apply the configuration when opening a device of that type.\n\n" + info = "When using external hardware for communicating, you may configure various parameters, such as channel settings, modulation schemes, interface speeds and access parameters. You can set up these parameters per device type, and Sideband will apply the configuration when opening a device of that type.\n\n" info += "Hardware configurations can also be exported or imported as [i]config motes[/i], which are self-contained plaintext strings that are easy to share with others. When importing a config mote, Sideband will automatically set all relevant parameters as specified within it.\n\n" info += "For changes to hardware parameters to take effect, you must shut down and restart Sideband.\n" self.hardware_screen.ids.hardware_info.text = info @@ -3950,11 +4410,11 @@ class SidebandApp(MDApp): info = "" if self.sideband.reticulum.is_connected_to_shared_instance: - info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" + info = "Sideband is connected via a shared Reticulum instance running on this system.\n\n" info += "To configure hardware parameters, edit the configuration file located at:\n\n" info += str(RNS.Reticulum.configpath) else: - info = "Sideband is currently running a standalone or master Reticulum instance on this system.\n\n" + info = "Sideband is currently running a standalone or master Reticulum instance on this system.\n\n" info += "To configure hardware parameters, edit the configuration file located at:\n\n" info += str(RNS.Reticulum.configpath) @@ -3967,14 +4427,16 @@ class SidebandApp(MDApp): def close_hardware_action(self, sender=None): self.open_conversations(direction="right") - ## RNode hardware screen + # RNode hardware screen def hardware_rnode_action(self, sender=None, direction="left"): if self.hardware_rnode_ready: self.hardware_rnode_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.hardware_rnode_init() + def o(dt): self.hardware_rnode_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -3990,52 +4452,61 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = "left" self.root.ids.screen_manager.current = "hardware_rnode_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition def hardware_rnode_save(self): try: - self.sideband.config["hw_rnode_frequency"] = int(float(self.hardware_rnode_screen.ids.hardware_rnode_frequency.text)*1000000) + self.sideband.config["hw_rnode_frequency"] = int( + float(self.hardware_rnode_screen.ids.hardware_rnode_frequency.text)*1000000) except: pass try: - self.sideband.config["hw_rnode_bandwidth"] = int(float(self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text)*1000) + self.sideband.config["hw_rnode_bandwidth"] = int( + float(self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text)*1000) except: pass try: - self.sideband.config["hw_rnode_tx_power"] = int(self.hardware_rnode_screen.ids.hardware_rnode_txpower.text) + self.sideband.config["hw_rnode_tx_power"] = int( + self.hardware_rnode_screen.ids.hardware_rnode_txpower.text) except: pass try: - self.sideband.config["hw_rnode_spreading_factor"] = int(self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text) + self.sideband.config["hw_rnode_spreading_factor"] = int( + self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text) except: pass - + try: - self.sideband.config["hw_rnode_coding_rate"] = int(self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text) + self.sideband.config["hw_rnode_coding_rate"] = int( + self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text) except: pass - + try: - self.sideband.config["hw_rnode_atl_short"] = float(self.hardware_rnode_screen.ids.hardware_rnode_atl_short.text) + self.sideband.config["hw_rnode_atl_short"] = float( + self.hardware_rnode_screen.ids.hardware_rnode_atl_short.text) except: self.sideband.config["hw_rnode_atl_short"] = None try: - self.sideband.config["hw_rnode_atl_long"] = float(self.hardware_rnode_screen.ids.hardware_rnode_atl_long.text) + self.sideband.config["hw_rnode_atl_long"] = float( + self.hardware_rnode_screen.ids.hardware_rnode_atl_long.text) except: self.sideband.config["hw_rnode_atl_long"] = None - + if self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text == "": self.sideband.config["hw_rnode_beaconinterval"] = None else: try: - self.sideband.config["hw_rnode_beaconinterval"] = int(self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text) + self.sideband.config["hw_rnode_beaconinterval"] = int( + self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text) except: pass @@ -4055,6 +4526,7 @@ class SidebandApp(MDApp): self.hardware_rnode_screen.ids.hardware_rnode_bt_pair_button.disabled = True self.hardware_rnode_screen.ids.hardware_rnode_bt_on_button.disabled = True self.hardware_rnode_screen.ids.hardware_rnode_bt_off_button.disabled = True + def re_enable(): time.sleep(2) while self.sideband.getstate("executing.bt_on"): @@ -4069,6 +4541,7 @@ class SidebandApp(MDApp): self.hardware_rnode_screen.ids.hardware_rnode_bt_pair_button.disabled = True self.hardware_rnode_screen.ids.hardware_rnode_bt_on_button.disabled = True self.hardware_rnode_screen.ids.hardware_rnode_bt_off_button.disabled = True + def re_enable(): time.sleep(2) while self.sideband.getstate("executing.bt_off"): @@ -4083,6 +4556,7 @@ class SidebandApp(MDApp): self.hardware_rnode_screen.ids.hardware_rnode_bt_pair_button.disabled = True self.hardware_rnode_screen.ids.hardware_rnode_bt_on_button.disabled = True self.hardware_rnode_screen.ids.hardware_rnode_bt_off_button.disabled = True + def re_enable(): time.sleep(2) while self.sideband.getstate("executing.bt_pair"): @@ -4101,7 +4575,7 @@ class SidebandApp(MDApp): self.sideband.config["hw_rnode_bluetooth"] = False self.sideband.save_configuration() - + def hardware_rnode_ble_toggle_action(self, sender=None, event=None): if sender.active: self.sideband.config["hw_rnode_ble"] = True @@ -4110,7 +4584,7 @@ class SidebandApp(MDApp): self.sideband.config["hw_rnode_ble"] = False self.sideband.save_configuration() - + def hardware_rnode_framebuffer_toggle_action(self, sender=None, event=None): if sender.active: self.sideband.config["hw_rnode_enable_framebuffer"] = True @@ -4118,15 +4592,18 @@ class SidebandApp(MDApp): self.sideband.config["hw_rnode_enable_framebuffer"] = False self.sideband.save_configuration() - + def hardware_rnode_init(self, sender=None): if not self.hardware_rnode_ready: if not self.root.ids.screen_manager.has_screen("hardware_rnode_screen"): - self.hardware_rnode_screen = Builder.load_string(layout_hardware_rnode_screen) + self.hardware_rnode_screen = Builder.load_string( + layout_hardware_rnode_screen) self.hardware_rnode_screen.app = self - self.root.ids.screen_manager.add_widget(self.hardware_rnode_screen) + self.root.ids.screen_manager.add_widget( + self.hardware_rnode_screen) self.hardware_rnode_screen.ids.hardware_rnode_scrollview.effect_cls = ScrollEffect + def save_connectivity(sender=None, event=None): if self.hardware_rnode_validate(): self.hardware_rnode_save() @@ -4137,7 +4614,8 @@ class SidebandApp(MDApp): save_connectivity(sender=sender) if self.sideband.config["hw_rnode_frequency"] != None: - t_freq = str(self.sideband.config["hw_rnode_frequency"]/1000000.0) + t_freq = str( + self.sideband.config["hw_rnode_frequency"]/1000000.0) else: t_freq = "" if self.sideband.config["hw_rnode_bandwidth"] != None: @@ -4177,9 +4655,12 @@ class SidebandApp(MDApp): else: t_atl = "" - self.hardware_rnode_screen.ids.hardware_rnode_bluetooth.active = self.sideband.config["hw_rnode_bluetooth"] - self.hardware_rnode_screen.ids.hardware_rnode_ble.active = self.sideband.config["hw_rnode_ble"] - self.hardware_rnode_screen.ids.hardware_rnode_framebuffer.active = self.sideband.config["hw_rnode_enable_framebuffer"] + self.hardware_rnode_screen.ids.hardware_rnode_bluetooth.active = self.sideband.config[ + "hw_rnode_bluetooth"] + self.hardware_rnode_screen.ids.hardware_rnode_ble.active = self.sideband.config[ + "hw_rnode_ble"] + self.hardware_rnode_screen.ids.hardware_rnode_framebuffer.active = self.sideband.config[ + "hw_rnode_enable_framebuffer"] self.hardware_rnode_screen.ids.hardware_rnode_frequency.text = t_freq self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text = t_bw self.hardware_rnode_screen.ids.hardware_rnode_txpower.text = t_p @@ -4190,94 +4671,126 @@ class SidebandApp(MDApp): self.hardware_rnode_screen.ids.hardware_rnode_bt_device.text = t_btd self.hardware_rnode_screen.ids.hardware_rnode_atl_short.text = t_ats self.hardware_rnode_screen.ids.hardware_rnode_atl_long.text = t_atl - self.hardware_rnode_screen.ids.hardware_rnode_frequency.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_txpower.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_codingrate.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_beacondata.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_bt_device.bind(focus=focus_save) - self.hardware_rnode_screen.ids.hardware_rnode_frequency.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_txpower.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_codingrate.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_beacondata.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_atl_short.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_atl_long.bind(on_text_validate=save_connectivity) - self.hardware_rnode_screen.ids.hardware_rnode_bluetooth.bind(active=self.hardware_rnode_bt_toggle_action) - self.hardware_rnode_screen.ids.hardware_rnode_ble.bind(active=self.hardware_rnode_ble_toggle_action) - self.hardware_rnode_screen.ids.hardware_rnode_framebuffer.bind(active=self.hardware_rnode_framebuffer_toggle_action) + self.hardware_rnode_screen.ids.hardware_rnode_frequency.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_txpower.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_codingrate.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_beacondata.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_bt_device.bind( + focus=focus_save) + self.hardware_rnode_screen.ids.hardware_rnode_frequency.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_txpower.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_codingrate.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_beacondata.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_atl_short.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_atl_long.bind( + on_text_validate=save_connectivity) + self.hardware_rnode_screen.ids.hardware_rnode_bluetooth.bind( + active=self.hardware_rnode_bt_toggle_action) + self.hardware_rnode_screen.ids.hardware_rnode_ble.bind( + active=self.hardware_rnode_ble_toggle_action) + self.hardware_rnode_screen.ids.hardware_rnode_framebuffer.bind( + active=self.hardware_rnode_framebuffer_toggle_action) self.hardware_rnode_ready = True def hardware_rnode_validate(self, sender=None): - valid = True + valid = True try: - val = float(self.hardware_rnode_screen.ids.hardware_rnode_frequency.text) + val = float( + self.hardware_rnode_screen.ids.hardware_rnode_frequency.text) if not val > 0: raise ValueError("Invalid frequency") self.hardware_rnode_screen.ids.hardware_rnode_frequency.error = False - self.hardware_rnode_screen.ids.hardware_rnode_frequency.text = str(val) + self.hardware_rnode_screen.ids.hardware_rnode_frequency.text = str( + val) except: self.hardware_rnode_screen.ids.hardware_rnode_frequency.error = True valid = False - + try: - valid_vals = [7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250, 500] - val = float(self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text) + valid_vals = [7.8, 10.4, 15.6, 20.8, + 31.25, 41.7, 62.5, 125, 250, 500] + val = float( + self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text) if not val in valid_vals: raise ValueError("Invalid bandwidth") self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.error = False - self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text = str(val) + self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text = str( + val) except: self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.error = True valid = False - + try: val = int(self.hardware_rnode_screen.ids.hardware_rnode_txpower.text) if not val >= 0: raise ValueError("Invalid TX power") self.hardware_rnode_screen.ids.hardware_rnode_txpower.error = False - self.hardware_rnode_screen.ids.hardware_rnode_txpower.text = str(val) + self.hardware_rnode_screen.ids.hardware_rnode_txpower.text = str( + val) except: self.hardware_rnode_screen.ids.hardware_rnode_txpower.error = True valid = False - + try: - val = int(self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text) + val = int( + self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text) if val < 7 or val > 12: raise ValueError("Invalid sf") self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.error = False - self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text = str(val) + self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text = str( + val) except: self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.error = True valid = False - + try: - val = int(self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text) + val = int( + self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text) if val < 5 or val > 8: raise ValueError("Invalid cr") self.hardware_rnode_screen.ids.hardware_rnode_codingrate.error = False - self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text = str(val) + self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text = str( + val) except: self.hardware_rnode_screen.ids.hardware_rnode_codingrate.error = True valid = False - + try: if self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text != "": - val = int(self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text) + val = int( + self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text) if val < 10: raise ValueError("Invalid beacon interval") - self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text = str(val) + self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text = str( + val) self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.error = False except: self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text = "" valid = False - + return valid def hardware_rnode_import(self, sender=None): @@ -4285,13 +4798,14 @@ class SidebandApp(MDApp): try: mote = Clipboard.paste() except Exception as e: - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Import Failed", text="Could not read data from your clipboard, please check your system permissions.", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) @@ -4299,12 +4813,17 @@ class SidebandApp(MDApp): try: config = msgpack.unpackb(base64.b32decode(mote)) - self.hardware_rnode_screen.ids.hardware_rnode_frequency.text = str(config["f"]/1000000.0) - self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text = str(config["b"]/1000.0) - self.hardware_rnode_screen.ids.hardware_rnode_txpower.text = str(config["t"]) - self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text = str(config["s"]) - self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text = str(config["c"]) - + self.hardware_rnode_screen.ids.hardware_rnode_frequency.text = str( + config["f"]/1000000.0) + self.hardware_rnode_screen.ids.hardware_rnode_bandwidth.text = str( + config["b"]/1000.0) + self.hardware_rnode_screen.ids.hardware_rnode_txpower.text = str( + config["t"]) + self.hardware_rnode_screen.ids.hardware_rnode_spreadingfactor.text = str( + config["s"]) + self.hardware_rnode_screen.ids.hardware_rnode_codingrate.text = str( + config["c"]) + if "n" in config and config["n"] != None: ifn = str(config["n"]) else: @@ -4314,31 +4833,32 @@ class SidebandApp(MDApp): else: ifp = "" - self.connectivity_screen.ids.connectivity_rnode_ifac_netname.text = ifn - self.sideband.config["connect_rnode_ifac_netname"] = ifn + self.connectivity_screen.ids.connectivity_rnode_ifac_netname.text = ifn + self.sideband.config["connect_rnode_ifac_netname"] = ifn self.connectivity_screen.ids.connectivity_rnode_ifac_passphrase.text = ifp - self.sideband.config["connect_rnode_ifac_passphrase"] = ifp + self.sideband.config["connect_rnode_ifac_passphrase"] = ifp if config["i"] != None: ti = str(config["i"]) else: ti = "" - self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text = ti + self.hardware_rnode_screen.ids.hardware_rnode_beaconinterval.text = ti if config["d"] != None: td = str(config["d"]) else: td = "" - self.hardware_rnode_screen.ids.hardware_rnode_beacondata.text = td + self.hardware_rnode_screen.ids.hardware_rnode_beacondata.text = td if self.hardware_rnode_validate(): self.hardware_rnode_save() - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Configuration Imported", text="The config mote was imported and saved as your active configuration.", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) @@ -4347,13 +4867,15 @@ class SidebandApp(MDApp): raise ValueError("Invalid mote") except Exception as e: - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Import Failed", - text="The read data did not contain a valid config mote. If any data was decoded, you may try to correct it by editing the relevant fields. The reported error was:\n\n"+str(e), - buttons=[ yes_button ], + text="The read data did not contain a valid config mote. If any data was decoded, you may try to correct it by editing the relevant fields. The reported error was:\n\n" + + str(e), + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) @@ -4378,39 +4900,43 @@ class SidebandApp(MDApp): if mote != None: Clipboard.copy(mote) - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Configuration Exported", text="The config mote was created and copied to your clipboard.", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) dialog.open() else: - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( title="Export Failed", text="The config mote could not be created, please check your settings.", - buttons=[ yes_button ], + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) dialog.open() - - ## Modem hardware screen - + + # Modem hardware screen + def hardware_modem_action(self, sender=None, direction="left"): if self.hardware_modem_ready: self.hardware_modem_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.hardware_modem_init() + def o(dt): self.hardware_modem_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -4427,7 +4953,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = "left" self.root.ids.screen_manager.current = "hardware_modem_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -4435,11 +4962,14 @@ class SidebandApp(MDApp): def hardware_modem_init(self, sender=None): if not self.hardware_modem_ready: if not self.root.ids.screen_manager.has_screen("hardware_modem_screen"): - self.hardware_modem_screen = Builder.load_string(layout_hardware_modem_screen) + self.hardware_modem_screen = Builder.load_string( + layout_hardware_modem_screen) self.hardware_modem_screen.app = self - self.root.ids.screen_manager.add_widget(self.hardware_modem_screen) + self.root.ids.screen_manager.add_widget( + self.hardware_modem_screen) self.hardware_modem_screen.ids.hardware_modem_scrollview.effect_cls = ScrollEffect + def save_connectivity(sender=None, event=None): if self.hardware_modem_validate(): self.hardware_modem_save() @@ -4463,22 +4993,22 @@ class SidebandApp(MDApp): t_p = str(self.sideband.config["hw_modem_parity"]) else: t_p = "" - + if self.sideband.config["hw_modem_stopbits"] != None: t_sb = str(self.sideband.config["hw_modem_stopbits"]) else: t_sb = "" - + if self.sideband.config["hw_modem_preamble"] != None: t_pa = str(self.sideband.config["hw_modem_preamble"]) else: t_pa = "" - + if self.sideband.config["hw_modem_tail"] != None: t_t = str(self.sideband.config["hw_modem_tail"]) else: t_t = "" - + if self.sideband.config["hw_modem_persistence"] != None: t_ps = str(self.sideband.config["hw_modem_persistence"]) else: @@ -4497,7 +5027,7 @@ class SidebandApp(MDApp): t_bd = str(self.sideband.config["hw_modem_beacondata"]) else: t_bd = "" - + self.hardware_modem_screen.ids.hardware_modem_baudrate.text = t_b self.hardware_modem_screen.ids.hardware_modem_databits.text = t_db self.hardware_modem_screen.ids.hardware_modem_parity.text = t_p @@ -4508,43 +5038,71 @@ class SidebandApp(MDApp): self.hardware_modem_screen.ids.hardware_modem_tail.text = t_t self.hardware_modem_screen.ids.hardware_modem_persistence.text = t_ps self.hardware_modem_screen.ids.hardware_modem_slottime.text = t_st - self.hardware_modem_screen.ids.hardware_modem_baudrate.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_databits.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_parity.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_stopbits.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_beaconinterval.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_beacondata.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_preamble.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_tail.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_persistence.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_slottime.bind(focus=focus_save) - self.hardware_modem_screen.ids.hardware_modem_baudrate.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_databits.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_parity.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_stopbits.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_beaconinterval.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_beacondata.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_preamble.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_tail.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_persistence.bind(on_text_validate=save_connectivity) - self.hardware_modem_screen.ids.hardware_modem_slottime.bind(on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_baudrate.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_databits.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_parity.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_stopbits.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_beaconinterval.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_beacondata.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_preamble.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_tail.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_persistence.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_slottime.bind( + focus=focus_save) + self.hardware_modem_screen.ids.hardware_modem_baudrate.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_databits.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_parity.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_stopbits.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_beaconinterval.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_beacondata.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_preamble.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_tail.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_persistence.bind( + on_text_validate=save_connectivity) + self.hardware_modem_screen.ids.hardware_modem_slottime.bind( + on_text_validate=save_connectivity) self.hardware_modem_ready = True - + def hardware_modem_save(self): - self.sideband.config["hw_modem_baudrate"] = int(self.hardware_modem_screen.ids.hardware_modem_baudrate.text) - self.sideband.config["hw_modem_databits"] = int(self.hardware_modem_screen.ids.hardware_modem_databits.text) + self.sideband.config["hw_modem_baudrate"] = int( + self.hardware_modem_screen.ids.hardware_modem_baudrate.text) + self.sideband.config["hw_modem_databits"] = int( + self.hardware_modem_screen.ids.hardware_modem_databits.text) self.sideband.config["hw_modem_parity"] = self.hardware_modem_screen.ids.hardware_modem_parity.text - self.sideband.config["hw_modem_stopbits"] = int(self.hardware_modem_screen.ids.hardware_modem_stopbits.text) - self.sideband.config["hw_modem_preamble"] = int(self.hardware_modem_screen.ids.hardware_modem_preamble.text) - self.sideband.config["hw_modem_tail"] = int(self.hardware_modem_screen.ids.hardware_modem_tail.text) - self.sideband.config["hw_modem_persistence"] = int(self.hardware_modem_screen.ids.hardware_modem_persistence.text) - self.sideband.config["hw_modem_slottime"] = int(self.hardware_modem_screen.ids.hardware_modem_slottime.text) + self.sideband.config["hw_modem_stopbits"] = int( + self.hardware_modem_screen.ids.hardware_modem_stopbits.text) + self.sideband.config["hw_modem_preamble"] = int( + self.hardware_modem_screen.ids.hardware_modem_preamble.text) + self.sideband.config["hw_modem_tail"] = int( + self.hardware_modem_screen.ids.hardware_modem_tail.text) + self.sideband.config["hw_modem_persistence"] = int( + self.hardware_modem_screen.ids.hardware_modem_persistence.text) + self.sideband.config["hw_modem_slottime"] = int( + self.hardware_modem_screen.ids.hardware_modem_slottime.text) if self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text == "": self.sideband.config["hw_modem_beaconinterval"] = None else: - self.sideband.config["hw_modem_beaconinterval"] = int(self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text) + self.sideband.config["hw_modem_beaconinterval"] = int( + self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text) if self.hardware_modem_screen.ids.hardware_modem_beacondata.text == "": self.sideband.config["hw_modem_beacondata"] = None @@ -4554,47 +5112,51 @@ class SidebandApp(MDApp): self.sideband.save_configuration() def hardware_modem_validate(self, sender=None): - valid = True + valid = True try: val = int(self.hardware_modem_screen.ids.hardware_modem_baudrate.text) if not val > 0: raise ValueError("Invalid baudrate") self.hardware_modem_screen.ids.hardware_modem_baudrate.error = False - self.hardware_modem_screen.ids.hardware_modem_baudrate.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_baudrate.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_baudrate.error = True valid = False - + try: val = int(self.hardware_modem_screen.ids.hardware_modem_databits.text) if not val > 0: raise ValueError("Invalid databits") self.hardware_modem_screen.ids.hardware_modem_databits.error = False - self.hardware_modem_screen.ids.hardware_modem_databits.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_databits.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_databits.error = True valid = False - + try: val = int(self.hardware_modem_screen.ids.hardware_modem_stopbits.text) if not val > 0: raise ValueError("Invalid stopbits") self.hardware_modem_screen.ids.hardware_modem_stopbits.error = False - self.hardware_modem_screen.ids.hardware_modem_stopbits.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_stopbits.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_stopbits.error = True valid = False - + try: val = int(self.hardware_modem_screen.ids.hardware_modem_preamble.text) if not (val >= 0 and val <= 1000): raise ValueError("Invalid preamble") self.hardware_modem_screen.ids.hardware_modem_preamble.error = False - self.hardware_modem_screen.ids.hardware_modem_preamble.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_preamble.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_preamble.error = True valid = False - + try: val = int(self.hardware_modem_screen.ids.hardware_modem_tail.text) if not (val > 0 and val <= 500): @@ -4604,27 +5166,30 @@ class SidebandApp(MDApp): except: self.hardware_modem_screen.ids.hardware_modem_tail.error = True valid = False - + try: val = int(self.hardware_modem_screen.ids.hardware_modem_slottime.text) if not (val > 0 and val <= 500): raise ValueError("Invalid slottime") self.hardware_modem_screen.ids.hardware_modem_slottime.error = False - self.hardware_modem_screen.ids.hardware_modem_slottime.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_slottime.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_slottime.error = True valid = False - + try: - val = int(self.hardware_modem_screen.ids.hardware_modem_persistence.text) + val = int( + self.hardware_modem_screen.ids.hardware_modem_persistence.text) if not (val > 0 and val <= 255): raise ValueError("Invalid persistence") self.hardware_modem_screen.ids.hardware_modem_persistence.error = False - self.hardware_modem_screen.ids.hardware_modem_persistence.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_persistence.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_persistence.error = True valid = False - + try: val = self.hardware_modem_screen.ids.hardware_modem_parity.text nval = val.lower() @@ -4637,17 +5202,20 @@ class SidebandApp(MDApp): if not val in ["even", "odd", "none"]: raise ValueError("Invalid parity") self.hardware_modem_screen.ids.hardware_modem_parity.error = False - self.hardware_modem_screen.ids.hardware_modem_parity.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_parity.text = str( + val) except: self.hardware_modem_screen.ids.hardware_modem_parity.error = True valid = False try: if self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text != "": - val = int(self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text) + val = int( + self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text) if val < 10: raise ValueError("Invalid bi") - self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text = str(val) + self.hardware_modem_screen.ids.hardware_modem_beaconinterval.text = str( + val) self.hardware_modem_screen.ids.hardware_modem_beaconinterval.error = False except: @@ -4655,15 +5223,17 @@ class SidebandApp(MDApp): valid = False return valid - - ## Serial hardware screen + + # Serial hardware screen def hardware_serial_action(self, sender=None, direction="left"): if self.hardware_serial_ready: self.hardware_serial_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.hardware_serial_init() + def o(dt): self.hardware_serial_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -4679,7 +5249,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = "left" self.root.ids.screen_manager.current = "hardware_serial_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -4687,11 +5258,14 @@ class SidebandApp(MDApp): def hardware_serial_init(self, sender=None): if not self.hardware_serial_ready: if not self.root.ids.screen_manager.has_screen("hardware_serial_screen"): - self.hardware_serial_screen = Builder.load_string(layout_hardware_serial_screen) + self.hardware_serial_screen = Builder.load_string( + layout_hardware_serial_screen) self.hardware_serial_screen.app = self - self.root.ids.screen_manager.add_widget(self.hardware_serial_screen) + self.root.ids.screen_manager.add_widget( + self.hardware_serial_screen) self.hardware_serial_screen.ids.hardware_serial_scrollview.effect_cls = ScrollEffect + def save_connectivity(sender=None, event=None): if self.hardware_serial_validate(): self.hardware_serial_save() @@ -4715,59 +5289,73 @@ class SidebandApp(MDApp): t_p = str(self.sideband.config["hw_serial_parity"]) else: t_p = "" - + if self.sideband.config["hw_serial_stopbits"] != None: t_sb = str(self.sideband.config["hw_serial_stopbits"]) else: t_sb = "" - + self.hardware_serial_screen.ids.hardware_serial_baudrate.text = t_b self.hardware_serial_screen.ids.hardware_serial_databits.text = t_db self.hardware_serial_screen.ids.hardware_serial_parity.text = t_p self.hardware_serial_screen.ids.hardware_serial_stopbits.text = t_sb - self.hardware_serial_screen.ids.hardware_serial_baudrate.bind(focus=focus_save) - self.hardware_serial_screen.ids.hardware_serial_databits.bind(focus=focus_save) - self.hardware_serial_screen.ids.hardware_serial_parity.bind(focus=focus_save) - self.hardware_serial_screen.ids.hardware_serial_stopbits.bind(focus=focus_save) - self.hardware_serial_screen.ids.hardware_serial_baudrate.bind(on_text_validate=save_connectivity) - self.hardware_serial_screen.ids.hardware_serial_databits.bind(on_text_validate=save_connectivity) - self.hardware_serial_screen.ids.hardware_serial_parity.bind(on_text_validate=save_connectivity) - self.hardware_serial_screen.ids.hardware_serial_stopbits.bind(on_text_validate=save_connectivity) + self.hardware_serial_screen.ids.hardware_serial_baudrate.bind( + focus=focus_save) + self.hardware_serial_screen.ids.hardware_serial_databits.bind( + focus=focus_save) + self.hardware_serial_screen.ids.hardware_serial_parity.bind( + focus=focus_save) + self.hardware_serial_screen.ids.hardware_serial_stopbits.bind( + focus=focus_save) + self.hardware_serial_screen.ids.hardware_serial_baudrate.bind( + on_text_validate=save_connectivity) + self.hardware_serial_screen.ids.hardware_serial_databits.bind( + on_text_validate=save_connectivity) + self.hardware_serial_screen.ids.hardware_serial_parity.bind( + on_text_validate=save_connectivity) + self.hardware_serial_screen.ids.hardware_serial_stopbits.bind( + on_text_validate=save_connectivity) self.hardware_serial_ready = True def hardware_serial_validate(self, sender=None): - valid = True + valid = True try: - val = int(self.hardware_serial_screen.ids.hardware_serial_baudrate.text) + val = int( + self.hardware_serial_screen.ids.hardware_serial_baudrate.text) if not val > 0: raise ValueError("Invalid baudrate") self.hardware_serial_screen.ids.hardware_serial_baudrate.error = False - self.hardware_serial_screen.ids.hardware_serial_baudrate.text = str(val) + self.hardware_serial_screen.ids.hardware_serial_baudrate.text = str( + val) except: self.hardware_serial_screen.ids.hardware_serial_baudrate.error = True valid = False - + try: - val = int(self.hardware_serial_screen.ids.hardware_serial_databits.text) + val = int( + self.hardware_serial_screen.ids.hardware_serial_databits.text) if not val > 0: raise ValueError("Invalid databits") self.hardware_serial_screen.ids.hardware_serial_databits.error = False - self.hardware_serial_screen.ids.hardware_serial_databits.text = str(val) + self.hardware_serial_screen.ids.hardware_serial_databits.text = str( + val) except: self.hardware_serial_screen.ids.hardware_serial_databits.error = True valid = False - + try: - val = int(self.hardware_serial_screen.ids.hardware_serial_stopbits.text) + val = int( + self.hardware_serial_screen.ids.hardware_serial_stopbits.text) if not val > 0: raise ValueError("Invalid stopbits") self.hardware_serial_screen.ids.hardware_serial_stopbits.error = False - self.hardware_serial_screen.ids.hardware_serial_stopbits.text = str(val) + self.hardware_serial_screen.ids.hardware_serial_stopbits.text = str( + val) except: self.hardware_serial_screen.ids.hardware_serial_stopbits.error = True valid = False - + try: val = self.hardware_serial_screen.ids.hardware_serial_parity.text nval = val.lower() @@ -4780,7 +5368,8 @@ class SidebandApp(MDApp): if not val in ["even", "odd", "none"]: raise ValueError("Invalid parity") self.hardware_serial_screen.ids.hardware_serial_parity.error = False - self.hardware_serial_screen.ids.hardware_serial_parity.text = str(val) + self.hardware_serial_screen.ids.hardware_serial_parity.text = str( + val) except: self.hardware_serial_screen.ids.hardware_serial_parity.error = True valid = False @@ -4788,14 +5377,17 @@ class SidebandApp(MDApp): return valid def hardware_serial_save(self): - self.sideband.config["hw_serial_baudrate"] = int(self.hardware_serial_screen.ids.hardware_serial_baudrate.text) - self.sideband.config["hw_serial_databits"] = int(self.hardware_serial_screen.ids.hardware_serial_databits.text) + self.sideband.config["hw_serial_baudrate"] = int( + self.hardware_serial_screen.ids.hardware_serial_baudrate.text) + self.sideband.config["hw_serial_databits"] = int( + self.hardware_serial_screen.ids.hardware_serial_databits.text) self.sideband.config["hw_serial_parity"] = self.hardware_serial_screen.ids.hardware_serial_parity.text - self.sideband.config["hw_serial_stopbits"] = int(self.hardware_serial_screen.ids.hardware_serial_stopbits.text) + self.sideband.config["hw_serial_stopbits"] = int( + self.hardware_serial_screen.ids.hardware_serial_stopbits.text) self.sideband.save_configuration() - ### Announce Stream screen + # Announce Stream screen ###################################### def init_announces_view(self, sender=None): if not self.announces_view: @@ -4803,10 +5395,12 @@ class SidebandApp(MDApp): self.sideband.setstate("app.flags.new_announces", True) for child in self.announces_view.ids.announces_scrollview.children: - self.announces_view.ids.announces_scrollview.remove_widget(child) + self.announces_view.ids.announces_scrollview.remove_widget( + child) self.announces_view.ids.announces_scrollview.effect_cls = ScrollEffect - self.announces_view.ids.announces_scrollview.add_widget(self.announces_view.get_widget()) + self.announces_view.ids.announces_scrollview.add_widget( + self.announces_view.get_widget()) self.announces_view.update() @@ -4815,8 +5409,10 @@ class SidebandApp(MDApp): self.announces_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.init_announces_view() + def o(dt): self.announces_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -4830,12 +5426,13 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = direction self.root.ids.nav_drawer.set_state("closed") - + if self.sideband.getstate("app.flags.new_announces"): self.announces_view.update() self.root.ids.screen_manager.current = "announces_screen" - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -4852,16 +5449,18 @@ class SidebandApp(MDApp): if self.root.ids.screen_manager.current == "conversations_screen": pass - ### Keys screen + # Keys screen ###################################### - + def keys_action(self, sender=None, direction="left"): if self.root.ids.screen_manager.has_screen("keys_screen"): self.keys_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.keys_init() + def o(dt): self.keys_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -4892,7 +5491,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = "left" self.root.ids.screen_manager.current = "keys_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -4901,36 +5501,45 @@ class SidebandApp(MDApp): self.open_conversations(direction="right") def identity_display_action(self, sender=None): - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) dialog = MDDialog( - text="Your Identity key, in base32 format is as follows:\n\n[b]"+str(base64.b32encode(self.sideband.identity.get_private_key()).decode("utf-8"))+"[/b]", - buttons=[ yes_button ], + text="Your Identity key, in base32 format is as follows:\n\n[b]"+str( + base64.b32encode(self.sideband.identity.get_private_key()).decode("utf-8"))+"[/b]", + buttons=[yes_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() - + yes_button.bind(on_release=dl_yes) dialog.open() def identity_copy_action(self, sender=None): - c_yes_button = MDRectangleFlatButton(text="Yes",font_size=dp(18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) - c_no_button = MDRectangleFlatButton(text="No, go back",font_size=dp(18)) - c_dialog = MDDialog(text="[b]Caution![/b]\n\nYour Identity key will be copied to the system clipboard. Take extreme care that no untrusted app steals your key by reading the clipboard data. Clear the system clipboard immediately after pasting your key where you need it.\n\nAre you sure that you wish to proceed?", buttons=[ c_no_button, c_yes_button ]) + c_yes_button = MDRectangleFlatButton(text="Yes", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) + c_no_button = MDRectangleFlatButton( + text="No, go back", font_size=dp(18)) + c_dialog = MDDialog(text="[b]Caution![/b]\n\nYour Identity key will be copied to the system clipboard. Take extreme care that no untrusted app steals your key by reading the clipboard data. Clear the system clipboard immediately after pasting your key where you need it.\n\nAre you sure that you wish to proceed?", buttons=[c_no_button, c_yes_button]) + def c_dl_no(s): c_dialog.dismiss() + def c_dl_yes(s): c_dialog.dismiss() yes_button = MDRectangleFlatButton(text="OK") - dialog = MDDialog(text="Your Identity key was copied to the system clipboard", buttons=[ yes_button ]) + dialog = MDDialog( + text="Your Identity key was copied to the system clipboard", buttons=[yes_button]) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) - Clipboard.copy(str(base64.b32encode(self.sideband.identity.get_private_key()).decode("utf-8"))) + Clipboard.copy(str(base64.b32encode( + self.sideband.identity.get_private_key()).decode("utf-8"))) dialog.open() - + c_yes_button.bind(on_release=c_dl_yes) c_no_button.bind(on_release=c_dl_no) @@ -4938,18 +5547,23 @@ class SidebandApp(MDApp): def identity_share_action(self, sender=None): if RNS.vendor.platformutils.get_platform() == "android": - self.share_text(str(base64.b32encode(self.sideband.identity.get_private_key()).decode("utf-8"))) + self.share_text(str(base64.b32encode( + self.sideband.identity.get_private_key()).decode("utf-8"))) def identity_restore_action(self, sender=None): - c_yes_button = MDRectangleFlatButton(text="Yes",font_size=dp(18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) - c_no_button = MDRectangleFlatButton(text="No, go back",font_size=dp(18)) - c_dialog = MDDialog(text="[b]Caution![/b]\n\nYou are about to import a new Identity key into Sideband. The currently active key will be irreversibly destroyed, and you will loose your LXMF address if you have not already backed up your current Identity key.\n\nAre you sure that you wish to import the key?", buttons=[ c_no_button, c_yes_button ]) + c_yes_button = MDRectangleFlatButton(text="Yes", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) + c_no_button = MDRectangleFlatButton( + text="No, go back", font_size=dp(18)) + c_dialog = MDDialog(text="[b]Caution![/b]\n\nYou are about to import a new Identity key into Sideband. The currently active key will be irreversibly destroyed, and you will loose your LXMF address if you have not already backed up your current Identity key.\n\nAre you sure that you wish to import the key?", buttons=[c_no_button, c_yes_button]) + def c_dl_no(s): c_dialog.dismiss() + def c_dl_yes(s): c_dialog.dismiss() b32_text = self.keys_screen.ids.key_restore_text.text - + try: key_bytes = base64.b32decode(b32_text) new_id = RNS.Identity.from_bytes(key_bytes) @@ -4957,8 +5571,10 @@ class SidebandApp(MDApp): if new_id != None: new_id.to_file(self.sideband.identity_path) - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) - dialog = MDDialog(text="[b]The provided Identity key data was imported[/b]\n\nThe app will now exit. Please restart Sideband to use the new Identity.", buttons=[ yes_button ]) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) + dialog = MDDialog( + text="[b]The provided Identity key data was imported[/b]\n\nThe app will now exit. Please restart Sideband to use the new Identity.", buttons=[yes_button]) + def dl_yes(s): dialog.dismiss() self.quit_action(sender=self) @@ -4966,29 +5582,32 @@ class SidebandApp(MDApp): dialog.open() except Exception as e: - yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) - dialog = MDDialog(text="[b]The provided Identity key data was not valid[/b]\n\nThe error reported by Reticulum was:\n\n[i]"+str(e)+"[/i]\n\nNo Identity was imported into Sideband.", buttons=[ yes_button ]) + yes_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) + dialog = MDDialog(text="[b]The provided Identity key data was not valid[/b]\n\nThe error reported by Reticulum was:\n\n[i]"+str( + e)+"[/i]\n\nNo Identity was imported into Sideband.", buttons=[yes_button]) + def dl_yes(s): dialog.dismiss() yes_button.bind(on_release=dl_yes) dialog.open() - - + c_yes_button.bind(on_release=c_dl_yes) c_no_button.bind(on_release=c_dl_no) c_dialog.open() - ### Plugins & Services screen + # Plugins & Services screen ###################################### - + def plugins_action(self, sender=None, direction="left"): if self.root.ids.screen_manager.has_screen("plugins_screen"): self.plugins_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.plugins_init() + def o(dt): self.plugins_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -5011,16 +5630,20 @@ class SidebandApp(MDApp): self.plugins_screen.ids.plugins_info1.text = info1 self.plugins_screen.ids.plugins_info2.text = info2 - self.plugins_screen.ids.settings_command_plugins_enabled.active = self.sideband.config["command_plugins_enabled"] - self.plugins_screen.ids.settings_service_plugins_enabled.active = self.sideband.config["service_plugins_enabled"] + self.plugins_screen.ids.settings_command_plugins_enabled.active = self.sideband.config[ + "command_plugins_enabled"] + self.plugins_screen.ids.settings_service_plugins_enabled.active = self.sideband.config[ + "service_plugins_enabled"] def plugins_settings_save(sender=None, event=None): self.sideband.config["command_plugins_enabled"] = self.plugins_screen.ids.settings_command_plugins_enabled.active self.sideband.config["service_plugins_enabled"] = self.plugins_screen.ids.settings_service_plugins_enabled.active self.sideband.save_configuration() - self.plugins_screen.ids.settings_command_plugins_enabled.bind(active=plugins_settings_save) - self.plugins_screen.ids.settings_service_plugins_enabled.bind(active=plugins_settings_save) + self.plugins_screen.ids.settings_command_plugins_enabled.bind( + active=plugins_settings_save) + self.plugins_screen.ids.settings_service_plugins_enabled.bind( + active=plugins_settings_save) def plugins_open(self, sender=None, direction="left", no_transition=False): plugins_info_text = self.sideband.get_plugins_info() @@ -5035,7 +5658,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = "left" self.root.ids.screen_manager.current = "plugins_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -5049,29 +5673,32 @@ class SidebandApp(MDApp): if os.path.isdir(path): self.sideband.config["command_plugins_path"] = path self.sideband.save_configuration() - + if RNS.vendor.platformutils.is_android(): toast("Using \""+str(path)+"\" as plugin directory") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton( + text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Directory Set", text="Using \""+str(path)+"\" as plugin directory", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() - + except Exception as e: - RNS.log(f"Error while setting plugins directory to \"{path}\": "+str(e), RNS.LOG_ERROR) + RNS.log( + f"Error while setting plugins directory to \"{path}\": "+str(e), RNS.LOG_ERROR) if RNS.vendor.platformutils.get_platform() == "android": toast("Could not set plugins directory to \""+str(path)+"\"") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) e_dialog = MDDialog( title="Error", - text="Could not set plugins directory to \""+str(path)+"\"", - buttons=[ ok_button ], + text="Could not set plugins directory to \"" + + str(path)+"\"", + buttons=[ok_button], ) ok_button.bind(on_release=e_dialog.dismiss) e_dialog.open() @@ -5084,7 +5711,7 @@ class SidebandApp(MDApp): perm_ok = False if self.sideband.config["command_plugins_path"] == None: if RNS.vendor.platformutils.is_android(): - perm_ok = self.check_storage_permission() + perm_ok = self.check_storage_permission() path = primary_external_storage_path() else: @@ -5101,49 +5728,49 @@ class SidebandApp(MDApp): exit_manager=self.plugins_fm_exited, select_path=self.plugins_fm_got_path, ) - + self.file_manager.show(path) except Exception as e: self.sideband.config["command_plugins_path"] = None self.sideband.save_configuration() - + if RNS.vendor.platformutils.is_android(): toast("Error reading directory, check permissions!") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton( + text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Error", text="Could not read directory, check permissions!", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() - + else: self.sideband.config["command_plugins_path"] = None self.sideband.save_configuration() if RNS.vendor.platformutils.is_android(): toast("No file access, check permissions!") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Error", text="No file access, check permissions!", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() - - ### Utilities Screen + # Utilities Screen ###################################### def utilities_init(self): if not self.utilities_ready: self.utilities_screen = Utilities(self) self.utilities_ready = True - + def utilities_open(self, sender=None, direction="left", no_transition=False): if no_transition: self.root.ids.screen_manager.transition = self.no_transition @@ -5153,7 +5780,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.current = "utilities_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -5163,8 +5791,10 @@ class SidebandApp(MDApp): self.utilities_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.utilities_init() + def o(dt): self.utilities_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -5173,15 +5803,14 @@ class SidebandApp(MDApp): def close_sub_utilities_action(self, sender=None): self.utilities_action(direction="right") - - ### Telemetry Screen + # Telemetry Screen ###################################### def telemetry_init(self): if not self.telemetry_ready: self.telemetry_screen = Telemetry(self) self.telemetry_ready = True - + def telemetry_open(self, sender=None, direction="left", no_transition=False): if no_transition: self.root.ids.screen_manager.transition = self.no_transition @@ -5191,7 +5820,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.current = "telemetry_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -5201,8 +5831,10 @@ class SidebandApp(MDApp): self.telemetry_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.telemetry_init() + def o(dt): self.telemetry_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -5222,14 +5854,14 @@ class SidebandApp(MDApp): self.sideband.setstate("app.flags.new_conversations", True) self.open_conversation(context_dest) - + def telemetry_send_update(self, sender=None): if not hasattr(self, "telemetry_info_dialog") or self.telemetry_info_dialog == None: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) self.telemetry_info_dialog = MDDialog( title="Info", text="", - buttons=[ ok_button ], + buttons=[ok_button], ) def dl_ok(s): @@ -5239,79 +5871,85 @@ class SidebandApp(MDApp): collector_address = self.sideband.config["telemetry_collector"] if self.sideband.config["telemetry_send_all_to_collector"]: - last_timebase = (self.sideband.getpersistent(f"telemetry.{RNS.hexrep(collector_address, delimit=False)}.last_send_success_timebase") or 0) - result = self.sideband.create_telemetry_collector_response(to_addr=collector_address, timebase=last_timebase, is_authorized_telemetry_request=True) + last_timebase = (self.sideband.getpersistent( + f"telemetry.{RNS.hexrep(collector_address, delimit=False)}.last_send_success_timebase") or 0) + result = self.sideband.create_telemetry_collector_response( + to_addr=collector_address, timebase=last_timebase, is_authorized_telemetry_request=True) else: - result = self.sideband.send_latest_telemetry(to_addr=collector_address) + result = self.sideband.send_latest_telemetry( + to_addr=collector_address) if result == "no_address": title_str = "Invalid Address" - info_str = "You must specify a valid LXMF address for the collector you want to sent data to." + info_str = "You must specify a valid LXMF address for the collector you want to sent data to." elif result == "destination_unknown": title_str = "Unknown Destination" - info_str = "No keys known for the destination. Connected reticules have been queried for the keys. Try again when an announce for the destination has arrived." + info_str = "No keys known for the destination. Connected reticules have been queried for the keys. Try again when an announce for the destination has arrived." elif result == "in_progress": title_str = "Transfer In Progress" - info_str = "There is already an outbound telemetry transfer in progress to the collector." + info_str = "There is already an outbound telemetry transfer in progress to the collector." elif result == "already_sent": title_str = "Already Delivered" - info_str = "The current telemetry data was already sent and delivered to the collector or propagation network." + info_str = "The current telemetry data was already sent and delivered to the collector or propagation network." elif result == "sent": title_str = "Update Sent" - info_str = "A telemetry update was sent to the collector." + info_str = "A telemetry update was sent to the collector." elif result == "not_sent": title_str = "Not Sent" - info_str = "The telemetry update could not be sent." + info_str = "The telemetry update could not be sent." elif result == "nothing_to_send": title_str = "Nothing to Send" - info_str = "There was no new data to send." + info_str = "There was no new data to send." else: title_str = "Unknown Status" - info_str = "The status of the telemetry update is unknown: "+str(result) + info_str = "The status of the telemetry update is unknown: " + \ + str(result) self.telemetry_info_dialog.title = title_str - self.telemetry_info_dialog.text = info_str + self.telemetry_info_dialog.text = info_str self.telemetry_info_dialog.open() def telemetry_request_action(self, sender=None): if not hasattr(self, "telemetry_info_dialog") or self.telemetry_info_dialog == None: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) self.telemetry_info_dialog = MDDialog( title="Info", text="", - buttons=[ ok_button ], + buttons=[ok_button], ) def dl_ok(s): self.telemetry_info_dialog.dismiss() ok_button.bind(on_release=dl_ok) - result = self.sideband.request_latest_telemetry(from_addr=self.sideband.config["telemetry_collector"]) + result = self.sideband.request_latest_telemetry( + from_addr=self.sideband.config["telemetry_collector"]) if result == "no_address": title_str = "Invalid Address" - info_str = "You must specify a valid LXMF address for the collector you want to request data from." + info_str = "You must specify a valid LXMF address for the collector you want to request data from." elif result == "destination_unknown": title_str = "Unknown Destination" - info_str = "No keys known for the destination. Connected reticules have been queried for the keys. Try again when an announce for the destination has arrived." + info_str = "No keys known for the destination. Connected reticules have been queried for the keys. Try again when an announce for the destination has arrived." elif result == "in_progress": title_str = "Transfer In Progress" - info_str = "There is already a telemetry request transfer in progress for this peer." + info_str = "There is already a telemetry request transfer in progress for this peer." elif result == "sent": title_str = "Request Sent" - info_str = "A telemetry request was sent to the peer. The peer should send any available telemetry shortly." + info_str = "A telemetry request was sent to the peer. The peer should send any available telemetry shortly." elif result == "not_sent": title_str = "Not Sent" - info_str = "A telemetry request could not be sent." + info_str = "A telemetry request could not be sent." else: title_str = "Unknown Status" - info_str = "The status of the telemetry request is unknown: "+str(result) + info_str = "The status of the telemetry request is unknown: " + \ + str(result) self.telemetry_info_dialog.title = title_str - self.telemetry_info_dialog.text = info_str + self.telemetry_info_dialog.text = info_str self.telemetry_info_dialog.open() - ### Map Screen + # Map Screen ###################################### def map_fm_got_path(self, path): @@ -5320,31 +5958,33 @@ class SidebandApp(MDApp): source = MBTilesMapSource(path) self.map_update_source() self.sideband.config["map_storage_file"] = path - self.sideband.config["map_storage_path"] = str(pathlib.Path(path).parent.resolve()) + self.sideband.config["map_storage_path"] = str( + pathlib.Path(path).parent.resolve()) self.sideband.save_configuration() if RNS.vendor.platformutils.is_android(): toast("Using \""+os.path.basename(path)+"\" as offline map") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Map Set", text="Using \""+os.path.basename(path)+"\" as offline map", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() 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) if RNS.vendor.platformutils.get_platform() == "android": toast("Could not load map \""+os.path.basename(path)+"\"") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) map_dialog = MDDialog( title="Map Error", text="The specified map file could not be loaded. Make sure the selected file is an MBTiles map in raster format. Vector maps are currently not supported.", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=map_dialog.dismiss) map_dialog.open() @@ -5367,8 +6007,9 @@ class SidebandApp(MDApp): if self.sideband.config["map_storage_external"]: path = secondary_external_storage_path() - if path == None: path = primary_external_storage_path() - else: + if path == None: + path = primary_external_storage_path() + else: path = primary_external_storage_path() else: @@ -5396,26 +6037,27 @@ class SidebandApp(MDApp): if RNS.vendor.platformutils.is_android(): toast("Error reading directory, check permissions!") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton( + text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Error", text="Could not read directory, check permissions!", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() - + else: self.sideband.config["map_storage_path"] = None self.sideband.save_configuration() if RNS.vendor.platformutils.is_android(): toast("No file access, check permissions!") else: - ok_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) + ok_button = MDRectangleFlatButton(text="OK", font_size=dp(18)) ate_dialog = MDDialog( title="Error", text="No file access, check permissions!", - buttons=[ ok_button ], + buttons=[ok_button], ) ok_button.bind(on_release=ate_dialog.dismiss) ate_dialog.open() @@ -5428,12 +6070,14 @@ class SidebandApp(MDApp): 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, cache_dir=self.map_cache) + source = MBTilesMapSource( + current_map_path, cache_dir=self.map_cache) self.offline_source = source return self.offline_source - + 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_use_offline"] = False self.sideband.config["map_use_online"] = True @@ -5446,34 +6090,42 @@ class SidebandApp(MDApp): source = None if self.sideband.config["map_use_offline"]: source = self.map_get_offline_source() - + if source == None: - source = MapSource.from_provider("osm", cache_dir=self.map_cache, quad_key=False) + source = MapSource.from_provider( + "osm", cache_dir=self.map_cache, quad_key=False) return source def map_update_source(self, source=None): ns = source or self.map_get_source() if self.map != None: - + if source != None: maxz = source.max_zoom minz = source.min_zoom if self.map.zoom > maxz: - mz = maxz; px, py = self.map_get_zoom_center(); self.map.set_zoom_at(mz, px, py) - + mz = maxz + px, py = self.map_get_zoom_center() + self.map.set_zoom_at(mz, px, py) + if self.map.zoom < minz: - mz = minz; px, py = self.map_get_zoom_center(); self.map.set_zoom_at(mz, px, py) + mz = minz + px, py = self.map_get_zoom_center() + self.map.set_zoom_at(mz, px, py) m = self.map 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) - + 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 @@ -5488,19 +6140,25 @@ class SidebandApp(MDApp): layers.append("osm") layers.append("ve") - if ml == None: ml = layers[0] + if ml == None: + ml = layers[0] if not ml in layers: ml = layers[0] mli = layers.index(ml) - mli = (mli+1)%len(layers) + 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", cache_dir=self.map_cache, quad_key=False) - if ml == "ve": source = MapSource.from_provider("ve", cache_dir=self.map_cache, quad_key=True) + if ml == "offline": + source = self.map_get_offline_source() + if ml == "osm": + source = MapSource.from_provider( + "osm", cache_dir=self.map_cache, quad_key=False) + if ml == "ve": + source = MapSource.from_provider( + "ve", cache_dir=self.map_cache, quad_key=True) if source != None: self.map_layer = ml @@ -5510,6 +6168,7 @@ class SidebandApp(MDApp): map_nav_divisor = 12 map_nav_zoom = 0.25 + def map_nav_left(self, sender=None, modifier=1.0): if self.map != None: bb = self.map.get_bbox() @@ -5548,8 +6207,10 @@ class SidebandApp(MDApp): 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 + 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): @@ -5571,8 +6232,10 @@ class SidebandApp(MDApp): self.map_open(sender=sender, direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.map_init() + def o(dt): self.map_open(sender=sender, no_transition=True) Clock.schedule_once(o, ll_ot) @@ -5582,25 +6245,34 @@ class SidebandApp(MDApp): if not self.root.ids.screen_manager.has_screen("map_screen"): msource = self.map_get_source() mzoom = self.sideband.config["map_zoom"] - mlat = self.sideband.config["map_lat"]; mlon = self.sideband.config["map_lon"] - if mzoom > msource.max_zoom: mzoom = msource.max_zoom - if mzoom < msource.min_zoom: mzoom = msource.min_zoom - if mlat < -89: mlat = -89 - if mlat > 89: mlat = 89 - if mlon < -179: mlon = -179 - if mlon > 179: mlon = 179 + mlat = self.sideband.config["map_lat"] + mlon = self.sideband.config["map_lon"] + if mzoom > msource.max_zoom: + mzoom = msource.max_zoom + if mzoom < msource.min_zoom: + mzoom = msource.min_zoom + if mlat < -89: + mlat = -89 + if mlat > 89: + mlat = 89 + if mlon < -179: + mlon = -179 + if mlon > 179: + mlon = 179 self.map_screen = Builder.load_string(layout_map_screen) self.map_screen.app = self self.root.ids.screen_manager.add_widget(self.map_screen) from mapview import MapView - mapview = MapView(map_source=msource, zoom=mzoom, lat=mlat, lon=mlon) + mapview = MapView(map_source=msource, + zoom=mzoom, lat=mlat, lon=mlon) mapview.snap_to_zoom = False mapview.double_tap_zoom = True self.map = mapview self.map_screen.ids.map_layout.map = mapview - self.map_screen.ids.map_layout.add_widget(self.map_screen.ids.map_layout.map) + self.map_screen.ids.map_layout.add_widget( + self.map_screen.ids.map_layout.map) def map_open(self, sender=None, direction="left", no_transition=False): if no_transition: @@ -5612,7 +6284,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.transition.direction = direction self.root.ids.screen_manager.current = "map_screen" 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) if not hasattr(self, "map_markers") or self.map_markers == None: self.map_markers = {} @@ -5626,12 +6299,16 @@ class SidebandApp(MDApp): 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"] + 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 @@ -5649,7 +6326,8 @@ class SidebandApp(MDApp): self.map_select_file_action() else: self.map_settings_screen.ids.map_use_online.active = True - map_settings_save(); self.map_update_source() + map_settings_save() + self.map_update_source() def online_toggle(sender=None, event=None): if self.map_settings_screen.ids.map_use_online.active: @@ -5657,16 +6335,19 @@ class SidebandApp(MDApp): pass else: self.map_settings_screen.ids.map_use_offline.active = True - map_settings_save(); self.map_update_source() + 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_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) + 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 = 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." @@ -5676,7 +6357,8 @@ class SidebandApp(MDApp): 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) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) def update_cache_size(dt): size = self.sideband.get_map_cache_size() @@ -5691,13 +6373,15 @@ class SidebandApp(MDApp): Clock.schedule_once(update_cache_size, 0.35) def map_clear_cache(self, sender=None): - yes_button = MDRectangleFlatButton(text="Yes",font_size=dp(18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) - no_button = MDRectangleFlatButton(text="No",font_size=dp(18)) + yes_button = MDRectangleFlatButton(text="Yes", font_size=dp( + 18), theme_text_color="Custom", line_color=self.color_reject, text_color=self.color_reject) + no_button = MDRectangleFlatButton(text="No", font_size=dp(18)) dialog = MDDialog( title="Clear map cache?", - buttons=[ yes_button, no_button ], + buttons=[yes_button, no_button], # elevation=0, ) + def dl_yes(s): dialog.dismiss() self.sideband.clear_map_cache() @@ -5727,11 +6411,13 @@ class SidebandApp(MDApp): mz = 16 lat = location["latitude"] lon = location["longitude"] - 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 + 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.zoom = mz self.map.trigger_update(True) - self.map.center_on(lat,lon) + self.map.center_on(lat, lon) self.map.trigger_update(True) else: if retry < max_tries: @@ -5760,7 +6446,8 @@ class SidebandApp(MDApp): def map_own_location_action(self, context_dest): self.sideband.update_telemetry() - location = self.sideband.peer_location(self.sideband.lxmf_destination.hash) + location = self.sideband.peer_location( + self.sideband.lxmf_destination.hash) if not location: self.location_error_dialog = MDDialog( title="No Location", @@ -5783,20 +6470,25 @@ class SidebandApp(MDApp): def map_display_own_telemetry(self, sender=None): self.sideband.update_telemetry() - self.object_details_action(source_dest=self.sideband.lxmf_destination.hash,from_telemetry=True) + self.object_details_action( + source_dest=self.sideband.lxmf_destination.hash, from_telemetry=True) def close_sub_map_action(self, sender=None): self.map_action(direction="right") def object_details_action(self, sender=None, from_conv=False, from_objects=False, from_telemetry=False, source_dest=None, direction="left"): if self.root.ids.screen_manager.has_screen("object_details_screen"): - self.object_details_open(sender=sender, from_conv=from_conv, from_objects=from_objects, from_telemetry=from_telemetry, source_dest=source_dest, direction=direction) + self.object_details_open(sender=sender, from_conv=from_conv, from_objects=from_objects, + from_telemetry=from_telemetry, source_dest=source_dest, direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.object_details_init() + def o(dt): - self.object_details_open(sender=sender, from_conv=from_conv, from_objects=from_objects, from_telemetry=from_telemetry, source_dest=source_dest, no_transition=True) + self.object_details_open(sender=sender, from_conv=from_conv, from_objects=from_objects, + from_telemetry=from_telemetry, source_dest=source_dest, no_transition=True) Clock.schedule_once(o, ll_ot) Clock.schedule_once(final, ll_ft) @@ -5830,11 +6522,13 @@ class SidebandApp(MDApp): self.conversations_action(direction="right") else: - Clock.schedule_once(lambda dt: self.object_details_screen.set_source(telemetry_source, from_conv=from_conv, from_objects=from_objects, from_telemetry=from_telemetry), 0.0) + Clock.schedule_once(lambda dt: self.object_details_screen.set_source( + telemetry_source, from_conv=from_conv, from_objects=from_objects, from_telemetry=from_telemetry), 0.0) def vj(dt): self.root.ids.screen_manager.current = "object_details_screen" - self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current) + self.sideband.setstate( + "app.displaying", self.root.ids.screen_manager.current) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition Clock.schedule_once(vj, 0.15) @@ -5843,8 +6537,10 @@ class SidebandApp(MDApp): try: l = telemetry["location"] a_icon = appearance[0] - a_fg = appearance[1]; a_bg = appearance[2] - marker = CustomMapMarker(lat=l["latitude"], lon=l["longitude"], icon_bg=a_bg) + a_fg = appearance[1] + a_bg = appearance[2] + marker = CustomMapMarker( + lat=l["latitude"], lon=l["longitude"], icon_bg=a_bg) marker.app = self marker.source_dest = source marker.location_time = l["last_update"] @@ -5853,7 +6549,7 @@ class SidebandApp(MDApp): md_bg_color=a_bg, theme_icon_color="Custom", icon_size=dp(32), on_release=self.map_display_telemetry, - ) + ) marker.icon._default_icon_pad = dp(16) marker.icon.source_dest = marker.source_dest marker.add_widget(marker.icon) @@ -5871,7 +6567,8 @@ class SidebandApp(MDApp): return marker except Exception as e: - RNS.log("Could not create map marker for "+RNS.prettyhexrep(source)+": "+str(e), RNS.LOG_ERROR) + RNS.log("Could not create map marker for " + + RNS.prettyhexrep(source)+": "+str(e), RNS.LOG_ERROR) return None def map_update_markers(self, sender=None): @@ -5907,9 +6604,10 @@ class SidebandApp(MDApp): try: if own_telemetry != None and "location" in own_telemetry and own_telemetry["location"] != None and own_telemetry["location"]["latitude"] != None and own_telemetry["location"]["longitude"] != None: retain_own = True - + if not own_address in self.map_markers: - marker = self.map_create_marker(own_address, own_telemetry, own_appearance) + marker = self.map_create_marker( + own_address, own_telemetry, own_appearance) if marker != None: self.map_markers[own_address] = marker self.map_screen.ids.map_layout.map.add_marker(marker) @@ -5945,10 +6643,12 @@ class SidebandApp(MDApp): self.map_markers.pop(marker) changes = True except Exception as e: - RNS.log("Error while removing map marker: "+str(e), RNS.LOG_ERROR) - + RNS.log("Error while removing map marker: " + + str(e), RNS.LOG_ERROR) + except Exception as e: - RNS.log("Error while updating own map marker: "+str(e), RNS.LOG_ERROR) + RNS.log("Error while updating own map marker: " + + str(e), RNS.LOG_ERROR) for telemetry_source in telemetry_entries: try: @@ -5976,30 +6676,34 @@ class SidebandApp(MDApp): if latest_viewable != None: l = latest_viewable["location"] if not telemetry_source in self.map_markers: - marker = self.map_create_marker(telemetry_source, latest_viewable, self.sideband.peer_appearance(telemetry_source)) + marker = self.map_create_marker( + telemetry_source, latest_viewable, self.sideband.peer_appearance(telemetry_source)) if marker != None: self.map_markers[telemetry_source] = marker - self.map_screen.ids.map_layout.map.add_marker(marker) + self.map_screen.ids.map_layout.map.add_marker( + marker) changes = True else: marker = self.map_markers[telemetry_source] marker.location_time = latest_viewable["time"]["utc"] marker.lat = l["latitude"] marker.lon = l["longitude"] - appearance = self.sideband.peer_appearance(telemetry_source) + appearance = self.sideband.peer_appearance( + telemetry_source) marker.icon.icon = appearance[0] marker.icon.icon_color = appearance[1] marker.icon.md_bg_color = appearance[2] changes = True except Exception as e: - RNS.log("Error while updating map entry for "+RNS.prettyhexrep(telemetry_source)+": "+str(e), RNS.LOG_ERROR) + RNS.log("Error while updating map entry for " + + RNS.prettyhexrep(telemetry_source)+": "+str(e), RNS.LOG_ERROR) self.last_map_update = time.time() if changes: self.map.trigger_update(True) - ### Guide screen + # Guide screen ###################################### def close_guide_action(self, sender=None): self.open_conversations(direction="right") @@ -6013,7 +6717,8 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.current = "guide_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -6023,8 +6728,10 @@ class SidebandApp(MDApp): self.guide_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.guide_init() + def o(dt): self.guide_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -6049,13 +6756,13 @@ This short guide will give you a basic introduction to the concepts that underpi [size=18dp][b]Communication Without Subjection[/b][/size][size=5dp]\n \n[/size]Sideband is completely free, permission-less, anonymous and infrastructure-less. Sideband uses the peer-to-peer and distributed messaging system LXMF. There is no sign-up, no service providers, no "end-user license agreements", no data theft and no surveillance. You own the system. This also means that Sideband operates differently than what you might be used to. It does not need a connection to a server on the Internet to function, and you do not have an account anywhere.""" - + guide_text3 = """ [size=18dp][b]Operating Principles[/b][/size][size=5dp]\n \n[/size]When Sideband is started on your device for the first time, it randomly generates a 512-bit Reticulum Identity Key. This cryptographic key is then used to create an LXMF address for your use, and in turn to secure any communication to your address. Any other endpoint in [i]any[/i] Reticulum network will be able to send data to your address, as long as there is [i]some sort of physical connection[/i] between your device and the remote endpoint. You can also move around to other Reticulum networks with this address, even ones that were never connected to the network the address was created on, or that didn't exist when the address was created.\n\nYour LXMF address is yours to keep and control for as long (or short) a time you need it, and you can always delete it and create a new one. You identity keys and corresponding addresses are never registered on or controlled by any external servers or services, and will never leave your device, unless you manually export them for backup.""" - + guide_text10 = """ [size=18dp][b]Getting Connected[/b][/size][size=5dp]\n \n[/size]If you already have Reticulum connectivity set up on the device you are running Sideband on, no further configuration should be necessary, and Sideband will simply use the available Reticulum connectivity.\n\nIf you are running Sideband on a computer, you can configure interfaces in the Reticulum configuration file ([b]~/.reticulum/config[/b] by default). If you are running Sideband on an Android device, you can configure various interface types in the [b]Connectivity[/b] section. By default, only an [i]AutoInterface[/i] is enabled, which will connect you automatically with any other local devices on the same WiFi and/or Ethernet networks. This may or may not include Reticulum Transport Nodes, which can route your traffic to wider networks.\n\nYou can enable any or all of the other available interface types to gain wider connectivity. For more specific information on interface types, configuration options, and how to effectively build your own Reticulum networks, see the [b]Reticulum Manual[b].""" - + guide_text4 = """ [size=18dp][b]Becoming Reachable[/b][/size][size=5dp]\n \n[/size]To establish reachability for any Reticulum destination on a network, an [i]announce[/i] must be sent. By default, Sideband will announce automatically when necessary, but if you want to stay silent, automatic announces can be disabled in [b]Preferences[/b].\n\nTo send an announce manually, press the [i]Announce[/i] button in the [i]Conversations[/i] section of the program. When you send an announce, you make your LXMF address reachable for real-time messaging to the entire network you are connected to. Even in very large networks, you can expect global reachability for your address to be established in under a minute. @@ -6073,7 +6780,7 @@ The Propagation Nodes also distribute copies of messages between each other, suc [size=18dp][b]Be Yourself, Be Unknown, Stay Free[/b][/size][size=5dp]\n \n[/size]Even with the above characteristics in mind, you [b]must remember[/b] that LXMF and Reticulum is not a technology that can guarantee anonymising connections that are already de-anonymised! If you use Sideband to connect to TCP Reticulum hubs over the clear Internet, from a network that can be tied to your personal identity, an adversary may learn that you are generating LXMF traffic.\n\nIf you want to avoid this, it is recommended to use I2P to connect to Reticulum hubs on the Internet. Or only connecting from within pure Reticulum networks, that take one or more hops to reach connections that span the Internet. This is a complex topic, with many more nuances than can be covered here. You are encouraged to ask on the various Reticulum discussion forums if you are in doubt. If you use Reticulum and LXMF on hardware that does not carry any identifiers tied to you, it is possible to establish a completely free and identification-less communication system with Reticulum and LXMF clients.""" - + guide_text8 = """ [size=18dp][b]Keyboard Shortcuts[/b][/size][size=5dp]\n \n[/size]To ease navigation and operation of the program, Sideband has keyboard shortcuts mapped to the most common actions. A reference is included below. @@ -6156,17 +6863,19 @@ Thank you very much for using Free Communications Systems. self.guide_screen.ids.guide_info9.bind(on_ref_press=link_exec) self.guide_screen.ids.guide_scrollview.effect_cls = ScrollEffect - ################################################# # Unimplemented Screens # ################################################# + def broadcasts_action(self, sender=None, direction="left"): if self.root.ids.screen_manager.has_screen("broadcasts_screen"): self.broadcasts_open(direction=direction) else: self.loader_action(direction=direction) + def final(dt): self.broadcasts_init() + def o(dt): self.broadcasts_open(no_transition=True) Clock.schedule_once(o, ll_ot) @@ -6186,7 +6895,8 @@ Thank you very much for using Free Communications Systems. self.root.ids.screen_manager.current = "broadcasts_screen" 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) if no_transition: self.root.ids.screen_manager.transition = self.slide_transition @@ -6198,40 +6908,51 @@ Thank you very much for using Free Communications Systems. webbrowser.open("https://unsigned.io/donate") threading.Thread(target=lj, daemon=True).start() - self.broadcasts_screen = Builder.load_string(layout_broadcasts_screen) + self.broadcasts_screen = Builder.load_string( + layout_broadcasts_screen) self.broadcasts_screen.app = self self.root.ids.screen_manager.add_widget(self.broadcasts_screen) self.broadcasts_screen.ids.broadcasts_scrollview.effect_cls = ScrollEffect - self.broadcasts_screen.ids.broadcasts_info.bind(on_ref_press=link_exec) + self.broadcasts_screen.ids.broadcasts_info.bind( + on_ref_press=link_exec) + class CustomOneLineIconListItem(OneLineIconListItem): icon = StringProperty() + class DialogItem(OneLineIconListItem): divider = None icon = StringProperty() + class MDMapIconButton(MDIconButton): pass + class UIScaling(BoxLayout): pass + if not args.daemon: from kivy.base import ExceptionManager, ExceptionHandler + class SidebandExceptionHandler(ExceptionHandler): def handle_exception(self, e): etype = type(e) if etype != SystemExit: import traceback - exception_info = "".join(traceback.TracebackException.from_exception(e).format()) - RNS.log(f"An unhandled {str(type(e))} exception occurred: {str(e)}", RNS.LOG_ERROR) + exception_info = "".join( + traceback.TracebackException.from_exception(e).format()) + RNS.log( + f"An unhandled {str(type(e))} exception occurred: {str(e)}", RNS.LOG_ERROR) RNS.log(exception_info, RNS.LOG_ERROR) return ExceptionManager.PASS else: return ExceptionManager.RAISE + def run(): if args.daemon: RNS.log("Starting Sideband in daemon mode") @@ -6251,8 +6972,9 @@ def run(): ExceptionManager.add_handler(SidebandExceptionHandler()) SidebandApp().run() + if __name__ == "__main__": run() if __name__ == "sbapp.main": - run() \ No newline at end of file + run()