8 Commits

20 changed files with 137 additions and 63 deletions

View File

@@ -11,6 +11,8 @@ electron/
android/
scripts/
Makefile
*.apk
*.aab
# Build artifacts and cache
build/

View File

@@ -69,7 +69,9 @@ jobs:
version: 10.0.0
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng
run: |
sudo apt-get update
sudo apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
@@ -85,9 +87,6 @@ jobs:
- name: Build Frontend
run: task build-frontend
- name: Prepare frontend directory
run: python scripts/prepare_frontend_dir.py
- name: Build Python wheel
run: task wheel
@@ -106,7 +105,7 @@ jobs:
echo "## SHA256 Checksums" > release-body.md
echo "" >> release-body.md
for file in *; do
if [ -f "$file" ] && [ "$file" != "release-body.md" ]; then
if [ -f "$file" ] && [ "$file" != "release-body.md" ] && [[ "$file" != *.sha256 ]]; then
sha256sum "$file" | tee "${file}.sha256"
echo "\`$(cat "${file}.sha256")\`" >> release-body.md
fi

5
.gitignore vendored
View File

@@ -40,9 +40,14 @@ android/local.properties
android/build/
android/app/build/
android/app/src/main/python/meshchatx/
android/app/src/main/python/RNS/
android/app/src/main/python/LXMF/
android/app/src/main/python/LXST/
android/app/src/main/python/meshchat_wrapper.py.bak
android/*.iml
android/.idea/
*.apk
*.aab
# Local storage and runtime data

View File

@@ -182,12 +182,29 @@ tasks:
android-prepare:
desc: Prepare Android build (copy meshchatx package and assets)
deps: [build, android-init]
deps: [build-frontend, android-init]
cmds:
- |
echo "Copying meshchatx package to Android project..."
echo "Copying meshchatx package and dependencies to Android project..."
mkdir -p android/app/src/main/python
# Remove old copies to ensure fresh build
rm -rf android/app/src/main/python/meshchatx
rm -rf android/app/src/main/python/RNS
rm -rf android/app/src/main/python/LXMF
rm -rf android/app/src/main/python/LXST
# Copy MeshChatX
cp -r meshchatx android/app/src/main/python/
# Vendor RNS, LXMF, and LXST from local source (like Sideband does)
cp -r /mnt/projects/Reticulum/Reticulum/RNS android/app/src/main/python/
cp -r /mnt/projects/Reticulum/LXMF/LXMF android/app/src/main/python/
cp -r /mnt/projects/Reticulum/LXST/LXST android/app/src/main/python/
# Cleanup vendored packages (remove utilities/tests etc if needed, similar to Sideband)
rm -rf android/app/src/main/python/RNS/Utilities/RNS
rm -rf android/app/src/main/python/LXMF/Utilities/LXMF
rm -rf android/app/src/main/python/LXST/Utilities/LXST
- |
echo "Android build prepared. Don't forget to:"
echo "1. Add Chaquopy license to android/local.properties"

View File

@@ -15,6 +15,9 @@ android {
versionName "3.1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "arm64-v8a", "x86_64"
}
}
buildTypes {
@@ -39,30 +42,20 @@ android {
chaquopy {
defaultConfig {
version = "3.11"
buildPython "python3.11"
buildPython "/usr/bin/python3.11"
pip {
install "aiohttp>=3.13.2"
install "lxmf>=0.9.3"
install "aiohttp==3.10.10"
install "psutil>=7.1.3"
install "rns>=1.0.4"
install "websockets>=15.0.1"
install "bcrypt>=5.0.0,<6.0.0"
install "bcrypt==3.1.7"
install "aiohttp-session>=2.12.1,<3.0.0"
install "cryptography>=46.0.3,<47.0.0"
install "cryptography==42.0.8"
install "requests>=2.32.5,<3.0.0"
install "lxst>=0.4.5,<0.5.0"
install "numpy==1.26.2"
install "ply>=3.11,<4.0"
}
}
sourceSets {
main {
python {
srcDirs = ["src/main/python"]
}
}
}
}
dependencies {

View File

@@ -12,9 +12,9 @@
<application
android:name="com.chaquo.python.android.PyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:roundIcon="@drawable/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MeshChatX"
android:usesCleartextTraffic="true"

View File

@@ -13,7 +13,7 @@ import com.chaquo.python.android.AndroidPlatform;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private ProgressBar progressBar;
private static final String SERVER_URL = "http://127.0.0.1:8000";
private static final String SERVER_URL = "https://127.0.0.1:8000";
private static final int SERVER_PORT = 8000;
@SuppressLint("SetJavaScriptEnabled")
@@ -49,6 +49,13 @@ public class MainActivity extends AppCompatActivity {
super.onPageStarted(view, url, favicon);
progressBar.setVisibility(android.view.View.VISIBLE);
}
@SuppressLint("WebViewClientOnReceivedSslError")
@Override
public void onReceivedSslError(WebView view, android.webkit.SslErrorHandler handler, android.net.http.SslError error) {
// Ignore SSL certificate errors for localhost
handler.proceed();
}
});
startMeshChatServer();

View File

@@ -8,8 +8,7 @@ def start_server(port=8000):
'meshchat',
'--headless',
'--host', '127.0.0.1',
'--port', str(port),
'--no-https'
'--port', str(port)
]
main()

View File

@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3D5AFE"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M30,30h48v48h-48z" />
</vector>

View File

@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3D5AFE"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M30,30h48v48h-48z" />
</vector>

View File

@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3D5AFE"
android:pathData="M54,54m-50,0a50,50 0,1 1,100 0a50,50 0,1 1,-100 0" />
<path
android:fillColor="#FFFFFF"
android:pathData="M30,30h48v48h-48z" />
</vector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/purple_500"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/purple_500"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -6,15 +6,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.7.3'
classpath "com.chaquo.python:gradle:15.0.1"
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url "https://chaquo.com/maven" }
classpath "com.chaquo.python:gradle:16.1.0"
}
}

View File

@@ -7931,7 +7931,7 @@ class ReticulumMeshChat:
destination_hash,
)
if db_destination_display_name is not None:
return db_destination_display_name.display_name
return db_destination_display_name
return None

View File

@@ -252,33 +252,42 @@ class VoicemailManager:
greeting_path = os.path.join(self.greetings_dir, "greeting.opus")
if not os.path.exists(greeting_path):
# Fallback if no greeting generated yet
self.generate_greeting(self.config.voicemail_greeting.get())
if self.has_espeak and self.has_ffmpeg:
try:
self.generate_greeting(self.config.voicemail_greeting.get())
except Exception as e:
RNS.log(f"Voicemail: Could not generate initial greeting: {e}", RNS.LOG_ERROR)
else:
RNS.log("Voicemail: espeak-ng or ffmpeg missing, cannot generate greeting", RNS.LOG_WARNING)
def session_job():
try:
# 1. Play greeting
try:
greeting_source = OpusFileSource(greeting_path, target_frame_ms=60)
# Attach to transmit mixer
greeting_pipeline = Pipeline(
source=greeting_source,
codec=Null(),
sink=telephone.transmit_mixer,
)
greeting_pipeline.start()
if os.path.exists(greeting_path):
try:
greeting_source = OpusFileSource(greeting_path, target_frame_ms=60)
# Attach to transmit mixer
greeting_pipeline = Pipeline(
source=greeting_source,
codec=Null(),
sink=telephone.transmit_mixer,
)
greeting_pipeline.start()
# Wait for greeting to finish
while greeting_source.running:
time.sleep(0.1)
if not telephone.active_call:
return
# Wait for greeting to finish
while greeting_source.running:
time.sleep(0.1)
if not telephone.active_call:
return
greeting_pipeline.stop()
except Exception as e:
RNS.log(
f"Voicemail: Could not play greeting (libs missing?): {e}",
RNS.LOG_ERROR,
)
greeting_pipeline.stop()
except Exception as e:
RNS.log(
f"Voicemail: Could not play greeting (libs missing?): {e}",
RNS.LOG_ERROR,
)
else:
RNS.log("Voicemail: No greeting available to play", RNS.LOG_WARNING)
# 2. Play beep
beep_source = LXST.ToneSource(

View File

@@ -47,10 +47,10 @@
@drop.prevent="onFavouriteDrop($event, favourite)"
@dragend="onFavouriteDragEnd"
>
<div class="favourite-card__icon">
<div class="favourite-card__icon flex-shrink-0">
<MaterialDesignIcon icon-name="server-network" class="w-5 h-5" />
</div>
<div class="flex-1">
<div class="min-w-0 flex-1">
<div
class="text-sm font-semibold text-gray-900 dark:text-white truncate"
:title="favourite.display_name"

View File

@@ -3,4 +3,4 @@ Auto-generated helper so Python tooling and the Electron build
share the same version string.
"""
__version__ = '3.1.0'
__version__ = '3.2.0'

View File

@@ -1,6 +1,6 @@
{
"name": "reticulum-meshchatx",
"version": "3.1.0",
"version": "3.2.0",
"description": "A simple mesh network communications app powered by the Reticulum Network Stack",
"homepage": "https://git.quad4.io/RNS-Things/MeshChatX",
"author": "Sudo-Ivan",

View File

@@ -1,6 +1,6 @@
[project]
name = "reticulum-meshchatx"
version = "3.1.0"
version = "3.2.0"
description = "A simple mesh network communications app powered by the Reticulum Network Stack"
authors = [
{name = "Sudo-Ivan"}