ALVR-IPv6/alvr/dashboard/src/dashboard/components/notifications.rs

150 lines
7.6 KiB
Rust

use alvr_common::{LogEntry, LogSeverity};
use alvr_gui_common::theme::{self, log_colors};
use alvr_session::Settings;
use eframe::{
egui::{self, Frame, Label, Layout, RichText, TopBottomPanel},
emath::Align,
epaint::{Color32, Stroke},
};
use rand::seq::SliceRandom;
use std::time::Duration;
#[cfg(target_arch = "wasm32")]
use instant::Instant;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
const TIMEOUT: Duration = Duration::from_secs(5);
const NO_NOTIFICATIONS_MESSAGE: &str = "No new notifications";
const NOTIFICATION_TIPS: &[&str] = &[
// The following tips are ordered roughtly in the order settings appear
r#"If you started having crashes after changing some settings, reset ALVR by deleting "session.json"."#,
r#"Some settings are hidden by default. Click the "Expand" button next to some settings to expand the submenus."#,
r#"It's highly advisable to keep audio setting as default in ALVR and modify the default audio device in the taskbar tray."#,
r#"Increasing "Maximum buffering" may reduce stutters at the cost of more latency."#,
r#"Turning off "Optimize game render latency" may improve streaming smoothness."#,
r#"Sometimes switching between h264 and HEVC codecs is necessary on certain GPUs to fix crashing or fallback to software encoding."#,
r#"If you're using NVIDIA gpu, best to use high bitrate H264, if you're using AMD gpu, HEVC might look better."#,
r#"If you experience "white snow" flickering, reduce the resolution to "Low" and disable "Foveated encoding"."#,
r#"Increasing "Color correction"->"Sharpness" may improve the perceived image quality."#,
r#"If you have problems syncing external controllers or trackers to ALVR tracking space, add one element to "Extra openvr props", then set a custom "Tracking system name"."#,
r#"To change the visual appearance of controllers, set "Controllers"->"Emulation mode"."#,
r#"ALVR supports custom button bindings! If you need help please ask us in the Discord server."#,
r#"ALVR supports hand tracking gestures. Use thumb-index/middle/ring/pinky to activate different buttons. Joystick is enabled by moving the thumb on a closed fist."#,
r#"If hand tracking gestures are annoying, you can disable them in "Controllers"->"Gestures". Alternatively you can enable "Gestures"->"Only touch"."#,
r#"You can fine-tune the controllers responsiveness with "Controllers"->"Prediction"."#,
r#"If the visual controller/hand models does not match the physical controller, you can tweak the offset in "Controllers"->"Left controller position/rotation offset" (affects both controllers)."#,
r#"When using external trackers or controllers you should set both "Position/Rotation recentering mode" to "Disabled"."#,
r#"You can enable tilt mode. Set "Position recentering mode to "Local" and "Rotation recentering mode" to "Tilted"."#,
r#"If you often experience image glitching, you can trade that with stutter frames using "Avoid video glitching"."#,
r#"You can run custom commands/programs at client connection/disconnection using "On connect/disconnect script"."#,
r#"In case you want to report a bug, to get a log file enable "Log to disk". The log will be inside "session_log.txt"."#,
r#"For hacking purposes, you can enable "Log tracking", "Log button presses", "Log haptics". You can get the data using a websocket at ws://localhost:8082/api/events"#,
r#"In case you want to report a bug and share your log, you should enable "Prefer backtrace"."#,
r#"You can quickly cycle through tips like this one by toggling "Show notification tip"."#,
r#"If you want to use body trackers or other SteamVR drivers together with ALVR, set "Driver launch action" to "Unregister ALVR at shutdown""#,
r#"It's handy to enable "Open and close SteamVR with dashboard"."#,
r#"If you want to share a video recording for reporting a bug, you can enable "Rolling video files" to limit the file size of the upload."#,
// Miscellaneous
r#"If your headset does not appear in the clients list it might be in a different subnet. Try "Add client manually"."#,
r#"For audio setup on Linux, check the wiki at https://github.com/alvr-org/ALVR/wiki/Installation-guide#automatic-audio--microphone-setup"#,
r#"ALVR supports wired connection using USB. Check the wiki at https://github.com/alvr-org/ALVR/wiki/ALVR-wired-setup-(ALVR-over-USB)"#,
r#"You can record a video of the gameplay using "Start recording" in the "Debug" category in the sidebar."#,
];
pub struct NotificationBar {
message: String,
current_level: LogSeverity,
receive_instant: Instant,
min_notification_level: LogSeverity,
tip_message: Option<String>,
expanded: bool,
}
impl NotificationBar {
pub fn new() -> Self {
Self {
message: NO_NOTIFICATIONS_MESSAGE.into(),
current_level: LogSeverity::Debug,
receive_instant: Instant::now(),
min_notification_level: LogSeverity::Debug,
tip_message: None,
expanded: false,
}
}
pub fn update_settings(&mut self, settings: &Settings) {
self.min_notification_level = settings.logging.notification_level;
if settings.logging.show_notification_tip {
if self.tip_message.is_none() {
self.tip_message = NOTIFICATION_TIPS
.choose(&mut rand::thread_rng())
.map(|s| format!("Tip: {s}"));
}
} else {
self.tip_message = None;
}
}
pub fn push_notification(&mut self, event: LogEntry) {
let now = Instant::now();
if event.severity >= self.min_notification_level
&& (now > self.receive_instant + TIMEOUT || event.severity >= self.current_level)
{
self.message = event.content;
self.current_level = event.severity;
self.receive_instant = now;
}
}
pub fn ui(&mut self, context: &egui::Context) {
let now = Instant::now();
if now > self.receive_instant + TIMEOUT {
self.message = self
.tip_message
.clone()
.unwrap_or_else(|| NO_NOTIFICATIONS_MESSAGE.into());
self.current_level = LogSeverity::Debug;
}
let (fg, bg) = match self.current_level {
LogSeverity::Error => (Color32::BLACK, log_colors::ERROR_LIGHT),
LogSeverity::Warning => (Color32::BLACK, log_colors::WARNING_LIGHT),
LogSeverity::Info => (Color32::BLACK, log_colors::INFO_LIGHT),
LogSeverity::Debug => (theme::FG, theme::LIGHTER_BG),
};
let mut bottom_bar = TopBottomPanel::bottom("bottom_panel").frame(
Frame::default()
.inner_margin(egui::vec2(10.0, 5.0))
.fill(bg)
.stroke(Stroke::new(1.0, theme::SEPARATOR_BG)),
);
let alignment = if !self.expanded {
bottom_bar = bottom_bar.max_height(26.0);
Align::TOP
} else {
Align::Center
};
bottom_bar.show(context, |ui| {
ui.with_layout(Layout::right_to_left(alignment), |ui| {
if !self.expanded {
if ui.small_button("Expand").clicked() {
self.expanded = true;
}
} else if ui.button("Reduce").clicked() {
self.expanded = false;
}
ui.with_layout(Layout::left_to_right(alignment), |ui| {
ui.add(
Label::new(RichText::new(&self.message).color(fg).size(12.0)).wrap(true),
);
})
})
});
}
}