diff --git a/assets/invisible.png b/assets/invisible.png new file mode 100644 index 00000000..2547b3f0 Binary files /dev/null and b/assets/invisible.png differ diff --git a/phira/locales/en-US/song.ftl b/phira/locales/en-US/song.ftl index 6a146f53..bb939b34 100644 --- a/phira/locales/en-US/song.ftl +++ b/phira/locales/en-US/song.ftl @@ -128,3 +128,5 @@ stabilize-approved = Approved stabilize-approved-passed = The chart has been stabilized. stabilize-denied = Denied stabilize-denied-passed = Denied, the beatmap is rejected + +report = Report \ No newline at end of file diff --git a/phira/locales/vi-VN/settings.ftl b/phira/locales/vi-VN/settings.ftl index 860962f3..80b009fa 100644 --- a/phira/locales/vi-VN/settings.ftl +++ b/phira/locales/vi-VN/settings.ftl @@ -62,4 +62,4 @@ about-content = Cảm ơn tất cả các nhà tài trợ của chúng tôi! (Sắp xếp theo từ điển) -哎喂哟-, 114514opkl, 123165, 341819481, 43167364miku, AEsir, Afterglow, akuanoneko, amstlkqp, ApecY176, Arashi, Ark小周, Aromq, Atariter, Aurora., Avencess, Bigironpig, Bradish, brightquasar, buguwu, ccw., CH06E01, CQBZ, Dagehoo, DongZheng, dslzhz, Dumbledore防重复, Ehdiwhxishs, Enigma, evmb, Fall_Li_distance, flamo, Fly段某, Gentle Emperor, GR-17, GYuuLT, Hen77777Tai, hibikip3p, huahbas, huanle, humosu, icyfish, Jerry24, Jiangling, jike, Kaji Emperor, KevinJame1, KKZN, KQ_KongQi, KRYSGCJ, Kynovter, LemonKnife, Lh_39_master, Lighear, liminghao, Lin124, Lio_the_Fox, LJMSTKZF, lorac, luftsch1oss, Maedey, mancy, MaxJack, MGRB, Miku.official, Miska1123, MSSkn, NaiTaGQ, NananEbina, nanxiangx, NEROILY, NingNing0721, NoChoco, Nothu, NsdrfChkew, O-DouSan, obsession, pgwcm, Phira-一个随意废物, PopCatNya, QAQwhatever, QingF_青枫, qwer0160, QWQYuRin, rainbowbex, Ransen, Reeslith, Requiem, RinceTacroix, Rinorsi, Rpec, RUNFORFUNQAQ, sbcujbj, Sensant, Shaaadowsong, Sixi, sksks, Sky_Frozen, soppi, Tearout, Tesla T-T, Thunderlis, Tigerzzz, Tixbicg, Tony0703, Ulyssses, Wind_And_Sky, wjxwp, wszyj, WuJi, wylwktd, xiaoqian, xiaozhemu, XOO_cookie, Xr888, yang125, YMiiiiiii, YN呓凝, YT_XT, yulilizi, yyyyyylll, ZERO707, Zips, ほしの アイ, 一片普通的茶叶, 三月鸠, 不会玩音游的屑, 久往大魔王, 乙酸乙烯酯, 二货甜鱼, 傲丙初A1bcu, 冷光_Lumine, 华树邶, 四十四次日落, 城边的一朵云, 天启之云, 如月清风, 小懒max, 小鲁班, 幻枫落晨, 御坂13900号, 心兮可念, 悲伤很菜, 我永远喜欢爱莉希雅, 日暖随安, 早安起不早, 明晓破风, 易阳Easy_sun, 晨曜, 曲奇cookies, 望悅不是月, 林江恒, 柒柒柒柒, 梓川川川川川川, 欧皇本蝗, 残风, 洛尘sama, 灵晨没有准度, 炫金创创鹅, 甘城猫猫猫猫, 男德村村西张寡妇, 白衣炫五月, 老王, 芝士土拨鼠, 若笛, 荷叶鸭腿, 落弦winglow, 落痕luor, 逐潘, 邮疣铀, 银酱, 露西亚是我的, 飞驰的压路机, 骁龙750G -Dịch bởi @Natelyt \ No newline at end of file + Dịch bởi @Natelyt \ No newline at end of file diff --git a/phira/locales/zh-CN/song.ftl b/phira/locales/zh-CN/song.ftl index 15e50670..9f16ac27 100644 --- a/phira/locales/zh-CN/song.ftl +++ b/phira/locales/zh-CN/song.ftl @@ -126,3 +126,5 @@ stabilize-approved = 已通过 stabilize-approved-passed = 已通过,谱面已 stable stabilize-denied = 已拒绝 stabilize-denied-passed = 已拒绝,谱面已打回 + +report = 举报 \ No newline at end of file diff --git a/phira/src/icons.rs b/phira/src/icons.rs index 7c22675c..60d5f47e 100644 --- a/phira/src/icons.rs +++ b/phira/src/icons.rs @@ -15,6 +15,7 @@ pub struct Icons { pub download: SafeTexture, pub user: SafeTexture, pub info: SafeTexture, + pub invisible: SafeTexture, pub delete: SafeTexture, pub menu: SafeTexture, pub edit: SafeTexture, @@ -43,6 +44,7 @@ impl Icons { download: load_texture("download.png").await?.into(), user: load_texture("user.png").await?.into(), info: load_texture("info.png").await?.into(), + invisible: load_texture("invisible.png").await?.into(), delete: load_texture("delete.png").await?.into(), menu: load_texture("menu.png").await?.into(), edit: load_texture("edit.png").await?.into(), diff --git a/phira/src/scene/song.rs b/phira/src/scene/song.rs index 2a6a22df..6a68fb87 100644 --- a/phira/src/scene/song.rs +++ b/phira/src/scene/song.rs @@ -66,6 +66,9 @@ use uuid::Uuid; use walkdir::WalkDir; use zip::{write::FileOptions, CompressionMethod, ZipWriter}; +mod action_panel; +use action_panel::ActionPanel; + // Things that need to be reloaded for chart info updates type LocalTuple = (String, ChartInfo, AudioClip, Illustration); @@ -78,6 +81,23 @@ static CONFIRM_OVERWRITE: AtomicBool = AtomicBool::new(false); static CONFIRM_UPLOAD: AtomicBool = AtomicBool::new(false); pub static RECORD_ID: AtomicI32 = AtomicI32::new(-1); +fn fit_in_rect(rect: Rect, texture: &SafeTexture) -> Rect { + let w = texture.width(); + let h = texture.height(); + let ratio = h / w; + let current_size = rect.size(); + let mut new_size = Vec2::default(); + if current_size.x < current_size.y / ratio { + new_size.x = current_size.x; + new_size.y = current_size.x * ratio; + } else { + new_size.x = current_size.y / ratio; + new_size.y = current_size.y; + } + let center = rect.center(); + Rect::new(center.x - new_size.x / 2., center.y - new_size.y / 2., new_size.x, new_size.y) +} + fn create_music(clip: AudioClip) -> Result { let mut music = UI_AUDIO.with(|it| { it.borrow_mut().create_music( @@ -208,6 +228,11 @@ impl SideContent { } } +enum SongSceneMode { + Player, + Staff, +} + #[derive(Deserialize)] struct StableR { status: i8, @@ -256,10 +281,17 @@ pub struct SongScene { should_delete: Arc, menu_options: Vec<&'static str>, + hide_gui_btn: RectButton, + hide_gui: bool, + info_edit: Option, edit_btn: RectButton, edit_scroll: Scroll, + action_scroll: Scroll, + action_panel: ActionPanel, + scene_mode: SongSceneMode, + mods: Mods, mod_btn: RectButton, mod_scroll: Scroll, @@ -283,6 +315,7 @@ pub struct SongScene { info_scroll: Scroll, review_task: Option>>, + report_task: Option>>, chart_should_delete: Arc, edit_tags_task: Option>>, @@ -310,6 +343,7 @@ pub struct SongScene { tr_start: f32, open_web_btn: DRectButton, + report_btn: DRectButton, // Imported chart for overwriting overwrite_from: Option, @@ -409,6 +443,9 @@ impl SongScene { fetch_best_task, + hide_gui_btn: RectButton::new(), + hide_gui: false, + menu: Popup::new(), menu_btn: RectButton::new(), need_show_menu: false, @@ -419,6 +456,10 @@ impl SongScene { edit_btn: RectButton::new(), edit_scroll: Scroll::new(), + scene_mode: SongSceneMode::Player, + action_panel: ActionPanel::new(), + action_scroll: Scroll::new(), + mods, mod_btn: RectButton::new(), mod_scroll: Scroll::new(), @@ -444,6 +485,8 @@ impl SongScene { review_task: None, chart_should_delete: Arc::default(), + report_task: None, + edit_tags_task: None, tags: TagsDialog::new(false), @@ -483,6 +526,8 @@ impl SongScene { open_web_btn: DRectButton::new(), + report_btn: DRectButton::new(), + overwrite_from: None, overwrite_task: None, @@ -917,8 +962,8 @@ impl SongScene { { warn!("this build does not support unlock video."); LoadingScene::new(mode, info, config, fs, player, upload_fn, update_fn, Some(preload)) - .await - .map(|it| NextScene::Overlay(Box::new(it))) + .await + .map(|it| NextScene::Overlay(Box::new(it))) } #[cfg(feature = "video")] { @@ -1090,6 +1135,8 @@ impl SongScene { let r = Rect::new(0.03, 0., mw, 0.12).nonuniform_feather(-0.03, -0.01); self.open_web_btn.render_text(ui, r, rt, ttl!("open-in-web"), 0.6, true); dy!(r.h + 0.04); + self.report_btn.render_text(ui, r, rt, tl!("report"), 0.6, true); + dy!(r.h + 0.04); } if let Some(uploader) = &self.info.uploader { let c = 0.06; @@ -1368,6 +1415,10 @@ impl Scene for SongScene { { return Ok(true); } + if self.hide_gui { + self.hide_gui = false; + return Ok(true); + } if self.downloading.is_some() { if let Some(dl) = &mut self.downloading { if dl.touch(touch, t) { @@ -1378,6 +1429,10 @@ impl Scene for SongScene { return Ok(false); } let rt = tm.real_time() as f32; + if self.hide_gui_btn.touch(touch) { + self.hide_gui = true; + return Ok(true); + } if self.tags.touch(touch, rt) { return Ok(true); } @@ -1388,6 +1443,10 @@ impl Scene for SongScene { self.menu.touch(touch, t); return Ok(true); } + self.action_panel.touch(touch, t); + if self.action_scroll.touch(touch, t) { + return Ok(true) + } if !self.side_enter_time.is_infinite() { if self.side_enter_time > 0. && tm.real_time() as f32 > self.side_enter_time + EDIT_TRANSIT { if touch.position.x < 1. - self.side_content.width() && touch.phase == TouchPhase::Started && self.save_task.is_none() { @@ -1446,6 +1505,10 @@ impl Scene for SongScene { open_url(&format!("https://phira.moe/chart/{}", self.info.id.unwrap()))?; return Ok(true); } + if self.report_btn.touch(touch, rt) { + request_input("report_reason", tl!("report-reason").as_ref()); + return Ok(true); + } } SideContent::Mods => { if self.mod_scroll.touch(touch, t) { @@ -1524,6 +1587,8 @@ impl Scene for SongScene { let rt = tm.real_time() as f32; self.tags.update(rt); self.rate_dialog.update(rt); + self.action_scroll.update(t); + self.action_panel.update(tm); if self.tags.confirmed.take() == Some(true) { let mut tags = self.tags.tags.tags().to_vec(); tags.push(self.tags.division.to_owned()); @@ -2021,6 +2086,19 @@ impl Scene for SongScene { .into()) })); } + "report-reason" => { + let id = self.info.id.unwrap(); + self.report_task = Some(Task::new(async move { + recv_raw(Client::post( + format!("/chart/{id}/report"), + &json!({ + "reason": text, + }), + )) + .await?; + Ok(()) + })); + } _ => return_input(id, text), } } @@ -2107,6 +2185,19 @@ impl Scene for SongScene { self.review_task = None; } } + if let Some(task) = &mut self.report_task { + if let Some(res) = task.take() { + match res { + Err(err) => { + show_error(err.context(tl!("report-failed"))); + } + Ok(_) => { + show_message(tl!("report-requested")).ok(); + } + } + self.review_task = None; + } + } if let Some(task) = &mut self.edit_tags_task { if let Some(res) = task.take() { match res { @@ -2167,19 +2258,41 @@ impl Scene for SongScene { fn render(&mut self, tm: &mut TimeManager, ui: &mut Ui) -> Result<()> { set_camera(&ui.camera()); let t = tm.now() as f32; + ui.fill_rect(ui.screen_rect(), (*self.illu.texture.1, ui.screen_rect())); ui.fill_rect(ui.screen_rect(), semi_black(0.55)); - - let r = ui.back_rect(); - self.back_btn.set(ui, r); - ui.fill_rect(r, (*self.icons.back, r, ScaleType::Fit)); + if self.hide_gui { + let in_rect = fit_in_rect(ui.screen_rect(), &self.illu.texture.1); + ui.fill_rect(in_rect, (*self.illu.texture.1, in_rect, ScaleType::Inside)); + } + if let Some(dl) = &mut self.downloading { + dl.render(ui, t); + } + if self.save_task.is_some() { + ui.full_loading(tl!("edit-saving"), t); + } + if self.upload_task.is_some() { + ui.full_loading(tl!("uploading"), t); + } + if self.review_task.is_some() { + ui.full_loading(tl!("review-doing"), t); + } + if self.edit_tags_task.is_some() || self.rate_task.is_some() || self.overwrite_task.is_some() || self.update_cksum_task.is_some() { + ui.full_loading("", t); + } + if self.hide_gui { + return Ok(()); + } + let back_r = ui.back_rect(); + self.back_btn.set(ui, back_r); + ui.fill_rect(back_r, (*self.icons.back, back_r, ScaleType::Fit)); ui.alpha::>(((t - self.fade_start) / FADE_IN_TIME).clamp(-1., 0.) + 1., |ui| { let r = ui .text(&self.info.name) - .max_width(0.57 - r.right()) + .max_width(0.57 - back_r.right()) .size(1.2) - .pos(r.right() + 0.02, r.y) + .pos(back_r.right() + 0.02, back_r.y) .draw(); ui.text(&self.info.composer) .size(0.5) @@ -2238,6 +2351,17 @@ impl Scene for SongScene { r.w += 0.13; self.ldb_btn.set(ui, r); } + ui.scope(|ui| { + let pad = 0.05; + ui.dy(back_r.bottom() + 0.07); + ui.dx(back_r.right() + 0.02 -pad); + let size = (0.8,r.top()-back_r.bottom()-0.1); + self.action_scroll.size(size); + self.action_scroll.render(ui, |ui| { + ui.dx(pad); + self.action_panel.render(ui, 0.8, t) + }); + }); // play button let w = 0.26; @@ -2286,12 +2410,12 @@ impl Scene for SongScene { } ui.fill_rect(r, (*self.icons.r#mod, r, ScaleType::Fit, if self.local_path.is_some() { WHITE } else { cc })); self.mod_btn.set(ui, r); + ui.dx(-r.w - 0.03); + ui.fill_rect(r, (*self.icons.invisible, r, ScaleType::Fit, if self.menu_options.is_empty() { cc } else { WHITE })); + self.hide_gui_btn.set(ui, r); }); - if let Some(dl) = &mut self.downloading { - dl.render(ui, t); - } - + // side content let rt = tm.real_time() as f32; if self.side_enter_time.is_finite() { let p = ((rt - self.side_enter_time.abs()) / EDIT_TRANSIT).min(1.); @@ -2329,18 +2453,6 @@ impl Scene for SongScene { self.menu.render(ui, t, 1.); - if self.save_task.is_some() { - ui.full_loading(tl!("edit-saving"), t); - } - if self.upload_task.is_some() { - ui.full_loading(tl!("uploading"), t); - } - if self.review_task.is_some() { - ui.full_loading(tl!("review-doing"), t); - } - if self.edit_tags_task.is_some() || self.rate_task.is_some() || self.overwrite_task.is_some() || self.update_cksum_task.is_some() { - ui.full_loading("", t); - } let rt = tm.real_time() as f32; self.tags.render(ui, rt); self.rate_dialog.render(ui, rt); diff --git a/phira/src/scene/song/action_panel.rs b/phira/src/scene/song/action_panel.rs new file mode 100644 index 00000000..17d375fd --- /dev/null +++ b/phira/src/scene/song/action_panel.rs @@ -0,0 +1,89 @@ +use macroquad::{input::Touch, math::Rect}; +use prpr::{ext::semi_black, time::TimeManager, ui::{DRectButton, Ui}}; +use tracing::debug; + +pub struct ActionPanel { + buttonl: DRectButton, + buttonr: DRectButton, + last_height: f32, + last_width: f32, +} + + +impl ActionPanel { + pub fn new() -> Self { + Self { + buttonl: DRectButton::new(), + buttonr: DRectButton::new(), + last_height:0.2, + last_width:0. + } + } + pub fn render(&mut self,ui: &mut Ui,width: f32, t:f32,) -> (f32, f32) { + let mut sy = 0.02; + let h_pad = 0.01; + let w_pad = 0.01; + ui.scope(|ui| { + ui.dy(sy); + let y_top = sy-h_pad; + ui.fill_rect(Rect::new(-2.0*w_pad, 0., self.last_width + 5.0*w_pad, self.last_height), semi_black(0.5)); + macro_rules! dy { + ($dy:expr) => {{ + let dy = $dy; + sy += dy; + ui.dy(dy); + }}; + } + macro_rules! gain_w { + ($w:expr) => { + let w = $w; + self.last_width = f32::max(self.last_width, w); + }; + } + macro_rules! item { + ($item:expr) => { + let r = $item; + dy!(r.h + h_pad); + gain_w!(r.w); + }; + ($item:expr, $pad:expr) => { + let r = $item; + dy!(r.h + $pad); + gain_w!(r.w); + } + } + dy!(h_pad); + let r = ui.text("Stable stat:").size(0.7).draw(); + ui.dx(r.w + w_pad); + let w2 = ui.text("test text").size(0.7).draw().w; + ui.dx(-r.w-w_pad); + gain_w!(r.w + w_pad + w2); + dy!(r.h + h_pad); + self.buttonl.render_text(ui, Rect::new(0., 0., 0.25, 0.075), t, "Test1", 0.6, true); + ui.dx(0.25 + w_pad); + self.buttonr.render_text(ui, Rect::new(0., 0., 0.25, 0.075), t, "Test", 0.6, true); + ui.dx(-(0.25 + w_pad)); + dy!(0.075 + h_pad); + gain_w!(0.5); + item!(ui.text("Title").size(0.74).draw()); + item!(ui.text("This is an update").size(0.7).draw(), 2.*h_pad); + item!(ui.checkbox("测试", &mut true)); + item!(ui.checkbox("测试", &mut true)); + item!(ui.checkbox("测试", &mut true)); + item!(ui.checkbox("测试", &mut true)); + }); + self.last_height = sy + h_pad; + (self.last_width, sy) + } + pub fn touch(&mut self,touch: &Touch, t:f32) { + if self.buttonl.touch(touch, t) { + debug!("touched test button") + } + if self.buttonr.touch(touch, t) { + debug!("touched test button") + } + } + pub fn update(&mut self, tm: &mut TimeManager) { + + } +} \ No newline at end of file