mirror of
https://github.com/liberatedsystems/openCom-Companion.git
synced 2025-02-22 09:19:51 +01:00
Added markdown rendering and message composing
This commit is contained in:
parent
a90a451865
commit
84b214cb90
@ -12,7 +12,7 @@ version.regex = __version__ = ['"](.*)['"]
|
||||
version.filename = %(source.dir)s/main.py
|
||||
android.numeric_version = 20250120
|
||||
|
||||
requirements = kivy==2.3.0,libbz2,pillow==10.2.0,qrcode==7.3.1,usb4a,usbserial4a,able_recipe,libwebp,libogg,libopus,opusfile,numpy,cryptography,ffpyplayer,codec2,pycodec2,sh,pynacl,typing-extensions
|
||||
requirements = kivy==2.3.0,libbz2,pillow==10.2.0,qrcode==7.3.1,usb4a,usbserial4a,able_recipe,libwebp,libogg,libopus,opusfile,numpy,cryptography,ffpyplayer,codec2,pycodec2,sh,pynacl,typing-extensions,mistune>=3.0.2,beautifulsoup4
|
||||
|
||||
android.gradle_dependencies = com.android.support:support-compat:28.0.0
|
||||
#android.enable_androidx = True
|
||||
|
@ -19,6 +19,7 @@ import RNS
|
||||
import LXMF
|
||||
import time
|
||||
import os
|
||||
import re
|
||||
import pathlib
|
||||
import base64
|
||||
import threading
|
||||
@ -1523,6 +1524,50 @@ class SidebandApp(MDApp):
|
||||
|
||||
### Messages (conversation) screen
|
||||
######################################
|
||||
|
||||
def md_to_bbcode(self, text):
|
||||
if not hasattr(self, "mdconv"):
|
||||
from md2bbcode.main import process_readme as mdconv
|
||||
self.mdconv = mdconv
|
||||
converted = self.mdconv(text)
|
||||
while converted.endswith("\n"):
|
||||
converted = converted[:-1]
|
||||
|
||||
return converted
|
||||
|
||||
def process_bb_markup(self, text):
|
||||
st = time.time()
|
||||
ms = int(sp(14))
|
||||
h1s = int(sp(20))
|
||||
h2s = int(sp(18))
|
||||
h3s = int(sp(16))
|
||||
|
||||
if not hasattr(self, "pres"):
|
||||
self.pres = []
|
||||
res = [ [r"\[(?:code|icode).*?\]", f"[font=mono][size={ms}]"],
|
||||
[r"\[\/(?:code|icode).*?\]", "[/size][/font]"],
|
||||
[r"\[(?:heading)\]", f"[b][size={h1s}]"],
|
||||
[r"\[(?:heading=1)*?\]", f"[b][size={h1s}]"],
|
||||
[r"\[(?:heading=2)*?\]", f"[b][size={h2s}]"],
|
||||
[r"\[(?:heading=3)*?\]", f"[b][size={h3s}]"],
|
||||
[r"\[(?:heading=).*?\]", f"[b][size={h3s}]"], # Match all remaining lower-level headings
|
||||
[r"\[\/(?:heading).*?\]", "[/size][/b]"],
|
||||
[r"\[(?:list).*?\]", ""],
|
||||
[r"\[\/(?:list).*?\]", ""],
|
||||
[r"\n\[(?:\*).*?\]", "\n - "],
|
||||
[r"\[(?:url).*?\]", ""], # Strip URLs for now
|
||||
[r"\[\/(?:url).*?\]", ""],
|
||||
[r"\[(?:img).*?\].*\[\/(?:img).*?\]", ""] # Strip images for now
|
||||
]
|
||||
|
||||
for r in res:
|
||||
self.pres.append([re.compile(r[0], re.IGNORECASE | re.MULTILINE ), r[1]])
|
||||
|
||||
for pr in self.pres:
|
||||
text = pr[0].sub(pr[1], text)
|
||||
|
||||
return text
|
||||
|
||||
def conversation_from_announce_action(self, context_dest):
|
||||
if self.sideband.has_conversation(context_dest):
|
||||
pass
|
||||
@ -2758,7 +2803,7 @@ class SidebandApp(MDApp):
|
||||
|
||||
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]PyDub[/b] (MIT License)\n - [b]PyOgg[/b] (Public Domain)\n - [b]MD2bbcode[/b] (GPL3 License)"
|
||||
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 © 2025 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
|
||||
@ -3041,6 +3086,10 @@ class SidebandApp(MDApp):
|
||||
self.sideband.config["trusted_markup_only"] = self.settings_screen.ids.settings_trusted_markup_only.active
|
||||
self.sideband.save_configuration()
|
||||
|
||||
def save_compose_in_markdown(sender=None, event=None):
|
||||
self.sideband.config["compose_in_markdown"] = self.settings_screen.ids.settings_compose_in_markdown.active
|
||||
self.sideband.save_configuration()
|
||||
|
||||
def save_advanced_stats(sender=None, event=None):
|
||||
self.sideband.config["advanced_stats"] = self.settings_screen.ids.settings_advanced_statistics.active
|
||||
self.sideband.save_configuration()
|
||||
@ -3219,6 +3268,9 @@ class SidebandApp(MDApp):
|
||||
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_compose_in_markdown.active = self.sideband.config["compose_in_markdown"]
|
||||
self.settings_screen.ids.settings_compose_in_markdown.bind(active=save_compose_in_markdown)
|
||||
|
||||
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)
|
||||
|
||||
|
@ -457,6 +457,7 @@ class SidebandCore():
|
||||
self.config["eink_mode"] = True
|
||||
self.config["lxm_limit_1mb"] = True
|
||||
self.config["trusted_markup_only"] = False
|
||||
self.config["compose_in_markdown"] = False
|
||||
|
||||
# Connectivity
|
||||
self.config["connect_transport"] = False
|
||||
@ -601,6 +602,8 @@ class SidebandCore():
|
||||
self.config["hq_ptt"] = False
|
||||
if not "trusted_markup_only" in self.config:
|
||||
self.config["trusted_markup_only"] = False
|
||||
if not "compose_in_markdown" in self.config:
|
||||
self.config["compose_in_markdown"] = False
|
||||
|
||||
if not "input_language" in self.config:
|
||||
self.config["input_language"] = None
|
||||
@ -4396,7 +4399,13 @@ class SidebandCore():
|
||||
fields[LXMF.FIELD_IMAGE] = image
|
||||
if audio != None:
|
||||
fields[LXMF.FIELD_AUDIO] = audio
|
||||
if self.has_bb_markup(content):
|
||||
md_sig = "#!md\n"
|
||||
if content.startswith(md_sig):
|
||||
content = content[len(md_sig):]
|
||||
fields[LXMF.FIELD_RENDERER] = LXMF.RENDERER_MARKDOWN
|
||||
elif self.config["compose_in_markdown"]:
|
||||
fields[LXMF.FIELD_RENDERER] = LXMF.RENDERER_MARKDOWN
|
||||
elif self.has_bb_markup(content):
|
||||
fields[LXMF.FIELD_RENDERER] = LXMF.RENDERER_BBCODE
|
||||
|
||||
lxm = LXMF.LXMessage(dest, source, content, title="", desired_method=desired_method, fields = fields, include_ticket=self.is_trusted(destination_hash))
|
||||
@ -4538,12 +4547,12 @@ class SidebandCore():
|
||||
|
||||
def strip_bb_markup(self, text):
|
||||
if not hasattr(self, "smr") or self.smr == None:
|
||||
self.smr = re.compile(r'\[\/?(?:b|i|u|url|quote|code|img|color|size)*?.*?\]',re.IGNORECASE | re.MULTILINE )
|
||||
self.smr = re.compile(r"\[\/?(?:b|i|u|url|quote|code|img|color|size)*?.*?\]",re.IGNORECASE | re.MULTILINE )
|
||||
return self.smr.sub("", text)
|
||||
|
||||
def has_bb_markup(self, text):
|
||||
if not hasattr(self, "smr") or self.smr == None:
|
||||
self.smr = re.compile(r'\[\/?(?:b|i|u|url|quote|code|img|color|size)*?.*?\]',re.IGNORECASE | re.MULTILINE )
|
||||
self.smr = re.compile(r"\[\/?(?:b|i|u|url|quote|code|img|color|size)*?.*?\]",re.IGNORECASE | re.MULTILINE )
|
||||
if self.smr.match(text):
|
||||
return True
|
||||
else:
|
||||
|
@ -1655,6 +1655,22 @@ MDScreen:
|
||||
disabled: False
|
||||
active: False
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "horizontal"
|
||||
size_hint_y: None
|
||||
padding: [0,0,dp(24),dp(0)]
|
||||
height: dp(48)
|
||||
|
||||
MDLabel:
|
||||
text: "Compose messages in markdown"
|
||||
font_style: "H6"
|
||||
|
||||
MDSwitch:
|
||||
id: settings_compose_in_markdown
|
||||
pos_hint: {"center_y": 0.3}
|
||||
disabled: False
|
||||
active: False
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "horizontal"
|
||||
size_hint_y: None
|
||||
|
@ -110,8 +110,6 @@ class Messages():
|
||||
msg = self.app.sideband.message(lxm_hash)
|
||||
if msg:
|
||||
close_button = MDRectangleFlatButton(text="Close", font_size=dp(18))
|
||||
# d_items = [ ]
|
||||
# d_items.append(DialogItem(IconLeftWidget(icon="postage-stamp"), text="[size="+str(ss)+"]Stamp[/size]"))
|
||||
|
||||
d_text = ""
|
||||
|
||||
@ -492,11 +490,24 @@ class Messages():
|
||||
|
||||
for m in self.new_messages:
|
||||
if not m["hash"] in self.added_item_hashes:
|
||||
renderer = None
|
||||
message_source = m["content"]
|
||||
if "lxm" in m and m["lxm"] and m["lxm"].fields != None and LXMF.FIELD_RENDERER in m["lxm"].fields:
|
||||
renderer = m["lxm"].fields[LXMF.FIELD_RENDERER]
|
||||
|
||||
try:
|
||||
if self.app.sideband.config["trusted_markup_only"] and not self.is_trusted:
|
||||
message_input = str( escape_markup(m["content"].decode("utf-8")) ).encode("utf-8")
|
||||
else:
|
||||
message_input = m["content"]
|
||||
if renderer == LXMF.RENDERER_MARKDOWN:
|
||||
message_input = self.app.md_to_bbcode(message_input.decode("utf-8")).encode("utf-8")
|
||||
message_input = self.app.process_bb_markup(message_input.decode("utf-8")).encode("utf-8")
|
||||
elif renderer == LXMF.RENDERER_BBCODE:
|
||||
message_input = self.app.process_bb_markup(message_input.decode("utf-8")).encode("utf-8")
|
||||
else:
|
||||
message_input = str(escape_markup(m["content"].decode("utf-8"))).encode("utf-8")
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Message content could not be decoded: {e}", RNS.LOG_DEBUG)
|
||||
message_input = b""
|
||||
@ -1144,7 +1155,7 @@ class Messages():
|
||||
"viewclass": "OneLineListItem",
|
||||
"text": "Copy message text",
|
||||
"height": dp(40),
|
||||
"on_release": gen_copy(message_input.decode("utf-8"), item)
|
||||
"on_release": gen_copy(message_source.decode("utf-8"), item)
|
||||
},
|
||||
{
|
||||
"text": "Delete",
|
||||
@ -1178,7 +1189,7 @@ class Messages():
|
||||
"viewclass": "OneLineListItem",
|
||||
"text": "Copy message text",
|
||||
"height": dp(40),
|
||||
"on_release": gen_copy(message_input.decode("utf-8"), item)
|
||||
"on_release": gen_copy(message_source.decode("utf-8"), item)
|
||||
},
|
||||
{
|
||||
"text": "Delete",
|
||||
@ -1196,7 +1207,7 @@ class Messages():
|
||||
"viewclass": "OneLineListItem",
|
||||
"text": "Copy",
|
||||
"height": dp(40),
|
||||
"on_release": gen_copy(message_input.decode("utf-8"), item)
|
||||
"on_release": gen_copy(message_source.decode("utf-8"), item)
|
||||
},
|
||||
{
|
||||
"text": "Delete",
|
||||
@ -1213,7 +1224,7 @@ class Messages():
|
||||
"viewclass": "OneLineListItem",
|
||||
"text": "Copy",
|
||||
"height": dp(40),
|
||||
"on_release": gen_copy(message_input.decode("utf-8"), item)
|
||||
"on_release": gen_copy(message_source.decode("utf-8"), item)
|
||||
},
|
||||
{
|
||||
"viewclass": "OneLineListItem",
|
||||
@ -1236,7 +1247,7 @@ class Messages():
|
||||
"viewclass": "OneLineListItem",
|
||||
"text": "Copy",
|
||||
"height": dp(40),
|
||||
"on_release": gen_copy(message_input.decode("utf-8"), item)
|
||||
"on_release": gen_copy(message_source.decode("utf-8"), item)
|
||||
},
|
||||
{
|
||||
"text": "Delete",
|
||||
|
Loading…
x
Reference in New Issue
Block a user