Skip to content
Extraits de code Groupes Projets
Vérifiée Valider 5385e9d2 rédigé par Kubat's avatar Kubat
Parcourir les fichiers

AMADEUS: Fix the flickering when offline + handle user token + kurisu token...

AMADEUS: Fix the flickering when offline + handle user token + kurisu token differently + Ensure correct scale factor when saving/loading config + Store retry time duration in config file
parent 49a62a3d
Branches
Aucune étiquette associée trouvée
1 requête de fusion!197Draft: Refactor the whole code.
......@@ -650,7 +650,7 @@ impl Application for Amadeus {
Message::RefreshRequest(RefreshRequest::Playlists),
Message::ConfigMessage(config::Message::Infos(Some(infos))),
]),
Err(_) => Message::ConnectionStatus(true),
Err(_) => Message::ConnectionStatus(false),
})
}
Message::SmollTick(instant) => {
......@@ -858,8 +858,8 @@ impl Application for Amadeus {
fn subscription(&self) -> iced::Subscription<Self::Message> {
use iced::time::{every, Duration};
let (smoll_time, big_time) = either!(self.is_connected =>
(Some(Duration::new(1, 0)), Duration::new(20, 0));
(None, Duration::new(30, 0))
(Some(Duration::new(1, 0)), self.config.amadeus.retry_time_interval());
(None, self.config.amadeus.retry_time_interval())
);
let keycodes = iced::subscription::events().map(|event| match event {
Event::Keyboard(KbdEvent::KeyReleased {
......
......@@ -18,6 +18,7 @@ use iced::{
use lektor_payloads::Infos;
use lektor_utils::{
config::{SocketScheme, UserConfig},
either,
log::{self, Level as LogLevel},
logger,
};
......@@ -29,6 +30,7 @@ pub struct State {
scroll_id: scrollable::Id,
current_scroll_offset: scrollable::RelativeOffset,
tmp_retry_time: u16,
tmp_scheme: String,
tmp_host: String,
tmp_port: u16,
......@@ -38,6 +40,14 @@ pub struct State {
system_informations: Option<iced::system::Information>,
}
fn clamp_scale_factor(scale: impl Into<f64>) -> f64 {
scale.into().clamp(0.5, 1.5)
}
fn clamp_time_interval(time: impl Into<i64>) -> u16 {
time.into().clamp(10, u16::MAX as i64) as u16
}
/// Amadeus configuration.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AmadeusConfig {
......@@ -58,8 +68,16 @@ pub struct UIConfig {
pub theme: theme::Message,
#[serde(default = "serde_utils::get_1_f64")]
#[serde(serialize_with = "serde_utils::serialize_scale_factor")]
#[serde(deserialize_with = "serde_utils::deserialize_scale_factor")]
scale_factor: f64,
/// Retry interval in seconds.
#[serde(default = "serde_utils::get_20_u16")]
#[serde(serialize_with = "serde_utils::serialize_interval")]
#[serde(deserialize_with = "serde_utils::deserialize_interval")]
retry_interval_sec: u16,
#[serde(default = "serde_utils::get_true")]
pub open_config_if_init_ping_failed: bool,
}
......@@ -70,6 +88,7 @@ pub struct RemoteConfig {
pub scheme: SocketScheme,
pub host: SocketAddr,
pub user: UserConfig,
pub kurisu_token: Option<String>,
}
/// Messages used to update the config file
......@@ -121,12 +140,19 @@ pub enum Message {
/// holded a connection we now need to reconnect for sure.
TokenChanged(String),
/// The token for kurisu changed. We do this so that we can override the token from lektord
/// config with one supplied by amadeus.
KurisuTokenChanged(String),
/// Open the settings page if lektord was offline when we launched amadeus.
OpenConfigIfInitPingFailed(bool),
/// The scale factor changed.
ScaleFactorChanged(f64),
/// The retry interval time changed.
RetryIntervalChanged(u16),
/// The config was scrolled.
Scrolled(Viewport),
......@@ -158,15 +184,61 @@ pub enum Request {
impl UIConfig {
/// Get the scale factor, should only be between 0.5 and 2.0
pub fn scale_factor(&self) -> f64 {
self.scale_factor.clamp(0.5, 2.0)
clamp_scale_factor(self.scale_factor)
}
/// Get the retry time for when we are offline.
pub fn retry_time_interval(&self) -> iced::time::Duration {
iced::time::Duration::new(clamp_time_interval(self.retry_interval_sec).into(), 0)
}
}
#[rustfmt::skip]
mod serde_utils {
pub(super) fn get_1_f64() -> f64 { 1.0 }
pub(super) fn get_20_u16() -> u16 { 20 }
pub(super) fn get_true() -> bool { true }
pub(super) fn get_false() -> bool { true }
pub(super) fn serialize_scale_factor<S: serde::Serializer>(v: &f64, ser: S) -> Result<S::Ok, S::Error> { ser.serialize_f64(*v) }
pub(super) fn deserialize_scale_factor<'de, D: serde::Deserializer<'de>>(de: D) -> Result<f64, D::Error> {
struct FloadVisitor;
impl<'de> serde::de::Visitor<'de> for FloadVisitor {
type Value = f64;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("f32 or f64") }
fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_f32<E: serde::de::Error>(self, v: f32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_i8 <E: serde::de::Error>(self, v: i8 ) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
fn visit_u8 <E: serde::de::Error>(self, v: u8 ) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) }
}
de.deserialize_any(FloadVisitor)
}
pub(super) fn serialize_interval<S: serde::Serializer>(v: &u16, ser: S) -> Result<S::Ok, S::Error> { ser.serialize_u16(*v) }
pub(super) fn deserialize_interval<'de, D: serde::Deserializer<'de>>(de: D) -> Result<u16, D::Error> {
struct FloadVisitor;
impl<'de> serde::de::Visitor<'de> for FloadVisitor {
type Value = u16;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("u16") }
fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_f32<E: serde::de::Error>(self, v: f32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_i8 <E: serde::de::Error>(self, v: i8 ) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_u8 <E: serde::de::Error>(self, v: u8 ) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) }
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
Ok(super::clamp_time_interval(v.clamp(0, i64::MAX as u64) as i64))
}
}
de.deserialize_any(FloadVisitor)
}
}
impl Default for State {
......@@ -175,6 +247,7 @@ impl Default for State {
scroll_id: scrollable::Id::unique(),
current_scroll_offset: scrollable::RelativeOffset::START,
config: Default::default(),
tmp_retry_time: serde_utils::get_20_u16(),
tmp_scheme: Default::default(),
tmp_host: Default::default(),
tmp_port: Default::default(),
......@@ -198,6 +271,7 @@ impl Default for RemoteConfig {
Self {
scheme: SocketScheme::Http,
host: SocketAddr::new([127, 0, 0, 1].into(), 6600),
kurisu_token: None,
user: UserConfig {
admin: false,
..Default::default()
......@@ -243,7 +317,8 @@ impl State {
});
};
macro_rules! connect_to {
() => {
($expr: expr) => {{
$expr;
match self.tmp_host.parse() {
Ok(host) => {
config.connect.host = SocketAddr::new(host, self.tmp_port);
......@@ -251,7 +326,13 @@ impl State {
}
_ => return Command::none(),
}
};
}};
}
macro_rules! write_config {
($reload: expr, $expr: expr) => {{
$expr;
self.write_config($reload)
}};
}
match message {
Message::None | Message::OpenLinkInBrowser(_) => {
......@@ -270,6 +351,7 @@ impl State {
SocketAddr::V6(v6) => (v6.ip().to_string(), v6.port()),
};
self.tmp_scheme = new.connect.scheme.to_string();
self.tmp_retry_time = clamp_time_interval(new.amadeus.retry_interval_sec);
*config = new;
// Some times we add things to the config, we need to re-write the config when we
// load it completly to apply the new defaults.
......@@ -282,54 +364,51 @@ impl State {
Command::none()
}
Message::OpenConfigIfInitPingFailed(flag) => {
config.amadeus.open_config_if_init_ping_failed = flag;
self.write_config(Request::None)
}
Message::ScaleFactorChanged(scale) => {
config.amadeus.scale_factor = scale.clamp(0.5, 2.0);
self.write_config(Request::None)
}
Message::OpenConfigIfInitPingFailed(flag) => write_config!(
Request::None,
config.amadeus.open_config_if_init_ping_failed = flag
),
Message::RetryIntervalChanged(interval) => write_config!(Request::None, {
config.amadeus.retry_interval_sec = interval;
self.tmp_retry_time = interval;
}),
Message::ScaleFactorChanged(scale) => write_config!(
Request::None,
config.amadeus.scale_factor = clamp_scale_factor(scale)
),
Message::ThemeChanged(theme) => {
config.amadeus.theme = theme;
self.write_config(Request::None)
write_config!(Request::None, config.amadeus.theme = theme)
}
Message::UserChanged(user) => {
config.connect.user.user = user;
self.write_config(Request::Reconnect)
write_config!(Request::Reconnect, config.connect.user.user = user)
}
Message::TokenChanged(token) => {
config.connect.user.token = token;
self.write_config(Request::Reconnect)
}
Message::LogLevelChanged(level) => {
config.log = level;
logger::level(level);
self.write_config(Request::None)
write_config!(Request::Reconnect, config.connect.user.token = token)
}
Message::KurisuTokenChanged(token) => write_config!(
Request::Reconnect,
config.connect.kurisu_token = either!(token.is_empty() => None; Some(token))
),
Message::MprisFlagChanged(flag) => {
config.mpris = flag;
self.write_config(Request::ToggleMprisServer(flag))
write_config!(Request::ToggleMprisServer(flag), config.mpris = flag)
}
Message::LogLevelChanged(level) => write_config!(Request::None, {
config.log = level;
logger::level(level);
}),
Message::SchemeChanged(scheme) => {
self.tmp_scheme = scheme.to_string();
if let Ok(scheme) = scheme.parse() {
config.connect.scheme = scheme;
return self.write_config(Request::None);
}
write_config!(Request::None, config.connect.scheme = scheme)
} else {
Command::none()
}
Message::PortChanged(port) => {
self.tmp_port = port;
connect_to!()
}
Message::HostChanged(host) => {
self.tmp_host = host;
connect_to!()
}
Message::PortChanged(port) => connect_to!(self.tmp_port = port),
Message::HostChanged(host) => connect_to!(self.tmp_host = host),
Message::Scrolled(viewport) => {
self.current_scroll_offset = viewport.relative_offset();
Command::none()
......@@ -342,10 +421,16 @@ impl State {
($name: literal => [ $($content: expr),+ $(,)? ]) => {
Some(container(column![
text(concat!("# ", $name)).size(SIZE_FONT_MEDIUM),
vertical_space(10),
vertical_space(5),
$($content),+,
vertical_space(20)
]).width(Length::Fixed(500.0)))
vertical_space(15)
].spacing(5)).width(Length::Fixed(500.0)))
};
}
macro_rules! elem_row {
($title: literal, $what: expr) => {
row![text($title), horizontal_space(Length::Fill), $what]
};
}
......@@ -358,20 +443,21 @@ impl State {
]
.align_items(Alignment::Start),
input!(@$what $($portion)?; $($args),+ => $event),
vertical_space(10),
vertical_space(5),
]
};
(@number $($portion: literal)?; $tip: expr, $value: expr, $min: expr, $max: expr => $event: ident) => {
(@number $($portion: literal)?; $tip: expr, $value: expr => $event: ident) => {
text_input($tip, &$value.to_string())
$(.width(Length::Fixed($portion)))?
.size(SIZE_FONT_NORMAL)
.padding(5)
.on_input(|str| {
match str.parse() {
Ok(int) if ($min..=$max).contains(&int) => Message::$event(int),
_ => Message::None,
}
.on_input(|str| if str.trim().is_empty() {
Message::$event(Default::default())
} else {
str.trim().parse()
.map(Message::$event)
.unwrap_or(Message::None)
})
};
......@@ -393,10 +479,6 @@ impl State {
};
}
let token_link =
icon!(SIZE_FONT_SMALL | Link -> Message::OpenLinkInBrowser(KURISU_TOKEN_LINK))
.padding(0);
macro_rules! scale_factor {
($factor: literal, $($factors: literal),+) => {
row![scale_factor!($factor), $(scale_factor!($factors)),+]
......@@ -416,18 +498,19 @@ impl State {
};
}
let token_link =
icon!(SIZE_FONT_SMALL | Link -> Message::OpenLinkInBrowser(KURISU_TOKEN_LINK))
.padding(0);
let content = container([
section![ "Misc" => [
self.loglevel.view(self.config.log).map(Message::LogLevelChanged),
vertical_space(5),
toggler(Some("MPRIS server".into()), self.config.mpris, Message::MprisFlagChanged)
.spacing(15)
.text_size(SIZE_FONT_NORMAL)
.size(SIZE_FONT_NORMAL),
]],
section![ "Amadeus" => [
self.theme.view(&self.config.amadeus.theme).map(Message::ThemeChanged),
vertical_space(5),
toggler(
Some("Open settings when lektord is offline on launch".into()),
self.config.amadeus.open_config_if_init_ping_failed,
......@@ -435,21 +518,14 @@ impl State {
)
.text_size(SIZE_FONT_NORMAL)
.size(SIZE_FONT_NORMAL),
vertical_space(5),
row![
text("Scale factor").size(SIZE_FONT_NORMAL),
horizontal_space(Length::Fill),
scale_factor! { 0.5, 1.0, 1.5, 2.0 }
],
elem_row!["Scale factor", scale_factor! { 0.5, 0.75, 1.0, 1.25, 1.5 }],
input!(number! "Retry interval (sec)", "seconds", self.tmp_retry_time => RetryIntervalChanged),
]],
section![ "Remote" => [
row![
input!(text! (100.0) "Scheme", "http", &self.tmp_scheme => SchemeChanged),
horizontal_space(Length::Fixed(1.0)),
input!(text! (270.0) "Host", "host", &self.tmp_host => HostChanged),
horizontal_space(Length::Fixed(1.0)),
input!(number! (100.0) "Port", "6600", self.tmp_port, 1024, u16::max_value() => PortChanged),
horizontal_space(Length::Fill),
input!(number! (100.0) "Port", "6600", self.tmp_port => PortChanged),
column![
tip!(button(text(iced_aw::graphics::icons::icon_to_char(iced_aw::graphics::icons::Icon::Check))
.horizontal_alignment(Horizontal::Center)
......@@ -463,66 +539,34 @@ impl State {
None => Box::<SquareButtonStyleSheet>::default(),
}
)).on_press(Message::TryConnect) => Right | " Try to connect"),
vertical_space(10)
vertical_space(5)
]
]
.spacing(1)
.align_items(Alignment::End)
.width(Length::Fixed(500.0)),
input!(text! "User", "user", &self.config.connect.user.user => UserChanged),
input!(password! "Token" token_link, KURISU_TOKEN_LINK, &self.config.connect.user.token => TokenChanged),
input!(password! "Token", "token", &self.config.connect.user.token => TokenChanged),
input!(password! "Kurisu Token" token_link, KURISU_TOKEN_LINK,
self.config.connect.kurisu_token.as_ref().map(|token| token.as_str()).unwrap_or_default()
=> KurisuTokenChanged
),
]],
match &self.remote_infos {
Some(Some(infos)) => section![ "Remote Infos" => [
row![
text("Server version").size(SIZE_FONT_NORMAL),
horizontal_space(Length::Fill),
text(&infos.version).size(SIZE_FONT_NORMAL),
],
row![
text("Database epoch").size(SIZE_FONT_NORMAL),
horizontal_space(Length::Fill),
text(infos.last_epoch.map(|x| x.to_string().into()).unwrap_or(Cow::Borrowed("None"))).size(SIZE_FONT_NORMAL),
],
elem_row!["Server version", text(&infos.version)],
elem_row!["Database epoch", text(infos.last_epoch.map(|x| x.to_string().into()).unwrap_or(Cow::Borrowed("None")))],
]],
_ => None,
},
match &self.system_informations {
Some(sys) => section! [ "System Infos" => [
row![
text("System name"),
horizontal_space(Length::Fill),
text(sys.system_name.as_deref().unwrap_or("...")),
],
vertical_space(5),
row![
text("Kernel name"),
horizontal_space(Length::Fill),
text(sys.system_kernel.as_deref().unwrap_or("..")),
],
vertical_space(5),
row![
text("System version"),
horizontal_space(Length::Fill),
text(sys.system_version.as_deref().unwrap_or("..")),
],
vertical_space(5),
row![
text("CPU"),
horizontal_space(Length::Fill),
text(format!("{}, {} cores", sys.cpu_brand.as_str(), sys.cpu_cores.unwrap_or(1))),
],
vertical_space(5),
row![
text("Total memory"),
horizontal_space(Length::Fill),
text(format!("{}GiB", sys.memory_total / (1024 * 1024 * 1024))),
],
vertical_space(5),
row![
text("Graphics backend and adapter"),
horizontal_space(Length::Fill),
text(format!("{}, {}", sys.graphics_backend, sys.graphics_adapter)),
],
elem_row!["System name", text(sys.system_name.as_deref().unwrap_or("..."))],
elem_row!["Kernel name", text(sys.system_kernel.as_deref().unwrap_or("..."))],
elem_row!["System version", text(sys.system_version.as_deref().unwrap_or("..."))],
elem_row!["CPU", text(format!("{}, {} cores", sys.cpu_brand.as_str(), sys.cpu_cores.unwrap_or(1)))],
elem_row!["Total memory", text(format!("{}GiB", sys.memory_total / (1024 * 1024 * 1024)))],
elem_row!["Graphics backend and adapter", text(format!("{}, {}", sys.graphics_backend, sys.graphics_adapter))],
]],
_ => None,
}
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter