Added audio recording UI elements

This commit is contained in:
Mark Qvist 2024-06-02 18:33:46 +02:00
parent c32b7ce1cf
commit 4ffe16b209
3 changed files with 161 additions and 34 deletions

View File

@ -23,7 +23,6 @@ import threading
import RNS.vendor.umsgpack as msgpack import RNS.vendor.umsgpack as msgpack
if not args.daemon: if not args.daemon:
import plyer
from kivy.logger import Logger, LOG_LEVELS from kivy.logger import Logger, LOG_LEVELS
from PIL import Image as PilImage from PIL import Image as PilImage
import io import io
@ -105,6 +104,7 @@ else:
if RNS.vendor.platformutils.get_platform() == "android": if RNS.vendor.platformutils.get_platform() == "android":
from sideband.core import SidebandCore from sideband.core import SidebandCore
import plyer
from ui.layouts import * from ui.layouts import *
from ui.conversations import Conversations, MsgSync, NewConv from ui.conversations import Conversations, MsgSync, NewConv
@ -127,6 +127,7 @@ else:
else: else:
from .sideband.core import SidebandCore from .sideband.core import SidebandCore
import sbapp.plyer as plyer
from .ui.layouts import * from .ui.layouts import *
from .ui.conversations import Conversations, MsgSync, NewConv from .ui.conversations import Conversations, MsgSync, NewConv
@ -225,6 +226,8 @@ class SidebandApp(MDApp):
self.attach_path = None self.attach_path = None
self.attach_type = None self.attach_type = None
self.attach_dialog = None
self.rec_dialog = None
Window.softinput_mode = "below_target" Window.softinput_mode = "below_target"
self.icon = self.sideband.asset_dir+"/icon.png" self.icon = self.sideband.asset_dir+"/icon.png"
@ -655,6 +658,12 @@ class SidebandApp(MDApp):
self.check_permissions() self.check_permissions()
def request_microphone_permission(self):
if RNS.vendor.platformutils.get_platform() == "android":
if not check_permission("android.permission.RECORD_AUDIO"):
RNS.log("Requesting microphone permission", RNS.LOG_DEBUG)
request_permissions(["android.permission.RECORD_AUDIO"])
def check_storage_permission(self): def check_storage_permission(self):
storage_permissions_ok = False storage_permissions_ok = False
if android_api_version < 30: if android_api_version < 30:
@ -1487,46 +1496,157 @@ class SidebandApp(MDApp):
ok_button.bind(on_release=ate_dialog.dismiss) ok_button.bind(on_release=ate_dialog.dismiss)
ate_dialog.open() ate_dialog.open()
def message_attach_action(self, attach_type=None): def message_record_audio_action(self):
self.attach_path = None ss = int(dp(18))
self.attach_type = attach_type if self.rec_dialog == None:
self.message_select_file_action() if RNS.vendor.platformutils.is_android():
from plyer import audio
self.request_microphone_permission()
else:
from sbapp.plyer import audio
def message_attachment_action(self, sender): self.msg_audio = audio
if self.attach_path == None: self.msg_audio._file_path = self.sideband.rec_cache+"/msg_rec.aac"
attach_dialog = None
def a_img_lb(sender): def a_rec_action(sender):
attach_dialog.dismiss() if not self.rec_dialog.recording:
self.message_attach_action(attach_type="lbimg") RNS.log("Starting recording...") # TODO: Remove
def a_img_def(sender): self.rec_dialog.recording = True
attach_dialog.dismiss() self.rec_dialog.rec_item.children[0].children[0].icon = "stop-circle"
self.message_attach_action(attach_type="defimg") self.rec_dialog.rec_item.text = "[size="+str(ss)+"]Stop Recording[/size]"
def a_img_hq(sender): self.msg_audio.start()
attach_dialog.dismiss() else:
self.message_attach_action(attach_type="hqimg") RNS.log("Stopping recording...") # TODO: Remove
def a_file(sender): self.rec_dialog.recording = False
attach_dialog.dismiss() self.rec_dialog.rec_item.text = "[size="+str(ss)+"]Start Recording[/size]"
self.message_attach_action(attach_type="file") self.rec_dialog.rec_item.children[0].children[0].icon = "record"
self.rec_dialog.play_item.disabled = False
self.rec_dialog.save_item.disabled = False
self.msg_audio.stop()
def a_play(sender):
if self.rec_dialog.recording:
a_rec_action(sender)
if not self.rec_dialog.playing:
RNS.log("Playing recording...") # TODO: Remove
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.msg_audio.play()
else:
RNS.log("Stopping playback...") # TODO: Remove
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.stop()
def a_finished(sender):
RNS.log("Playback finished") # TODO: Remove
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)
self.rec_dialog.dismiss()
self.attach_path = self.msg_audio._file_path
self.update_message_widgets()
toast("Attached \""+str(self.attach_path)+"\"")
# TODO: Remove
self.attach_type = "file"
ss = int(dp(18))
cancel_button = MDRectangleFlatButton(text="Cancel", font_size=dp(18)) cancel_button = MDRectangleFlatButton(text="Cancel", font_size=dp(18))
attach_dialog = MDDialog( rec_item = DialogItem(IconLeftWidget(icon="record"), text="[size="+str(ss)+"]Start Recording[/size]", on_release=a_rec_action)
title="Add Attachment", play_item = DialogItem(IconLeftWidget(icon="play"), text="[size="+str(ss)+"]Play[/size]", on_release=a_play, disabled=True)
save_item = DialogItem(IconLeftWidget(icon="content-save-move-outline"), text="[size="+str(ss)+"]Save to message[/size]", on_release=a_save, disabled=True)
self.rec_dialog = MDDialog(
title="Record Audio",
type="simple", type="simple",
text="Select the type of attachment you want to send with this message\n", text="Test\n",
items=[ items=[
DialogItem(IconLeftWidget(icon="message-image-outline"), text="[size="+str(ss)+"]Low-bandwidth Image[/size]", on_release=a_img_lb), rec_item,
DialogItem(IconLeftWidget(icon="file-image"), text="[size="+str(ss)+"]Medium Image[/size]", on_release=a_img_def), play_item,
DialogItem(IconLeftWidget(icon="image-outline"), text="[size="+str(ss)+"]High-res Image[/size]", on_release=a_img_hq), save_item,
DialogItem(IconLeftWidget(icon="file-outline"), text="[size="+str(ss)+"]File Attachment[/size]", on_release=a_file),
], ],
buttons=[ cancel_button ], buttons=[ cancel_button ],
width_offset=dp(12), width_offset=dp(12),
) )
cancel_button.bind(on_release=self.rec_dialog.dismiss)
self.rec_dialog.recording = False
self.rec_dialog.playing = False
self.rec_dialog.rec_item = rec_item
self.rec_dialog.play_item = play_item
self.rec_dialog.save_item = save_item
cancel_button.bind(on_release=attach_dialog.dismiss) else:
attach_dialog.open() self.rec_dialog.play_item.disabled = True
attach_dialog.update_width() 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.children[0].children[0].icon = "record"
self.rec_dialog.open()
self.rec_dialog.update_width()
def message_attach_action(self, attach_type=None):
file_attach_types = ["lbimg", "defimg", "hqimg", "file"]
rec_attach_types = ["lbaudio", "defaudio", "hqaudio"]
self.attach_path = None
if attach_type in file_attach_types:
self.attach_type = attach_type
self.message_select_file_action()
elif attach_type in rec_attach_types:
self.attach_type = attach_type
self.message_record_audio_action()
def message_attachment_action(self, sender):
if self.attach_path == None:
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_lb(sender):
self.attach_dialog.dismiss()
self.message_attach_action(attach_type="lbaudio")
if self.attach_dialog == None:
ss = int(dp(18))
cancel_button = MDRectangleFlatButton(text="Cancel", font_size=dp(18))
self.attach_dialog = MDDialog(
title="Add Attachment",
type="simple",
text="Select the type of attachment you want to send with this message\n",
items=[
DialogItem(IconLeftWidget(icon="message-image-outline"), text="[size="+str(ss)+"]Low-bandwidth Image[/size]", on_release=a_img_lb),
DialogItem(IconLeftWidget(icon="file-image"), text="[size="+str(ss)+"]Medium Image[/size]", on_release=a_img_def),
DialogItem(IconLeftWidget(icon="image-outline"), text="[size="+str(ss)+"]High-res Image[/size]", on_release=a_img_hq),
DialogItem(IconLeftWidget(icon="microphone-message"), text="[size="+str(ss)+"]Audio Recording[/size]", on_release=a_audio_lb),
DialogItem(IconLeftWidget(icon="file-outline"), text="[size="+str(ss)+"]File Attachment[/size]", on_release=a_file),
],
buttons=[ cancel_button ],
width_offset=dp(12),
)
cancel_button.bind(on_release=self.attach_dialog.dismiss)
self.attach_dialog.open()
self.attach_dialog.update_width()
else: else:
self.attach_path = None self.attach_path = None
@ -5074,6 +5194,7 @@ class CustomOneLineIconListItem(OneLineIconListItem):
class DialogItem(OneLineIconListItem): class DialogItem(OneLineIconListItem):
divider = None divider = None
icon = StringProperty()
class MDMapIconButton(MDIconButton): class MDMapIconButton(MDIconButton):
pass pass

View File

@ -1,7 +1,6 @@
import RNS import RNS
import LXMF import LXMF
import threading import threading
import plyer
import os.path import os.path
import time import time
import struct import struct
@ -20,6 +19,7 @@ from .sense import Telemeter, Commands
from .plugins import SidebandCommandPlugin, SidebandServicePlugin, SidebandTelemetryPlugin from .plugins import SidebandCommandPlugin, SidebandServicePlugin, SidebandTelemetryPlugin
if RNS.vendor.platformutils.get_platform() == "android": if RNS.vendor.platformutils.get_platform() == "android":
import plyer
from jnius import autoclass, cast from jnius import autoclass, cast
# Squelch excessive method signature logging # Squelch excessive method signature logging
import jnius.reflect import jnius.reflect
@ -33,7 +33,8 @@ if RNS.vendor.platformutils.get_platform() == "android":
jnius.reflect.log_method = mod jnius.reflect.log_method = mod
jnius.reflect.log = redirect_log() jnius.reflect.log = redirect_log()
############################################ ############################################
else:
import sbapp.plyer as plyer
class PropagationNodeDetector(): class PropagationNodeDetector():
EMITTED_DELTA_GRACE = 300 EMITTED_DELTA_GRACE = 300
@ -170,6 +171,10 @@ class SidebandCore():
if not os.path.isdir(self.map_cache): if not os.path.isdir(self.map_cache):
os.makedirs(self.map_cache) os.makedirs(self.map_cache)
self.rec_cache = self.cache_dir+"/rec"
if not os.path.isdir(self.rec_cache):
os.makedirs(self.rec_cache)
self.icon = self.asset_dir+"/icon.png" self.icon = self.asset_dir+"/icon.png"
self.icon_48 = self.asset_dir+"/icon_48.png" self.icon_48 = self.asset_dir+"/icon_48.png"
self.icon_32 = self.asset_dir+"/icon_32.png" self.icon_32 = self.asset_dir+"/icon_32.png"

View File

@ -25,17 +25,18 @@ else:
import io import io
import os import os
import plyer
import subprocess import subprocess
import shlex import shlex
from kivy.graphics.opengl import glGetIntegerv, GL_MAX_TEXTURE_SIZE from kivy.graphics.opengl import glGetIntegerv, GL_MAX_TEXTURE_SIZE
if RNS.vendor.platformutils.get_platform() == "android": if RNS.vendor.platformutils.get_platform() == "android":
import plyer
from sideband.sense import Telemeter, Commands from sideband.sense import Telemeter, Commands
from ui.helpers import ts_format, file_ts_format, mdc from ui.helpers import ts_format, file_ts_format, mdc
from ui.helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light from ui.helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light
else: else:
import sbapp.plyer as plyer
from sbapp.sideband.sense import Telemeter, Commands from sbapp.sideband.sense import Telemeter, Commands
from .helpers import ts_format, file_ts_format, mdc from .helpers import ts_format, file_ts_format, mdc
from .helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light from .helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light