diff --git a/phira/locales/en-US/settings.ftl b/phira/locales/en-US/settings.ftl index 4c3bbb983..d4f00b7fb 100644 --- a/phira/locales/en-US/settings.ftl +++ b/phira/locales/en-US/settings.ftl @@ -41,6 +41,7 @@ item-sfx = SFX Volume item-bgm = BGM Volume item-cali = Adjust Offset item-preferred-sample-rate = Preferred Sample Rate +item-audio-buffer-size = Audio Buffer Size item-show-acc = Real-Time Accuracy item-show-avg-fps = Show AVG FPS diff --git a/phira/locales/zh-CN/settings.ftl b/phira/locales/zh-CN/settings.ftl index 1f76869d2..08c920a53 100644 --- a/phira/locales/zh-CN/settings.ftl +++ b/phira/locales/zh-CN/settings.ftl @@ -41,6 +41,7 @@ item-sfx = 音效音量 item-bgm = BGM 音量 item-cali = 调整延迟 item-preferred-sample-rate = 首选采样率 +item-audio-buffer-size = 音频缓冲区大小 item-show-acc = 显示实时准度 item-show-avg-fps = 显示平均帧率 diff --git a/phira/src/lib.rs b/phira/src/lib.rs index fde235606..7d001f3c3 100644 --- a/phira/src/lib.rs +++ b/phira/src/lib.rs @@ -498,14 +498,7 @@ pub fn set_chosen_file(file: String) { #[cfg(target_env = "ohos")] #[napi] -pub fn mark_import() { +pub fn mark_auto_import() { use prpr::scene::CHOSEN_FILE; - CHOSEN_FILE.lock().unwrap().0 = Some("_import".to_owned()); -} - -#[cfg(target_env = "ohos")] -#[napi] -pub fn mark_import_respack() { - use prpr::scene::CHOSEN_FILE; - CHOSEN_FILE.lock().unwrap().0 = Some("_import_respack".to_owned()); + CHOSEN_FILE.lock().unwrap().0 = Some("_import_auto".to_owned()); } diff --git a/phira/src/page/library.rs b/phira/src/page/library.rs index 13017bbca..08c3c4a02 100644 --- a/phira/src/page/library.rs +++ b/phira/src/page/library.rs @@ -506,6 +506,8 @@ fn request_export() { EXPORT_PICKER_PATH.lock().unwrap().replace(output_path_str); } EXPORT_CONFIG.lock().unwrap().replace(config); + } else if #[cfg(target_env = "ohos")] { + miniquad::native::call_request_callback(format!("{{\"action\":\"request_export\",\"filename\":\"{}\"}}", suggested_name)); } else { if let Some(output_path) = rfd::FileDialog::new().set_title(tl!("multi-export-title")).set_file_name(&suggested_name).save_file() { let config = File::create(&output_path).map(|file| ExportConfig { @@ -542,6 +544,22 @@ extern "system" fn process_export_fd(env: jni::JNIEnv, _: jni::objects::JClass, })); } +#[cfg(target_env = "ohos")] +mod ohos_export { + use super::*; + use napi_derive_ohos::napi; + #[napi] + #[allow(dead_code)] + pub fn process_export_fd_ohos(fd: u32) { + use std::os::fd::FromRawFd; + let file = unsafe { File::from_raw_fd(fd as _) }; + EXPORT_CONFIG.lock().unwrap().replace(Ok(ExportConfig { + file, + deleter: Box::new(|| Ok(())), + })); + } +} + impl Page for LibraryPage { fn label(&self) -> Cow<'static, str> { tl!("label") diff --git a/phira/src/page/settings.rs b/phira/src/page/settings.rs index f40f85c04..5262c16e3 100644 --- a/phira/src/page/settings.rs +++ b/phira/src/page/settings.rs @@ -272,7 +272,7 @@ struct GeneralList { lang_btn: ChooseButton, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))] fullscreen_btn: DRectButton, cache_btn: DRectButton, @@ -306,7 +306,7 @@ impl GeneralList { .unwrap_or_default(), ), - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))] fullscreen_btn: DRectButton::new(), cache_btn: DRectButton::new(), @@ -364,7 +364,7 @@ impl GeneralList { return Ok(Some(false)); } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))] if self.fullscreen_btn.touch(touch, t) { config.fullscreen_mode ^= true; @@ -475,7 +475,7 @@ impl GeneralList { self.lang_btn.render(ui, rr, t); } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))] item! { render_title(ui, tl!("item-fullscreen"), None); render_switch(ui, rr, t, &mut self.fullscreen_btn, config.fullscreen_mode); @@ -537,6 +537,8 @@ struct AudioList { cali_btn: DRectButton, #[cfg(not(target_os = "android"))] preferred_sample_rate_btn: DRectButton, + #[cfg(target_env = "ohos")] + audio_buffer_size_btn: DRectButton, cali_task: LocalTask>, next_page: Option, } @@ -551,6 +553,8 @@ impl AudioList { cali_btn: DRectButton::new(), #[cfg(not(target_os = "android"))] preferred_sample_rate_btn: DRectButton::new(), + #[cfg(target_env = "ohos")] + audio_buffer_size_btn: DRectButton::new(), cali_task: None, next_page: None, @@ -593,6 +597,14 @@ impl AudioList { config.preferred_sample_rate = options[(selected + 1) % options.len()]; return Ok(Some(true)); } + #[cfg(target_env = "ohos")] + if self.audio_buffer_size_btn.touch(touch, t) { + let options = [128u32, 256u32, 512u32]; + let current = config.audio_buffer_size.unwrap_or(256); + let selected = options.iter().position(|&r| r == current).unwrap_or(1); + config.audio_buffer_size = Some(options[(selected + 1) % options.len()]); + return Ok(Some(true)); + } Ok(None) } @@ -650,6 +662,12 @@ impl AudioList { render_title(ui, tl!("item-preferred-sample-rate"), None); self.preferred_sample_rate_btn.render_text(ui, rr, t, format!("{} Hz", config.preferred_sample_rate), 0.5, false); } + #[cfg(target_env = "ohos")] + item! { + render_title(ui, tl!("item-audio-buffer-size"), None); + let buf_size = config.audio_buffer_size.unwrap_or(256); + self.audio_buffer_size_btn.render_text(ui, rr, t, format!("{}", buf_size), 0.5, false); + } (w, h) } diff --git a/phira/src/scene/main.rs b/phira/src/scene/main.rs index b8efa79b3..6422698d4 100644 --- a/phira/src/scene/main.rs +++ b/phira/src/scene/main.rs @@ -358,6 +358,19 @@ impl Scene for MainScene { } if let Some((id, file)) = take_file() { match id.as_str() { + "_import_auto" => { + let new_id = match File::open(&file).map(BufReader::new).map(zip::ZipArchive::new) { + Ok(Ok(zip)) => { + if zip.file_names().any(|name| name.ends_with("click.png")) { + "_import_respack" + } else { + "_import" + } + } + _ => "_import", + }; + return_file(new_id.to_owned(), file); + } "_import" => { let export_info = (|| -> Result> { let file = File::open(&file)?; diff --git a/prpr/src/config.rs b/prpr/src/config.rs index 2e58a5c35..ebca62602 100644 --- a/prpr/src/config.rs +++ b/prpr/src/config.rs @@ -80,7 +80,7 @@ impl Default for Config { particle: true, player_name: "Mivik".to_string(), player_rks: 15., - preferred_sample_rate: 44100, + preferred_sample_rate: if cfg!(target_env = "ohos") { 48000 } else { 44100 }, res_pack_path: None, sample_count: 1, show_acc: false, diff --git a/prpr/src/ext.rs b/prpr/src/ext.rs index 74ad42359..614488cd9 100644 --- a/prpr/src/ext.rs +++ b/prpr/src/ext.rs @@ -389,7 +389,7 @@ pub fn screen_aspect() -> f32 { let vp = get_viewport(); vp.2 as f32 / vp.3 as f32 } - +// This function is used to create in-game audio manager pub fn create_audio_manger(config: &Config) -> Result { #[cfg(target_os = "android")] { @@ -404,8 +404,8 @@ pub fn create_audio_manger(config: &Config) -> Result { { use sasa::backend::ohos::*; AudioManager::new(OhosBackend::new(OhosSettings { - buffer_size: Some(256), - sample_rate: Some(config.preferred_sample_rate), + sample_rate: config.preferred_sample_rate.into(), + buffer_size: config.audio_buffer_size.or(Some(256)), channels: 2, })) } diff --git a/prpr/src/judge.rs b/prpr/src/judge.rs index 65fdda932..a3dbfc861 100644 --- a/prpr/src/judge.rs +++ b/prpr/src/judge.rs @@ -151,7 +151,7 @@ pub enum Judgement { Miss, } -#[cfg(any(not(closed), target_os = "windows", target_os = "linux"))] +#[cfg(any(not(closed), all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos"))))] #[derive(Default)] pub(crate) struct JudgeInner { diffs: Vec, @@ -162,7 +162,7 @@ pub(crate) struct JudgeInner { num_of_notes: u32, } -#[cfg(any(not(closed), target_os = "windows", target_os = "linux"))] +#[cfg(any(not(closed), all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos"))))] impl JudgeInner { pub fn new(num_of_notes: u32) -> Self { Self { @@ -247,9 +247,9 @@ impl JudgeInner { } #[rustfmt::skip] -#[cfg(all(closed, not(any(target_os = "windows", target_os = "linux"))))] +#[cfg(all(closed, not(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))))] pub mod inner; -#[cfg(all(closed, not(any(target_os = "windows", target_os = "linux"))))] +#[cfg(all(closed, not(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))))] use inner::*; type Judgements = Vec<(f32, u32, u32, Result)>; diff --git a/prpr/src/lib.rs b/prpr/src/lib.rs index 03c1270ed..dd999a823 100644 --- a/prpr/src/lib.rs +++ b/prpr/src/lib.rs @@ -17,7 +17,7 @@ pub mod ui; pub mod log; #[rustfmt::skip] -#[cfg(all(closed, not(any(target_os = "windows", target_os = "linux"))))] +#[cfg(all(closed, not(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))))] pub mod inner; pub use scene::Main; diff --git a/prpr/src/scene.rs b/prpr/src/scene.rs index fa13c7fbe..2591c3b4f 100644 --- a/prpr/src/scene.rs +++ b/prpr/src/scene.rs @@ -176,13 +176,7 @@ pub fn request_input(id: impl Into, mut config: InputBox) { if config.prompt.is_none() { config = config.prompt(ttl!("input-msg")); } - cfg_if! { - if #[cfg(target_env = "ohos")] { - miniquad::native::call_request_callback(r#"{"action": "show_input_window"}"#.to_string()); - } else { - show_inputbox(config, &*default_backend()); - } - } + show_inputbox(config, &*default_backend()); } pub fn take_input() -> Option<(String, String)> { @@ -196,7 +190,10 @@ pub fn return_input(id: String, text: String) { #[cfg(not(target_arch = "wasm32"))] pub fn request_file(id: impl Into) { - *CHOSEN_FILE.lock().unwrap() = (Some(id.into()), None); + let id: String = id.into(); + #[cfg(target_env = "ohos")] + let is_photo = id == "avatar"; + *CHOSEN_FILE.lock().unwrap() = (Some(id), None); cfg_if! { if #[cfg(target_os = "android")] { unsafe { @@ -299,7 +296,7 @@ pub fn request_file(id: impl Into) { .unwrap() .presentViewController_animated_completion(&picker, true, None); } else if #[cfg(target_env = "ohos")] { - miniquad::native::call_request_callback(r#"{"action": "chooseFile"}"#.to_string()); + miniquad::native::call_request_callback(format!(r#"{{"action": "chooseFile", "isPhoto": {}}}"#, is_photo)); } else { // desktop CHOSEN_FILE.lock().unwrap().1 = rfd::FileDialog::new().pick_file().map(|it| it.display().to_string()); } diff --git a/prpr/src/scene/game.rs b/prpr/src/scene/game.rs index 6aaad8152..7dff135d9 100644 --- a/prpr/src/scene/game.rs +++ b/prpr/src/scene/game.rs @@ -45,9 +45,9 @@ use tracing::{debug, warn}; const PAUSE_CLICK_INTERVAL: f32 = 0.7; #[rustfmt::skip] -#[cfg(all(closed, not(any(target_os = "windows", target_os = "linux"))))] +#[cfg(all(closed, not(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))))] mod inner; -#[cfg(all(closed, not(any(target_os = "windows", target_os = "linux"))))] +#[cfg(all(closed, not(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))))] use inner::*; const WAIT_TIME: f32 = 0.5; @@ -916,7 +916,7 @@ impl Scene for GameScene { if t >= AFTER_TIME + 0.3 { let mut record_data = None; // TODO strengthen the protection - #[cfg(all(closed, not(any(target_os = "windows", target_os = "linux"))))] + #[cfg(all(closed, not(all(any(target_os = "windows", target_os = "linux"), not(target_env = "ohos")))))] if let Some(upload_fn) = &self.upload_fn { if !self.res.config.offline_mode && !self.res.config.autoplay() && self.res.config.speed >= 1.0 - 1e-3 { if let Some(player) = &self.player { diff --git a/prpr/src/ui.rs b/prpr/src/ui.rs index 778e6ff97..29b6a9484 100644 --- a/prpr/src/ui.rs +++ b/prpr/src/ui.rs @@ -1246,7 +1246,7 @@ impl<'a> From<(Option, &'a mut f32)> for LoadingParams<'a> { } } } - +// This function is used to create UI audio manager. #[allow(clippy::blocks_in_conditions)] fn build_audio() -> AudioManager { match {