Skip to content

Commit 5e234c7

Browse files
committed
feat: add message actions
1 parent 75b216f commit 5e234c7

5 files changed

Lines changed: 144 additions & 17 deletions

File tree

phira/src/charts_view.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
client::{Chart, ChartRef},
55
dir, get_data, get_data_mut,
66
icons::Icons,
7-
page::{ChartItem, ChartType, Fader, Illustration, CHOOSE_COVER, CHOSEN_COVER},
7+
page::{ChartItem, Fader, CHOOSE_COVER, CHOSEN_COVER},
88
popup::Popup,
99
save_data,
1010
scene::{render_release_to_refresh, SongScene, MP_PANEL},
@@ -59,12 +59,7 @@ impl ChartDisplayItem {
5959

6060
pub fn from_remote(chart: &Chart) -> Self {
6161
Self::new(
62-
Some(ChartItem {
63-
info: chart.to_info(),
64-
illu: Illustration::from_file_thumbnail(chart.illustration.clone()),
65-
local_path: None,
66-
chart_type: ChartType::Downloaded,
67-
}),
62+
Some(ChartItem::from_remote(chart)),
6863
if chart.stable_request {
6964
Some('+')
7065
} else if !chart.reviewed {

phira/src/client/model/message.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use chrono::{DateTime, Utc};
22
use serde::Deserialize;
33

4+
#[derive(Deserialize)]
5+
pub struct MessageAction {
6+
pub name: String,
7+
pub action: String,
8+
}
9+
410
#[derive(Deserialize)]
511
#[allow(dead_code)]
612
pub struct Message {
@@ -9,4 +15,6 @@ pub struct Message {
915
pub content: String,
1016
pub author: String,
1117
pub time: DateTime<Utc>,
18+
#[serde(default)]
19+
pub actions: Vec<MessageAction>,
1220
}

phira/src/page.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub use settings::SettingsPage;
2727
use tokio::sync::Notify;
2828

2929
use crate::{
30-
client::{ChartRef, File},
30+
client::{Chart, ChartRef, File},
3131
data::BriefChartInfo,
3232
dir, get_data,
3333
images::Images,
@@ -214,6 +214,15 @@ impl ChartItem {
214214
pub fn to_ref(&self) -> ChartRef {
215215
ChartRef::new_bare(self.info.id, self.local_path.as_deref())
216216
}
217+
218+
pub fn from_remote(chart: &Chart) -> Self {
219+
ChartItem {
220+
info: chart.to_info(),
221+
illu: Illustration::from_file_thumbnail(chart.illustration.clone()),
222+
local_path: None,
223+
chart_type: ChartType::Downloaded,
224+
}
225+
}
217226
}
218227

219228
#[derive(Clone, Copy)]

phira/src/page/home.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ impl Page for HomePage {
410410
return Ok(true);
411411
}
412412
if self.btn_msg.touch(touch, t) {
413-
self.next_page = Some(NextPage::Overlay(Box::new(MessagePage::new())));
413+
self.next_page = Some(NextPage::Overlay(Box::new(MessagePage::new(Arc::clone(&self.icons), s.icons.clone()))));
414414
return Ok(true);
415415
}
416416
if self.btn_settings.touch(touch, t) {

phira/src/page/message.rs

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
prpr_l10n::tl_file!("message");
22

3-
use std::borrow::Cow;
3+
use std::{borrow::Cow, sync::Arc};
44

55
use super::{Page, SharedState};
66
use crate::{
7-
client::{recv_raw, Client, Message},
8-
get_data, get_data_mut, save_data,
7+
client::{recv_raw, Chart, Client, Message, Ptr},
8+
get_data, get_data_mut,
9+
icons::Icons,
10+
page::{ChartItem, SFader},
11+
save_data,
12+
scene::{ProfileScene, SongScene},
913
};
1014
use anyhow::Result;
1115
use chrono::Local;
1216
use macroquad::prelude::*;
1317
use prpr::{
14-
ext::{semi_black, semi_white, RectExt},
18+
ext::{open_url, semi_black, semi_white, RectExt, SafeTexture},
1519
scene::show_error,
1620
task::Task,
1721
ui::{DRectButton, Scroll, Ui},
@@ -25,10 +29,17 @@ pub struct MessagePage {
2529

2630
btns_scroll: Scroll,
2731
scroll: Scroll,
32+
33+
action_btns: Vec<DRectButton>,
34+
35+
sf: SFader,
36+
chart_task: Option<Task<Result<Arc<Chart>>>>,
37+
icons: Arc<Icons>,
38+
rank_icons: [SafeTexture; 8],
2839
}
2940

3041
impl MessagePage {
31-
pub fn new() -> Self {
42+
pub fn new(icons: Arc<Icons>, rank_icons: [SafeTexture; 8]) -> Self {
3243
Self {
3344
msgs: None,
3445
load_task: None,
@@ -37,6 +48,13 @@ impl MessagePage {
3748

3849
btns_scroll: Scroll::new(),
3950
scroll: Scroll::new(),
51+
52+
action_btns: Vec::new(),
53+
54+
sf: SFader::new(),
55+
chart_task: None,
56+
icons,
57+
rank_icons,
4058
}
4159
}
4260

@@ -53,6 +71,46 @@ impl MessagePage {
5371
Ok(recv_raw(req).await?.json().await?)
5472
}));
5573
}
74+
75+
fn execute_action(&mut self, t: f32, action: String) -> Result<()> {
76+
let (ty, param) = match action.split_once(':') {
77+
Some(it) => it,
78+
None => {
79+
warn!("invalid action: {action}");
80+
return Ok(());
81+
}
82+
};
83+
match ty {
84+
"url" => {
85+
open_url(param)?;
86+
}
87+
"chart" => {
88+
let id = match param.parse::<i32>() {
89+
Ok(it) => it,
90+
Err(_) => {
91+
warn!("invalid chart id: {param}");
92+
return Ok(());
93+
}
94+
};
95+
self.chart_task = Some(Task::new(async move { Ptr::<Chart>::new(id).fetch().await }));
96+
}
97+
"user" => {
98+
let id = match param.parse::<i32>() {
99+
Ok(it) => it,
100+
Err(_) => {
101+
warn!("invalid user id: {param}");
102+
return Ok(());
103+
}
104+
};
105+
self.sf.goto(t, ProfileScene::new(id, self.icons.user.clone(), self.rank_icons.clone()));
106+
}
107+
_ => {
108+
warn!("unknown action type: {ty}");
109+
}
110+
}
111+
112+
Ok(())
113+
}
56114
}
57115

58116
impl Page for MessagePage {
@@ -67,6 +125,9 @@ impl Page for MessagePage {
67125

68126
fn touch(&mut self, touch: &Touch, s: &mut SharedState) -> Result<bool> {
69127
let t = s.t;
128+
if self.chart_task.is_some() {
129+
return Ok(false);
130+
}
70131
if self.load_task.is_none() {
71132
if self.btns_scroll.touch(touch, t) {
72133
return Ok(true);
@@ -86,6 +147,15 @@ impl Page for MessagePage {
86147
return Ok(true);
87148
}
88149
}
150+
if let Some(index) = self.index {
151+
for (btn, action) in self.action_btns.iter_mut().zip(&msgs[index].0.actions) {
152+
if btn.touch(touch, t) {
153+
let action = action.action.clone();
154+
self.execute_action(t, action)?;
155+
return Ok(true);
156+
}
157+
}
158+
}
89159
}
90160
}
91161
if self.scroll.touch(touch, t) {
@@ -118,6 +188,29 @@ impl Page for MessagePage {
118188
self.load_task = None;
119189
}
120190
}
191+
if self.chart_task.is_some() {
192+
if let Some(res) = self.chart_task.as_mut().unwrap().take() {
193+
match res {
194+
Err(err) => {
195+
show_error(err);
196+
}
197+
Ok(chart) => {
198+
let data = get_data();
199+
let (local_path, mods) = data
200+
.charts
201+
.iter()
202+
.find(|it| it.info.id == Some(chart.id))
203+
.map(|it| (Some(it.local_path.clone()), it.mods))
204+
.unwrap_or_default();
205+
self.sf.goto(
206+
t,
207+
SongScene::new(ChartItem::from_remote(chart.as_ref()), local_path, self.icons.clone(), self.rank_icons.clone(), mods),
208+
);
209+
}
210+
}
211+
self.chart_task = None;
212+
}
213+
}
121214
Ok(())
122215
}
123216

@@ -162,10 +255,24 @@ impl Page for MessagePage {
162255
});
163256
s.render_fader(ui, |ui| {
164257
ui.fill_path(&cr.rounded(0.005), semi_black(0.4));
165-
let pad = 0.03;
166-
ui.dx(cr.x + pad + 0.01);
167-
ui.dy(cr.y + pad);
258+
168259
if let Some(msg) = self.index.and_then(|it| self.msgs.as_ref().map(|msgs| &msgs[it].0)) {
260+
let pad = 0.03;
261+
ui.scope(|ui| {
262+
ui.dx(cr.right() - pad);
263+
ui.dy(cr.bottom() - pad);
264+
self.action_btns.resize_with(msg.actions.len(), DRectButton::new);
265+
let mut r = Rect::new(0., 0., 0.28, 0.1);
266+
r.x -= r.w;
267+
r.y -= r.h;
268+
for (btn, action) in self.action_btns.iter_mut().zip(&msg.actions) {
269+
btn.render_text(ui, r, t, &action.name, 0.5, false);
270+
ui.dy(-r.h - 0.01);
271+
}
272+
});
273+
274+
ui.dx(cr.x + pad + 0.01);
275+
ui.dy(cr.y + pad);
169276
let mw = cr.w - pad * 2. - 0.01;
170277
let mut h = 0.;
171278
macro_rules! dy {
@@ -193,6 +300,14 @@ impl Page for MessagePage {
193300
});
194301
}
195302
});
303+
self.sf.render(ui, t);
304+
if self.chart_task.is_some() {
305+
ui.full_loading_simple(t);
306+
}
196307
Ok(())
197308
}
309+
310+
fn next_scene(&mut self, s: &mut SharedState) -> prpr::scene::NextScene {
311+
self.sf.next_scene(s.t).unwrap_or_default()
312+
}
198313
}

0 commit comments

Comments
 (0)