Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,120 changes: 1,135 additions & 985 deletions RustApp/Cargo.lock

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions RustApp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,14 @@ directories = "6"
prost = "0.14"
tokio-util = { version = "0.7", features = ["codec", "net"] }
chrono = "0.4"
libcosmic = { git = "https://github.com/pop-os/libcosmic.git", rev = "8412dd593913b85618ec30e8b92a58aaa0ad6bb8", default-features = false, features = [
libcosmic = { git = "https://github.com/pop-os/libcosmic.git", rev = "709044891ee04c6ca62ff3d1087ab0e4ebb59bb4", default-features = false, features = [
"winit",
"wgpu",
"tokio",
"multi-window",
"markdown",
# todo: remove this
"highlighter",
"about",
"a11y",
] }
notify-rust = "4"
byteorder = "1"
Expand All @@ -93,6 +92,7 @@ serde_with = "3"
strum = { version = "0.27", features = ["derive"] }
resvg = "0.45"
rubato = "0.16"
#https://github.com/tauri-apps/fix-path-env-rs/pull/19
fix-path-env = { git = "https://github.com/wiiznokes/fix-path-env-rs", rev = "8612a0d8590843dbe9c6326d26292963e6a97f2a" }
env_logger = "0.11"
nnnoiseless = "0.5"
Expand All @@ -101,7 +101,9 @@ speexdsp = { git = "https://github.com/wiiznokes/speexdsp-rs-fork", branch = "ve
"sys",
"vendored-sys",
] }
fslock = "0.2.1"
fslock = "0.2"
interprocess = { version = "2", features = ["tokio"] }
async-stream = "0.3"

[build-dependencies]
prost-build = "0.14"
Expand Down
3 changes: 3 additions & 0 deletions RustApp/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ pub struct Args {
default_value_t = false
)]
pub show_supported_audio_config: bool,

#[arg(long, hide = true, default_value_t = false)]
pub launched_automatically: bool,
}

#[derive(
Expand Down
21 changes: 16 additions & 5 deletions RustApp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ use ui::app::run_ui;
use utils::{APP, ORG, QUALIFIER};
use zconf::ConfigManager;

use crate::ui::app::Flags;

#[macro_use]
extern crate log;

mod audio;
mod config;
mod single_instance;
mod start_at_login;
mod streamer;
mod ui;
Expand Down Expand Up @@ -85,10 +88,14 @@ fn main() {
};
let mut app_lock = LockFile::open(&instance_lock_path).expect("Failed to open app lock file");
if !app_lock.try_lock_with_pid().unwrap_or(false) {
error!(
info!(
"Another instance is already running. PID can be found in {:?}",
instance_lock_path
);

if let Err(e) = single_instance::send_event(single_instance::IpcEvent::Show) {
error!("can't send ipc event {e}");
}
return;
}

Expand Down Expand Up @@ -142,9 +149,13 @@ fn main() {
});

localize::localize();
run_ui(

let flags = Flags {
config,
config_file_path.to_string_lossy().to_string(),
log_file_path.to_string_lossy().to_string(),
)
config_path: config_file_path.to_string_lossy().to_string(),
log_path: log_file_path.to_string_lossy().to_string(),
launched_automatically: args.launched_automatically,
};

run_ui(flags)
}
89 changes: 89 additions & 0 deletions RustApp/src/single_instance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use byteorder::WriteBytesExt;
use futures::stream::Stream;
use interprocess::local_socket::traits::Stream as InterprocessStreamTrait;
use interprocess::local_socket::traits::tokio::Listener as TokioListener;
use interprocess::local_socket::{GenericNamespaced, ListenerOptions, ToNsName};
use interprocess::local_socket::{Name, Stream as InterprocessStream};

use tokio::io::AsyncReadExt;

use async_stream::stream;

#[derive(Debug, Clone)]
pub enum IpcEvent {
Show,
}

impl TryFrom<u8> for IpcEvent {
type Error = ();

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(IpcEvent::Show),
_ => Err(()),
}
}
}

impl From<IpcEvent> for u8 {
fn from(value: IpcEvent) -> Self {
match value {
IpcEvent::Show => 0,
}
}
}

fn get_name() -> anyhow::Result<Name<'static>> {
let printname = "android-mic.sock";
let name = printname.to_ns_name::<GenericNamespaced>()?;
Ok(name)
}

pub fn stream() -> anyhow::Result<impl Stream<Item = IpcEvent>> {
let name = get_name()?;
let opts = ListenerOptions::new().name(name);
let listener = opts.create_tokio()?;

let stream = stream! {

loop {
match listener.accept().await {
Ok(mut client) => {
loop {
match client.read_u8().await {
Ok(byte) => match byte.try_into() {
Ok(event) => yield event,
Err(_) => {
error!("can't parse ipc event");
}
},
Err(e) => {
if e.kind() == std::io::ErrorKind::UnexpectedEof {
} else {
error!("error reading client: {e}");
}
break;
}
}
}
}
Err(e) => {
error!("error accepting client: {e}");
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
}
}
};

Ok(stream)
}

pub fn send_event(event: IpcEvent) -> anyhow::Result<()> {
let name = get_name()?;

let mut stream = InterprocessStream::connect(name)?;

stream.write_u8(event.into())?;

Ok(())
}
5 changes: 4 additions & 1 deletion RustApp/src/start_at_login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ mod windows {
fn create_shortcut(lnk: &Path) -> anyhow::Result<()> {
let target = env::current_exe()?;

mslnk::ShellLink::new(target)?.create_lnk(lnk)?;
let mut shell_link = mslnk::ShellLink::new(target)?;
shell_link.set_name(Some(String::from("AndroidMic")));
shell_link.set_arguments(Some(String::from("--launched-automatically")));
shell_link.create_lnk(lnk)?;

Ok(())
}
Expand Down
50 changes: 36 additions & 14 deletions RustApp/src/ui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,18 @@ use crate::{
config::{
AppTheme, AudioFormat, ChannelCount, Config, ConnectionMode, NetworkAdapter, SampleRate,
},
fl,
fl, single_instance,
streamer::{self, ConnectOption, StreamerCommand, StreamerMsg},
ui::view::{SCROLLABLE_ID, about_window},
utils::APP_ID,
window_icon,
};
use zconf::ConfigManager;

pub fn run_ui(config: ConfigManager<Config>, config_path: String, log_path: String) {
pub fn run_ui(flags: Flags) {
let settings = Settings::default()
.no_main_window(true)
.theme(to_cosmic_theme(&config.data().theme));

let flags = Flags {
config,
config_path,
log_path,
};
.theme(to_cosmic_theme(&flags.config.data().theme));

cosmic::app::run::<AppState>(settings, flags).unwrap();
}
Expand Down Expand Up @@ -137,6 +131,7 @@ pub struct AppState {
pub system_tray: Option<SystemTray>,
pub system_tray_stream: Option<SystemTrayStream>,
has_shown_minimize_notification: bool,
launched_automatically: bool,
}

pub struct CustomWindow {
Expand Down Expand Up @@ -274,9 +269,10 @@ impl AppState {
}

pub struct Flags {
config: ConfigManager<Config>,
config_path: String,
log_path: String,
pub config: ConfigManager<Config>,
pub config_path: String,
pub log_path: String,
pub launched_automatically: bool,
}

// used because the markdown parsing only detect https links
Expand Down Expand Up @@ -386,6 +382,7 @@ impl Application for AppState {
system_tray,
system_tray_stream,
has_shown_minimize_notification: false,
launched_automatically: flags.launched_automatically,
};

commands.push(
Expand All @@ -403,10 +400,21 @@ impl Application for AppState {
info!("config path: {}", flags.config_path);
info!("log path: {}", flags.log_path);

if !app.config.data().start_minimized {
if !flags.launched_automatically || !app.config.data().start_minimized {
commands.push(app.open_main_window());
}

match single_instance::stream() {
Ok(stream) => {
commands.push(cosmic::iced::task::Task::run(stream, |event| match event {
single_instance::IpcEvent::Show => cosmic::Action::App(AppMsg::ShowWindow),
}));
}
Err(e) => {
error!("can't create ipc stream {e}")
}
}

(app, Task::batch(commands))
}

Expand Down Expand Up @@ -708,7 +716,7 @@ impl Application for AppState {
self.about_window = None;
}

if !self.config.data().start_minimized && !self.has_shown_minimize_notification {
if !self.launched_automatically && !self.has_shown_minimize_notification {
let _ = Notification::new()
.summary("AndroidMic")
.body(&fl!("minimized_to_tray"))
Expand Down Expand Up @@ -763,6 +771,20 @@ impl Application for AppState {
SystemTrayMsg::Connect => return self.connect(),
SystemTrayMsg::Disconnect => return self.disconnect(),
},
AppMsg::ShowWindow => {
if let Some(main_window) = &self.main_window {
// avoid duplicate window
return cosmic::iced_runtime::task::effect(
cosmic::iced::runtime::Action::Window(window::Action::GainFocus(
main_window.window_id,
)),
);
} else {
let command = self.open_main_window();

return Task::batch(vec![command, self.update_audio_stream()]);
}
}
}

Task::none()
Expand Down
1 change: 1 addition & 0 deletions RustApp/src/ui/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub enum AppMsg {
RefreshAudioDevices,
RefreshNetworkAdapters,
HideWindow,
ShowWindow,
Menu(MenuMsg),
LinkClicked(String),
SystemTray(SystemTrayMsg),
Expand Down
8 changes: 5 additions & 3 deletions RustApp/src/ui/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,9 @@ static ABOUT: LazyLock<About> = LazyLock::new(|| {
});

pub fn about_window() -> Element<'static, AppMsg> {
container(widget::about(&ABOUT, AppMsg::LinkClicked))
.padding(20)
.into()
container(widget::about(&ABOUT, |url| {
AppMsg::LinkClicked(url.to_owned())
}))
.padding(20)
.into()
}
Loading