Added service split for Android and notifications on Android and Linux
This commit is contained in:
parent
e58c8a96be
commit
7ee0171ec7
102
sbapp/main.py
102
sbapp/main.py
|
@ -72,8 +72,6 @@ class SidebandApp(MDApp):
|
|||
self.android_service = None
|
||||
|
||||
self.app_dir = plyer.storagepath.get_application_dir()
|
||||
# TODO: Remove
|
||||
RNS.log("Application directory is: "+str(self.app_dir))
|
||||
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
self.sideband = SidebandCore(self, is_client=True, android_app_dir=self.app_dir)
|
||||
|
@ -82,20 +80,16 @@ class SidebandApp(MDApp):
|
|||
|
||||
self.conversations_view = None
|
||||
|
||||
self.flag_new_conversations = False
|
||||
self.flag_unread_conversations = False
|
||||
self.flag_new_announces = False
|
||||
self.lxmf_sync_dialog_open = False
|
||||
self.sync_dialog = None
|
||||
|
||||
Window.softinput_mode = "below_target"
|
||||
self.icon = self.sideband.asset_dir+"/icon.png"
|
||||
self.notification_icon = self.sideband.asset_dir+"/notification_icon.png"
|
||||
self.check_permissions()
|
||||
|
||||
def start_core(self, dt):
|
||||
self.start_service()
|
||||
|
||||
self.open_conversations()
|
||||
Clock.schedule_interval(self.jobs, 1)
|
||||
|
||||
def dismiss_splash(dt):
|
||||
|
@ -105,8 +99,15 @@ class SidebandApp(MDApp):
|
|||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
Clock.schedule_once(dismiss_splash, 0)
|
||||
|
||||
if self.sideband.first_run:
|
||||
self.guide_action()
|
||||
self.sideband.setstate("app.loaded", True)
|
||||
self.sideband.setstate("app.running", True)
|
||||
self.sideband.setstate("app.foreground", True)
|
||||
|
||||
if self.sideband.first_run:
|
||||
self.guide_action()
|
||||
self.request_notifications_permission()
|
||||
else:
|
||||
self.open_conversations()
|
||||
|
||||
self.app_state = SidebandApp.ACTIVE
|
||||
|
||||
|
@ -125,8 +126,6 @@ class SidebandApp(MDApp):
|
|||
time.sleep(7)
|
||||
|
||||
# Start local core instance
|
||||
# TODO: Remove log
|
||||
RNS.log("Starting local core")
|
||||
self.sideband.start()
|
||||
|
||||
else:
|
||||
|
@ -150,14 +149,20 @@ class SidebandApp(MDApp):
|
|||
mActivity.startActivity(shareIntent)
|
||||
|
||||
def on_pause(self):
|
||||
self.sideband.setstate("app.running", True)
|
||||
self.sideband.setstate("app.foreground", False)
|
||||
self.app_state = SidebandApp.PAUSED
|
||||
self.sideband.should_persist_data()
|
||||
return True
|
||||
|
||||
def on_resume(self):
|
||||
self.sideband.setstate("app.running", True)
|
||||
self.sideband.setstate("app.foreground", True)
|
||||
self.app_state = SidebandApp.ACTIVE
|
||||
|
||||
def on_stop(self):
|
||||
self.sideband.setstate("app.running", False)
|
||||
self.sideband.setstate("app.foreground", False)
|
||||
self.app_state = SidebandApp.STOPPING
|
||||
|
||||
def is_in_foreground(self):
|
||||
|
@ -166,25 +171,27 @@ class SidebandApp(MDApp):
|
|||
else:
|
||||
return False
|
||||
|
||||
def notify(self, title, content):
|
||||
notifications_enabled = True
|
||||
|
||||
if notifications_enabled:
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
notifications_permitted = False
|
||||
if check_permission("android.permission.POST_NOTIFICATIONS"):
|
||||
notifications_permitted = True
|
||||
else:
|
||||
RNS.log("Requesting notification permission")
|
||||
request_permissions(["android.permission.POST_NOTIFICATIONS"])
|
||||
def check_permissions(self):
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
if check_permission("android.permission.POST_NOTIFICATIONS"):
|
||||
RNS.log("Have notification permissions")
|
||||
self.sideband.setpersistent("permissions.notifications", True)
|
||||
else:
|
||||
notifications_permitted = True
|
||||
RNS.log("Do not have notification permissions")
|
||||
self.sideband.setpersistent("permissions.notifications", False)
|
||||
else:
|
||||
self.sideband.setpersistent("permissions.notifications", True)
|
||||
|
||||
if notifications_permitted:
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
plyer.notification.notify(title, content, notification_icon=self.notification_icon)
|
||||
else:
|
||||
plyer.notification.notify(title, content)
|
||||
def request_permissions(self):
|
||||
self.request_notifications_permission()
|
||||
|
||||
def request_notifications_permission(self):
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
if not check_permission("android.permission.POST_NOTIFICATIONS"):
|
||||
RNS.log("Requesting notification permission")
|
||||
request_permissions(["android.permission.POST_NOTIFICATIONS"])
|
||||
|
||||
self.check_permissions()
|
||||
|
||||
def build(self):
|
||||
FONT_PATH = self.sideband.asset_dir+"/fonts"
|
||||
|
@ -201,22 +208,22 @@ class SidebandApp(MDApp):
|
|||
self.message_area_detect()
|
||||
|
||||
elif self.root.ids.screen_manager.current == "conversations_screen":
|
||||
if self.flag_new_conversations:
|
||||
if self.sideband.getstate("app.flags.new_conversations"):
|
||||
RNS.log("Updating because of new conversations flag")
|
||||
if self.conversations_view != None:
|
||||
self.conversations_view.update()
|
||||
|
||||
if self.flag_unread_conversations:
|
||||
if self.sideband.getstate("app.flags.unread_conversations"):
|
||||
RNS.log("Updating because of unread messages flag")
|
||||
if self.conversations_view != None:
|
||||
self.conversations_view.update()
|
||||
|
||||
if self.lxmf_sync_dialog_open and self.sync_dialog != None:
|
||||
if self.sideband.getstate("app.flags.lxmf_sync_dialog_open") and self.sync_dialog != None:
|
||||
self.sync_dialog.ids.sync_progress.value = self.sideband.get_sync_progress()*100
|
||||
self.sync_dialog.ids.sync_status.text = self.sideband.get_sync_status()
|
||||
|
||||
elif self.root.ids.screen_manager.current == "announces_screen":
|
||||
if self.flag_new_announces:
|
||||
if self.sideband.getstate("app.flags.new_announces"):
|
||||
RNS.log("Updating because of new announces flag")
|
||||
if self.announces_view != None:
|
||||
self.announces_view.update()
|
||||
|
@ -304,6 +311,9 @@ class SidebandApp(MDApp):
|
|||
self.root.ids.nav_drawer.set_state("closed")
|
||||
self.sideband.should_persist_data()
|
||||
|
||||
self.sideband.setstate("app.running", False)
|
||||
self.sideband.setstate("app.foreground", False)
|
||||
|
||||
def final_exit(dt):
|
||||
RNS.exit()
|
||||
MDApp.get_running_app().stop()
|
||||
|
@ -328,13 +338,6 @@ class SidebandApp(MDApp):
|
|||
yes_button.bind(on_release=dl_yes)
|
||||
dialog.open()
|
||||
|
||||
def conversation_update(self, context_dest):
|
||||
pass
|
||||
# if self.root.ids.messages_scrollview.active_conversation == context_dest:
|
||||
# self.messages_view.update_widget()
|
||||
# else:
|
||||
# RNS.log("Not updating since context_dest does not match active")
|
||||
|
||||
|
||||
#################################################
|
||||
# Screens #
|
||||
|
@ -372,12 +375,14 @@ class SidebandApp(MDApp):
|
|||
self.root.ids.messages_scrollview.scroll_y = 0
|
||||
self.root.ids.messages_toolbar.title = self.sideband.peer_display_name(context_dest)
|
||||
self.root.ids.messages_scrollview.active_conversation = context_dest
|
||||
self.sideband.setstate("app.active_conversation", context_dest)
|
||||
|
||||
self.root.ids.nokeys_text.text = ""
|
||||
self.message_area_detect()
|
||||
self.update_message_widgets()
|
||||
|
||||
self.root.ids.screen_manager.current = "messages_screen"
|
||||
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
||||
|
||||
self.sideband.read_conversation(context_dest)
|
||||
|
||||
|
@ -480,6 +485,7 @@ class SidebandApp(MDApp):
|
|||
|
||||
self.root.ids.screen_manager.current = "conversations_screen"
|
||||
self.root.ids.messages_scrollview.active_conversation = None
|
||||
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
||||
|
||||
def connectivity_status(self, sender):
|
||||
hs = dp(22)
|
||||
|
@ -567,18 +573,12 @@ class SidebandApp(MDApp):
|
|||
)
|
||||
dialog.d_content = dialog_content
|
||||
def dl_close(s):
|
||||
self.lxmf_sync_dialog_open = False
|
||||
self.sideband.setstate("app.flags.lxmf_sync_dialog_open", False)
|
||||
dialog.dismiss()
|
||||
self.sideband.cancel_lxmf_sync()
|
||||
|
||||
# def dl_stop(s):
|
||||
# self.lxmf_sync_dialog_open = False
|
||||
# dialog.dismiss()
|
||||
# self.sideband.cancel_lxmf_sync()
|
||||
|
||||
close_button.bind(on_release=dl_close)
|
||||
# stop_button.bind(on_release=dl_stop)
|
||||
self.lxmf_sync_dialog_open = True
|
||||
self.sideband.setstate("app.flags.lxmf_sync_dialog_open", True)
|
||||
self.sync_dialog = dialog_content
|
||||
dialog.open()
|
||||
dialog_content.ids.sync_progress.value = self.sideband.get_sync_progress()*100
|
||||
|
@ -652,6 +652,7 @@ 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)
|
||||
|
||||
def close_information_action(self, sender=None):
|
||||
self.open_conversations(direction="right")
|
||||
|
@ -743,6 +744,7 @@ class SidebandApp(MDApp):
|
|||
|
||||
self.root.ids.screen_manager.current = "settings_screen"
|
||||
self.root.ids.nav_drawer.set_state("closed")
|
||||
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
||||
|
||||
def close_settings_action(self, sender=None):
|
||||
self.open_conversations(direction="right")
|
||||
|
@ -852,6 +854,7 @@ class SidebandApp(MDApp):
|
|||
self.root.ids.screen_manager.transition.direction = "left"
|
||||
self.root.ids.screen_manager.current = "connectivity_screen"
|
||||
self.root.ids.nav_drawer.set_state("closed")
|
||||
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
||||
|
||||
|
||||
def close_connectivity_action(self, sender=None):
|
||||
|
@ -875,6 +878,7 @@ class SidebandApp(MDApp):
|
|||
self.root.ids.announces_scrollview.add_widget(self.announces_view.get_widget())
|
||||
|
||||
self.root.ids.screen_manager.current = "announces_screen"
|
||||
self.sideband.setstate("app.displaying", self.root.ids.screen_manager.current)
|
||||
|
||||
def close_announces_action(self, sender=None):
|
||||
self.open_conversations(direction="right")
|
||||
|
@ -900,6 +904,7 @@ 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)
|
||||
|
||||
def close_keys_action(self, sender=None):
|
||||
self.open_conversations(direction="right")
|
||||
|
@ -1031,6 +1036,7 @@ Thank you very much for using Free Communications Systems.
|
|||
self.root.ids.screen_manager.transition.direction = "left"
|
||||
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)
|
||||
|
||||
|
||||
#################################################
|
||||
|
@ -1049,6 +1055,7 @@ Thank you very much for using Free Communications Systems.
|
|||
self.root.ids.screen_manager.transition.direction = "left"
|
||||
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)
|
||||
|
||||
def broadcasts_action(self, sender=None):
|
||||
def link_exec(sender=None, event=None):
|
||||
|
@ -1062,6 +1069,7 @@ Thank you very much for using Free Communications Systems.
|
|||
self.root.ids.screen_manager.transition.direction = "left"
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -130,20 +130,22 @@ public class PythonService extends Service implements Runnable {
|
|||
} else {
|
||||
// for android 8+ we need to create our own channel
|
||||
// https://stackoverflow.com/questions/47531742/startforeground-fail-after-upgrade-to-android-8-1
|
||||
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a"; //TODO: make this configurable
|
||||
String channelName = "Background Service"; //TODO: make this configurable
|
||||
String NOTIFICATION_CHANNEL_ID = "io.unsigned.sideband.reticulum";
|
||||
String channelName = "Background Service";
|
||||
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,
|
||||
NotificationManager.IMPORTANCE_NONE);
|
||||
|
||||
chan.setLightColor(Color.BLUE);
|
||||
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||
chan.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||
chan.setShowBadge(false);
|
||||
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
manager.createNotificationChannel(chan);
|
||||
|
||||
Notification.Builder builder = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID);
|
||||
builder.setContentTitle("Sideband");
|
||||
builder.setContentText("Reticulum Running");
|
||||
builder.setContentTitle("Sideband Active");
|
||||
// builder.setContentText("Reticulum Active");
|
||||
builder.setContentIntent(pIntent);
|
||||
// builder.setOngoing(true);
|
||||
|
||||
// TODO: Generalise this
|
||||
Bitmap icon_bitmap = BitmapFactory.decodeFile("/data/user/0/io.unsigned.sideband/files/app/assets/notification_icon.png");
|
||||
|
|
|
@ -46,7 +46,7 @@ class Notification:
|
|||
'''
|
||||
|
||||
def notify(self, title='', message='', app_name='', app_icon='', notification_icon=None,
|
||||
timeout=10, ticker='', toast=False, hints={}):
|
||||
timeout=10, ticker='', toast=False, hints={}, context_override=None):
|
||||
'''
|
||||
Send a notification.
|
||||
|
||||
|
@ -84,7 +84,7 @@ class Notification:
|
|||
self._notify(
|
||||
title=title, message=message,
|
||||
app_icon=app_icon, app_name=app_name, notification_icon=notification_icon,
|
||||
timeout=timeout, ticker=ticker, toast=toast, hints=hints
|
||||
timeout=timeout, ticker=ticker, toast=toast, hints=hints, context_override=context_override
|
||||
)
|
||||
|
||||
# private
|
||||
|
|
|
@ -180,6 +180,7 @@ class AndroidNotification(Notification):
|
|||
)
|
||||
icon = kwargs.get('app_icon')
|
||||
notification_icon = kwargs.get('notification_icon')
|
||||
context_override = kwargs.get('context_override')
|
||||
|
||||
# decide whether toast only or proper notification
|
||||
if kwargs.get('toast'):
|
||||
|
|
|
@ -9,7 +9,18 @@ Logger.setLevel(LOG_LEVELS["debug"])
|
|||
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
from jnius import autoclass, cast
|
||||
from android import python_act
|
||||
Context = autoclass('android.content.Context')
|
||||
Intent = autoclass('android.content.Intent')
|
||||
BitmapFactory = autoclass('android.graphics.BitmapFactory')
|
||||
Icon = autoclass("android.graphics.drawable.Icon")
|
||||
PendingIntent = autoclass('android.app.PendingIntent')
|
||||
AndroidString = autoclass('java.lang.String')
|
||||
NotificationManager = autoclass('android.app.NotificationManager')
|
||||
Context = autoclass('android.content.Context')
|
||||
NotificationBuilder = autoclass('android.app.Notification$Builder')
|
||||
NotificationChannel = autoclass('android.app.NotificationChannel')
|
||||
|
||||
from sideband.core import SidebandCore
|
||||
|
||||
else:
|
||||
|
@ -20,6 +31,64 @@ class AppProxy():
|
|||
pass
|
||||
|
||||
class SidebandService():
|
||||
def android_notification(self, title="", content="", ticker="", group=None, context_id=None):
|
||||
package_name = "io.unsigned.sideband"
|
||||
|
||||
if not self.notification_service:
|
||||
self.notification_service = cast(NotificationManager, self.app_context.getSystemService(
|
||||
Context.NOTIFICATION_SERVICE
|
||||
))
|
||||
|
||||
channel_id = package_name
|
||||
group_id = ""
|
||||
if group != None:
|
||||
channel_id += "."+str(group)
|
||||
group_id += str(group)
|
||||
if context_id != None:
|
||||
channel_id += "."+str(context_id)
|
||||
group_id += "."+str(context_id)
|
||||
|
||||
if not title or title == "":
|
||||
channel_name = "Sideband"
|
||||
else:
|
||||
channel_name = title
|
||||
|
||||
self.notification_channel = NotificationChannel(channel_id, channel_name, NotificationManager.IMPORTANCE_DEFAULT)
|
||||
self.notification_channel.enableVibration(True)
|
||||
self.notification_channel.setShowBadge(True)
|
||||
self.notification_service.createNotificationChannel(self.notification_channel)
|
||||
|
||||
notification = NotificationBuilder(self.app_context, channel_id)
|
||||
notification.setContentTitle(title)
|
||||
notification.setContentText(AndroidString(content))
|
||||
|
||||
# if group != None:
|
||||
# notification.setGroup(group_id)
|
||||
|
||||
if not self.notification_small_icon:
|
||||
path = self.sideband.notification_icon
|
||||
bitmap = BitmapFactory.decodeFile(path)
|
||||
self.notification_small_icon = Icon.createWithBitmap(bitmap)
|
||||
|
||||
notification.setSmallIcon(self.notification_small_icon)
|
||||
|
||||
# large_icon_path = self.sideband.icon
|
||||
# bitmap_icon = BitmapFactory.decodeFile(large_icon_path)
|
||||
# notification.setLargeIcon(bitmap_icon)
|
||||
|
||||
if not self.notification_intent:
|
||||
notification_intent = Intent(self.app_context, python_act)
|
||||
notification_intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
notification_intent.setAction(Intent.ACTION_MAIN)
|
||||
notification_intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
|
||||
self.notification_intent = PendingIntent.getActivity(self.app_context, 0, notification_intent, 0)
|
||||
|
||||
notification.setContentIntent(self.notification_intent)
|
||||
notification.setAutoCancel(True)
|
||||
|
||||
built_notification = notification.build()
|
||||
self.notification_service.notify(0, built_notification)
|
||||
|
||||
def __init__(self):
|
||||
self.argument = environ.get('PYTHON_SERVICE_ARGUMENT', '')
|
||||
|
@ -34,15 +103,20 @@ class SidebandService():
|
|||
self.app_context = None
|
||||
self.wifi_manager = None
|
||||
|
||||
self.notification_service = None
|
||||
self.notification_channel = None
|
||||
self.notification_intent = None
|
||||
self.notification_small_icon = None
|
||||
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
self.android_service = autoclass('org.kivy.android.PythonService').mService
|
||||
self.app_context = self.android_service.getApplication().getApplicationContext()
|
||||
self.wifi_manager = self.app_context.getSystemService(Context.WIFI_SERVICE)
|
||||
# The returned instance is an android.net.wifi.WifiManager
|
||||
# The returned instance /\ is an android.net.wifi.WifiManager
|
||||
|
||||
# TODO: Remove?
|
||||
RNS.log("Sideband background service created, starting core...", RNS.LOG_DEBUG)
|
||||
self.sideband = SidebandCore(self.app_proxy, is_service=True, android_app_dir=self.app_dir)
|
||||
self.sideband.service_context = self.android_service
|
||||
self.sideband.owner_service = self
|
||||
self.sideband.start()
|
||||
|
||||
def start(self):
|
||||
|
@ -77,7 +151,3 @@ class SidebandService():
|
|||
|
||||
sbs = SidebandService()
|
||||
sbs.start()
|
||||
|
||||
# TODO: Remove
|
||||
print("SBS: Service thread done")
|
||||
RNS.log("Service thread done")
|
|
@ -8,6 +8,9 @@ import sqlite3
|
|||
|
||||
import RNS.vendor.umsgpack as msgpack
|
||||
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
from jnius import autoclass, cast
|
||||
|
||||
class PropagationNodeDetector():
|
||||
EMITTED_DELTA_GRACE = 300
|
||||
EMITTED_DELTA_IGNORE = 10
|
||||
|
@ -60,6 +63,8 @@ class SidebandCore():
|
|||
|
||||
MAX_ANNOUNCES = 48
|
||||
|
||||
JOB_INTERVAL = 1
|
||||
|
||||
aspect_filter = "lxmf.delivery"
|
||||
def received_announce(self, destination_hash, announced_identity, app_data):
|
||||
# Add the announce to the directory announce
|
||||
|
@ -75,12 +80,6 @@ class SidebandCore():
|
|||
else:
|
||||
self.is_standalone = False
|
||||
|
||||
if self.is_client:
|
||||
from .serviceproxy import ServiceProxy
|
||||
self.serviceproxy = ServiceProxy(self)
|
||||
else:
|
||||
self.serviceproxy = None
|
||||
|
||||
self.owner_app = owner_app
|
||||
self.reticulum = None
|
||||
|
||||
|
@ -90,11 +89,18 @@ class SidebandCore():
|
|||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
self.app_dir = android_app_dir+"/io.unsigned.sideband/files/"
|
||||
self.rns_configdir = self.app_dir+"/app_storage/reticulum"
|
||||
self.asset_dir = self.app_dir+"/app/assets"
|
||||
else:
|
||||
self.asset_dir = plyer.storagepath.get_application_dir()+"/sbapp/assets"
|
||||
|
||||
self.icon = self.asset_dir+"/icon.png"
|
||||
self.icon_48 = self.asset_dir+"/icon_48.png"
|
||||
self.icon_32 = self.asset_dir+"/icon_32.png"
|
||||
self.notification_icon = self.asset_dir+"/notification_icon.png"
|
||||
|
||||
if not os.path.isdir(self.app_dir+"/app_storage"):
|
||||
os.makedirs(self.app_dir+"/app_storage")
|
||||
|
||||
self.asset_dir = self.app_dir+"/app/assets"
|
||||
self.config_path = self.app_dir+"/app_storage/sideband_config"
|
||||
self.identity_path = self.app_dir+"/app_storage/primary_identity"
|
||||
self.db_path = self.app_dir+"/app_storage/sideband.db"
|
||||
|
@ -195,6 +201,9 @@ class SidebandCore():
|
|||
|
||||
if not os.path.isfile(self.db_path):
|
||||
self.__db_init()
|
||||
else:
|
||||
self._db_initstate()
|
||||
self._db_initpersistent()
|
||||
|
||||
|
||||
def __save_config(self):
|
||||
|
@ -222,11 +231,32 @@ class SidebandCore():
|
|||
RNS.log("Error while setting LXMF propagation node: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
|
||||
def notify(self, title, content, group=None, context_id=None):
|
||||
notifications_enabled = True
|
||||
|
||||
if notifications_enabled:
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
if self.getpersistent("permissions.notifications"):
|
||||
notifications_permitted = True
|
||||
else:
|
||||
notifications_permitted = False
|
||||
else:
|
||||
notifications_permitted = True
|
||||
|
||||
if notifications_permitted:
|
||||
if RNS.vendor.platformutils.get_platform() == "android":
|
||||
if self.is_service:
|
||||
self.owner_service.android_notification(title, content, group=group, context_id=context_id)
|
||||
else:
|
||||
plyer.notification.notify(title, content, notification_icon=self.notification_icon, context_override=None)
|
||||
else:
|
||||
plyer.notification.notify(title, content, app_icon=self.icon_32)
|
||||
|
||||
def log_announce(self, dest, app_data, dest_type):
|
||||
try:
|
||||
RNS.log("Received "+str(dest_type)+" announce for "+RNS.prettyhexrep(dest)+" with data: "+app_data.decode("utf-8"))
|
||||
self._db_save_announce(dest, app_data, dest_type)
|
||||
self.owner_app.flag_new_announces = True
|
||||
self.setstate("app.flags.new_announces", True)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Exception while decoding LXMF destination announce data:"+str(e))
|
||||
|
@ -345,6 +375,27 @@ class SidebandCore():
|
|||
else:
|
||||
return []
|
||||
|
||||
def gui_foreground(self):
|
||||
return self._db_getstate("app.foreground")
|
||||
|
||||
def gui_display(self):
|
||||
return self._db_getstate("app.displaying")
|
||||
|
||||
def gui_conversation(self):
|
||||
return self._db_getstate("app.active_conversation")
|
||||
|
||||
def setstate(self, prop, val):
|
||||
self._db_setstate(prop, val)
|
||||
|
||||
def getstate(self, prop):
|
||||
return self._db_getstate(prop)
|
||||
|
||||
def setpersistent(self, prop, val):
|
||||
self._db_setpersistent(prop, val)
|
||||
|
||||
def getpersistent(self, prop):
|
||||
return self._db_getpersistent(prop)
|
||||
|
||||
def __event_conversations_changed(self):
|
||||
pass
|
||||
|
||||
|
@ -364,6 +415,100 @@ class SidebandCore():
|
|||
dbc.execute("DROP TABLE IF EXISTS announce")
|
||||
dbc.execute("CREATE TABLE announce (id PRIMARY KEY, received INTEGER, source BLOB, data BLOB, dest_type BLOB)")
|
||||
|
||||
dbc.execute("DROP TABLE IF EXISTS state")
|
||||
dbc.execute("CREATE TABLE state (property BLOB PRIMARY KEY, value BLOB)")
|
||||
|
||||
dbc.execute("DROP TABLE IF EXISTS persistent")
|
||||
dbc.execute("CREATE TABLE persistent (property BLOB PRIMARY KEY, value BLOB)")
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
def _db_initstate(self):
|
||||
db = sqlite3.connect(self.db_path)
|
||||
dbc = db.cursor()
|
||||
|
||||
dbc.execute("DROP TABLE IF EXISTS state")
|
||||
dbc.execute("CREATE TABLE state (property BLOB PRIMARY KEY, value BLOB)")
|
||||
self._db_setstate("database_ready", True)
|
||||
|
||||
def _db_getstate(self, prop):
|
||||
db = sqlite3.connect(self.db_path)
|
||||
dbc = db.cursor()
|
||||
|
||||
query = "select * from state where property=:uprop"
|
||||
dbc.execute(query, {"uprop": prop.encode("utf-8")})
|
||||
result = dbc.fetchall()
|
||||
db.close()
|
||||
|
||||
if len(result) < 1:
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
entry = result[0]
|
||||
val = msgpack.unpackb(entry[1])
|
||||
return val
|
||||
except Exception as e:
|
||||
RNS.log("Could not unpack state value from database for property \""+str(prop)+"\". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
return None
|
||||
|
||||
def _db_setstate(self, prop, val):
|
||||
db = sqlite3.connect(self.db_path)
|
||||
dbc = db.cursor()
|
||||
uprop = prop.encode("utf-8")
|
||||
bval = msgpack.packb(val)
|
||||
|
||||
if self._db_getstate(prop) == None:
|
||||
query = "INSERT INTO state (property, value) values (?, ?)"
|
||||
data = (uprop, bval)
|
||||
dbc.execute(query, data)
|
||||
else:
|
||||
query = "UPDATE state set value=:bval where property=:uprop;"
|
||||
dbc.execute(query, {"bval": bval, "uprop": uprop})
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
def _db_initpersistent(self):
|
||||
db = sqlite3.connect(self.db_path)
|
||||
dbc = db.cursor()
|
||||
|
||||
dbc.execute("CREATE TABLE IF NOT EXISTS persistent (property BLOB PRIMARY KEY, value BLOB)")
|
||||
|
||||
def _db_getpersistent(self, prop):
|
||||
db = sqlite3.connect(self.db_path)
|
||||
dbc = db.cursor()
|
||||
|
||||
query = "select * from persistent where property=:uprop"
|
||||
dbc.execute(query, {"uprop": prop.encode("utf-8")})
|
||||
result = dbc.fetchall()
|
||||
db.close()
|
||||
|
||||
if len(result) < 1:
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
entry = result[0]
|
||||
val = msgpack.unpackb(entry[1])
|
||||
return val
|
||||
except Exception as e:
|
||||
RNS.log("Could not unpack persistent value from database for property \""+str(prop)+"\". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
return None
|
||||
|
||||
def _db_setpersistent(self, prop, val):
|
||||
db = sqlite3.connect(self.db_path)
|
||||
dbc = db.cursor()
|
||||
uprop = prop.encode("utf-8")
|
||||
bval = msgpack.packb(val)
|
||||
|
||||
if self._db_getpersistent(prop) == None:
|
||||
query = "INSERT INTO persistent (property, value) values (?, ?)"
|
||||
data = (uprop, bval)
|
||||
dbc.execute(query, data)
|
||||
else:
|
||||
query = "UPDATE persistent set value=:bval where property=:uprop;"
|
||||
dbc.execute(query, {"bval": bval, "uprop": uprop})
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
|
@ -687,7 +832,11 @@ class SidebandCore():
|
|||
db.close()
|
||||
|
||||
def lxmf_announce(self):
|
||||
self.lxmf_destination.announce()
|
||||
if self.is_standalone or self.is_service:
|
||||
self.lxmf_destination.announce()
|
||||
self.setstate("wants.announce", False)
|
||||
else:
|
||||
self.setstate("wants.announce", True)
|
||||
|
||||
def is_known(self, dest_hash):
|
||||
try:
|
||||
|
@ -710,10 +859,20 @@ class SidebandCore():
|
|||
RNS.log("Error while querying for key: "+str(e), RNS.LOG_ERROR)
|
||||
return False
|
||||
|
||||
def _service_jobs(self):
|
||||
if self.is_service:
|
||||
while True:
|
||||
time.sleep(SidebandCore.JOB_INTERVAL)
|
||||
if self.getstate("wants.announce"):
|
||||
self.lxmf_announce()
|
||||
|
||||
def __start_jobs_deferred(self):
|
||||
if self.config["start_announce"]:
|
||||
# TODO: (Service) Handle this in service
|
||||
self.lxmf_destination.announce()
|
||||
self.lxmf_announce()
|
||||
|
||||
if self.is_service:
|
||||
self.service_thread = threading.Thread(target=self._service_jobs, daemon=True)
|
||||
self.service_thread.start()
|
||||
|
||||
def __start_jobs_immediate(self):
|
||||
# TODO: Reset loglevel
|
||||
|
@ -828,19 +987,14 @@ class SidebandCore():
|
|||
RNS.log("Error while adding I2P Interface. The contained exception was: "+str(e))
|
||||
self.interface_i2p = None
|
||||
|
||||
if self.is_service or self.is_standalone:
|
||||
RNS.log("Reticulum started, activating LXMF...")
|
||||
self.message_router = LXMF.LXMRouter(identity = self.identity, storagepath = self.lxmf_storage, autopeer = True)
|
||||
self.message_router.register_delivery_callback(self.lxmf_delivery)
|
||||
RNS.log("Reticulum started, activating LXMF...")
|
||||
self.message_router = LXMF.LXMRouter(identity = self.identity, storagepath = self.lxmf_storage, autopeer = True)
|
||||
self.message_router.register_delivery_callback(self.lxmf_delivery)
|
||||
|
||||
self.lxmf_destination = self.message_router.register_delivery_identity(self.identity, display_name=self.config["display_name"])
|
||||
self.lxmf_destination.set_default_app_data(self.get_display_name_bytes)
|
||||
self.lxmf_destination = self.message_router.register_delivery_identity(self.identity, display_name=self.config["display_name"])
|
||||
self.lxmf_destination.set_default_app_data(self.get_display_name_bytes)
|
||||
|
||||
self.rns_dir = RNS.Reticulum.configdir
|
||||
|
||||
else:
|
||||
self.message_router = self.serviceproxy
|
||||
self.lxmf_destination = self.serviceproxy
|
||||
self.rns_dir = RNS.Reticulum.configdir
|
||||
|
||||
if self.config["lxmf_propagation_node"] != None and self.config["lxmf_propagation_node"] != "":
|
||||
self.set_active_propagation_node(self.config["lxmf_propagation_node"])
|
||||
|
@ -941,23 +1095,21 @@ class SidebandCore():
|
|||
|
||||
if self._db_conversation(context_dest) == None:
|
||||
self._db_create_conversation(context_dest)
|
||||
self.owner_app.flag_new_conversations = True
|
||||
self.setstate("app.flags.new_conversations", True)
|
||||
|
||||
if self.owner_app.root.ids.screen_manager.current == "messages_screen":
|
||||
if self.owner_app.root.ids.messages_scrollview.active_conversation != context_dest:
|
||||
if self.gui_display() == "messages_screen":
|
||||
if self.gui_conversation() != context_dest:
|
||||
self.unread_conversation(context_dest)
|
||||
self.owner_app.flag_unread_conversations = True
|
||||
self.setstate("app.flags.unread_conversations", True)
|
||||
else:
|
||||
if self.owner_app.is_in_foreground():
|
||||
if self.gui_foreground():
|
||||
should_notify = False
|
||||
else:
|
||||
self.unread_conversation(context_dest)
|
||||
self.owner_app.flag_unread_conversations = True
|
||||
self.setstate("app.flags.unread_conversations", True)
|
||||
|
||||
try:
|
||||
self.owner_app.conversation_update(context_dest)
|
||||
except Exception as e:
|
||||
RNS.log("Error in conversation update callback: "+str(e))
|
||||
if self.is_client:
|
||||
should_notify = False
|
||||
|
||||
if should_notify:
|
||||
nlen = 128
|
||||
|
@ -966,7 +1118,7 @@ class SidebandCore():
|
|||
if len(text) > nlen:
|
||||
text += "..."
|
||||
|
||||
self.owner_app.notify(title="Message from "+self.peer_display_name(context_dest), content=notification_content)
|
||||
self.notify(title=self.peer_display_name(context_dest), content=notification_content, group="LXM", context_id=RNS.hexrep(context_dest, delimit=False))
|
||||
|
||||
|
||||
def start(self):
|
||||
|
@ -976,6 +1128,8 @@ class SidebandCore():
|
|||
thread = threading.Thread(target=self.__start_jobs_deferred)
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
||||
self._db_setstate("core.started", True)
|
||||
RNS.log("Sideband Core "+str(self)+" started")
|
||||
|
||||
def request_lxmf_sync(self, limit = None):
|
||||
|
|
|
@ -39,10 +39,8 @@ class Announces():
|
|||
def update(self):
|
||||
self.clear_list()
|
||||
self.announces = self.app.sideband.list_announces()
|
||||
|
||||
self.update_widget()
|
||||
|
||||
self.app.flag_new_announces = False
|
||||
self.app.sideband.setstate("app.flags.new_announces", False)
|
||||
|
||||
def update_widget(self):
|
||||
if self.list == None:
|
||||
|
|
|
@ -45,14 +45,14 @@ class Conversations():
|
|||
self.added_item_dests = []
|
||||
|
||||
def update(self):
|
||||
if self.app.flag_unread_conversations:
|
||||
if self.app.sideband.getstate("app.flags.unread_conversations"):
|
||||
self.clear_list()
|
||||
|
||||
self.context_dests = self.app.sideband.list_conversations()
|
||||
self.update_widget()
|
||||
|
||||
self.app.flag_new_conversations = False
|
||||
self.app.flag_unread_conversations = False
|
||||
self.app.sideband.setstate("app.flags.unread_conversations", False)
|
||||
self.app.sideband.setstate("app.flags.new_conversations", False)
|
||||
|
||||
def update_widget(self):
|
||||
if self.list == None:
|
||||
|
|
Loading…
Reference in New Issue