feat: android build
This commit is contained in:
parent
6017ce18d4
commit
91f0baf75c
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@
|
||||
/lock.mdb
|
||||
/data.mdb
|
||||
/.idea
|
||||
/cache
|
||||
/cache
|
||||
/ffmpeg-kit
|
713
Cargo.lock
generated
713
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
25
Cargo.toml
25
Cargo.toml
@ -19,32 +19,17 @@ pretty_env_logger = "0.5.0"
|
||||
egui_inbox = "0.6.0"
|
||||
bech32 = "0.11.0"
|
||||
libc = "0.2.158"
|
||||
egui-video = { git = "https://github.com/v0l/egui-video.git", rev = "4766d939ce4d34b5a3a57b2fbe750ea10f389f39" }
|
||||
uuid = { version = "1.11.0", features = ["v4"] }
|
||||
chrono = "0.4.38"
|
||||
anyhow = "1.0.89"
|
||||
async-trait = "0.1.83"
|
||||
sha2 = "0.10.8"
|
||||
reqwest = { version = "0.12.7", default-features = false, features = [ "rustls-tls-native-roots" ] }
|
||||
reqwest = { version = "0.12.7", default-features = false, features = ["rustls-tls-native-roots"] }
|
||||
itertools = "0.13.0"
|
||||
|
||||
egui-video = { git = "https://github.com/v0l/egui-video.git", rev = "7e9f8dbc2c7d69dd2f327b18f6dc3687d65129b4" }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.14.1"
|
||||
android-activity = { version = "0.6.0", features = [ "native-activity" ] }
|
||||
winit = { version = "0.30.5", features = [ "android-native-activity" ] }
|
||||
|
||||
[package.metadata.android]
|
||||
package = "stream.zap.app"
|
||||
build_targets = [ "aarch64-linux-android" ]
|
||||
#build_targets = [ "armv7-linux-androideabi" ]
|
||||
large_heap = true
|
||||
|
||||
[package.metadata.android.sdk]
|
||||
min_sdk_version = 20
|
||||
target_sdk_version = 32
|
||||
|
||||
[package.metadata.android.application]
|
||||
extract_native_libs = true
|
||||
|
||||
[package.metadata.android.application.activity]
|
||||
config_changes = "orientation"
|
||||
android-activity = { version = "0.6.0", features = ["native-activity"] }
|
||||
winit = { version = "0.30.5", features = ["android-native-activity"] }
|
28
android.sh
Executable file
28
android.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
git clone https://github.com/v0l/ffmpeg-kit.git
|
||||
export ANDROID_SDK_ROOT=$ANDROID_HOME
|
||||
#cd ffmpeg-kit && ./android.sh \
|
||||
# --disable-x86 \
|
||||
# --disable-x86-64 \
|
||||
# --disable-arm-v7a \
|
||||
# --disable-arm-v7a-neon \
|
||||
# --no-ffmpeg-kit-protocols \
|
||||
# --no-archive
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
NDK_VER="28.0.12433566"
|
||||
ARCH="arm64"
|
||||
PLATFORM="android"
|
||||
TRIPLET="aarch64-linux-android"
|
||||
export PKG_CONFIG_SYSROOT_DIR="/"
|
||||
export FFMPEG_DIR="$(pwd)/ffmpeg-kit/prebuilt/$PLATFORM-$ARCH/ffmpeg"
|
||||
|
||||
# DIRTY HACK !!
|
||||
cp "$ANDROID_HOME/ndk/$NDK_VER/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/$TRIPLET/35/libcamera2ndk.so" \
|
||||
./target/x/debug/android/$ARCH/cargo/$TRIPLET/debug/deps
|
||||
|
||||
x build --arch $ARCH --platform $PLATFORM --verbose
|
10
manifest.yaml
Normal file
10
manifest.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
android:
|
||||
manifest:
|
||||
package: stream.zap.app
|
||||
uses_permission:
|
||||
- name: "android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
- name: "android.permission.READ_EXTERNAL_STORAGE"
|
||||
- name: "android.permission.INTERNET"
|
||||
uses_feature:
|
||||
- name: "android.hardware.vulkan.level"
|
||||
required: true
|
12
src/app.rs
12
src/app.rs
@ -1,9 +1,10 @@
|
||||
use crate::route::Router;
|
||||
use eframe::{App, CreationContext, Frame};
|
||||
use egui::{Color32, Context, Pos2, Rect, Rounding};
|
||||
use egui::{Color32, Context};
|
||||
use nostr_sdk::database::MemoryDatabase;
|
||||
use nostr_sdk::{Client, RelayPoolNotification};
|
||||
use nostrdb::{Config, Ndb};
|
||||
use std::path::PathBuf;
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
pub struct ZapStreamApp {
|
||||
@ -13,7 +14,7 @@ pub struct ZapStreamApp {
|
||||
}
|
||||
|
||||
impl ZapStreamApp {
|
||||
pub fn new(cc: &CreationContext) -> Self {
|
||||
pub fn new(cc: &CreationContext, data_path: PathBuf) -> Self {
|
||||
let client = Client::builder()
|
||||
.database(MemoryDatabase::with_opts(Default::default()))
|
||||
.build();
|
||||
@ -34,12 +35,15 @@ impl ZapStreamApp {
|
||||
});
|
||||
egui_extras::install_image_loaders(&cc.egui_ctx);
|
||||
|
||||
let ndb = Ndb::new(".", &Config::default()).unwrap();
|
||||
let ndb_path = data_path.join("ndb");
|
||||
std::fs::create_dir_all(&ndb_path).expect("Failed to create ndb directory");
|
||||
|
||||
let ndb = Ndb::new(ndb_path.to_str().unwrap(), &Config::default()).unwrap();
|
||||
|
||||
Self {
|
||||
client: client.clone(),
|
||||
notifications,
|
||||
router: Router::new(cc.egui_ctx.clone(), client.clone(), ndb.clone()),
|
||||
router: Router::new(data_path, cc.egui_ctx.clone(), client.clone(), ndb.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use eframe::Renderer;
|
||||
use egui::Vec2;
|
||||
use std::path::PathBuf;
|
||||
use zap_stream_app::app::ZapStreamApp;
|
||||
|
||||
#[tokio::main]
|
||||
@ -12,9 +13,10 @@ async fn main() {
|
||||
options.renderer = Renderer::Glow;
|
||||
options.viewport = options.viewport.with_inner_size(Vec2::new(360., 720.));
|
||||
|
||||
let data_path = PathBuf::from(".");
|
||||
let _res = eframe::run_native(
|
||||
"zap.stream",
|
||||
options,
|
||||
Box::new(move |cc| Ok(Box::new(ZapStreamApp::new(cc)))),
|
||||
Box::new(move |cc| Ok(Box::new(ZapStreamApp::new(cc, data_path)))),
|
||||
);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ use winit::platform::android::EventLoopBuilderExtAndroid;
|
||||
#[tokio::main]
|
||||
pub async fn android_main(app: AndroidApp) {
|
||||
std::env::set_var("RUST_BACKTRACE", "full");
|
||||
android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info));
|
||||
android_logger::init_once(android_logger::Config::default().with_max_level(log::LevelFilter::Info));
|
||||
|
||||
let mut options = eframe::NativeOptions::default();
|
||||
options.renderer = Renderer::Glow;
|
||||
@ -31,9 +31,14 @@ pub async fn android_main(app: AndroidApp) {
|
||||
builder.with_android_app(app_clone_for_event_loop);
|
||||
}));
|
||||
|
||||
let external_data_path = app
|
||||
.external_data_path()
|
||||
.expect("external data path")
|
||||
.to_path_buf();
|
||||
|
||||
let _res = eframe::run_native(
|
||||
"zap.stream",
|
||||
options,
|
||||
Box::new(move |cc| Ok(Box::new(ZapStreamApp::new(cc)))),
|
||||
Box::new(move |cc| Ok(Box::new(ZapStreamApp::new(cc, external_data_path)))),
|
||||
);
|
||||
}
|
@ -14,6 +14,7 @@ use nostr_sdk::nips::nip01;
|
||||
use nostr_sdk::{Client, Kind, PublicKey};
|
||||
use nostrdb::{Filter, Ndb, Note, Transaction};
|
||||
use std::borrow::Borrow;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod home;
|
||||
mod stream;
|
||||
@ -52,7 +53,7 @@ pub struct Router {
|
||||
}
|
||||
|
||||
impl Router {
|
||||
pub fn new(ctx: Context, client: Client, ndb: Ndb) -> Self {
|
||||
pub fn new(data_path: PathBuf, ctx: Context, client: Client, ndb: Ndb) -> Self {
|
||||
Self {
|
||||
current: Routes::HomePage,
|
||||
current_widget: None,
|
||||
@ -61,7 +62,7 @@ impl Router {
|
||||
ndb: NDBWrapper::new(ctx.clone(), ndb.clone(), client.clone()),
|
||||
client,
|
||||
login: None,
|
||||
image_cache: ImageCache::new(ctx.clone()),
|
||||
image_cache: ImageCache::new(data_path, ctx.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ pub struct ImageCache {
|
||||
}
|
||||
|
||||
impl ImageCache {
|
||||
pub fn new(ctx: egui::Context) -> Self {
|
||||
let out = PathBuf::from("./cache/images");
|
||||
pub fn new(data_path: PathBuf, ctx: egui::Context) -> Self {
|
||||
let out = data_path.join("cache/images");
|
||||
fs::create_dir_all(&out).unwrap();
|
||||
Self {
|
||||
ctx,
|
||||
|
@ -1,18 +1,21 @@
|
||||
use crate::widgets::VideoPlaceholder;
|
||||
use egui::{Context, Response, Ui, Vec2, Widget};
|
||||
use egui_video::Player;
|
||||
use egui_video::{AudioDevice, Player};
|
||||
|
||||
pub struct StreamPlayer {
|
||||
player: Option<Player>,
|
||||
audio: AudioDevice,
|
||||
}
|
||||
|
||||
impl StreamPlayer {
|
||||
pub fn new(ctx: &Context, url: &String) -> Self {
|
||||
let mut audio = AudioDevice::new().unwrap();
|
||||
Self {
|
||||
player: Player::new(ctx, url).map_or(None, |mut f| {
|
||||
f.start();
|
||||
Some(f)
|
||||
}),
|
||||
audio,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,6 +27,7 @@ impl Widget for &mut StreamPlayer {
|
||||
let size = Vec2::new(w, h);
|
||||
|
||||
if let Some(mut p) = self.player.as_mut() {
|
||||
p.add_audio(&mut self.audio).expect("Failed to add audio to stream player");
|
||||
p.ui(ui, size)
|
||||
} else {
|
||||
VideoPlaceholder.ui(ui)
|
||||
|
Loading…
x
Reference in New Issue
Block a user