feat: added funfacts changing on background change (#718)
Co-authored-by: rozwader <maciek.rozwadowski2006@gmail.com>
This commit is contained in:
parent
578ec187cd
commit
efed361417
4 changed files with 76 additions and 11 deletions
|
|
@ -232,6 +232,17 @@ impl Actions {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn reset_onboarding(&self) {
|
||||
if let Some(updated) = self.mutate_settings(|settings| {
|
||||
settings.seen_onboarding = false;
|
||||
settings.accepted_tos_version = 0;
|
||||
settings.accepted_privacy_version = 0;
|
||||
settings.seen_versions.clear();
|
||||
}) {
|
||||
self.persist(updated);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accept_tos(&self, terms_version: u32, privacy_version: u32) {
|
||||
if let Some(updated) = self.mutate_settings(|settings| {
|
||||
settings.accepted_tos_version = terms_version;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use oneclient_auth::preview_samples;
|
|||
use oneclient_core::simulate::Damage;
|
||||
use oneclient_net::status::{self, ServiceStatus};
|
||||
|
||||
use crate::Actions;
|
||||
use crate::components::{Button, Dropdown, Icon, IconType, TextInput, login_dialog, toggle};
|
||||
use crate::hooks::use_dispatch;
|
||||
use crate::notifications::{
|
||||
|
|
@ -22,6 +23,7 @@ pub struct Debug;
|
|||
|
||||
impl Component for Debug {
|
||||
fn render(&self) -> impl IntoElement {
|
||||
let dispatch = use_dispatch();
|
||||
let log_debug_info = use_state(|| false);
|
||||
let show_dev_stuff = use_state(|| false);
|
||||
let seen_onboarding = use_state(|| true);
|
||||
|
|
@ -97,7 +99,7 @@ impl Component for Debug {
|
|||
.child(divider())
|
||||
.child(section(
|
||||
"Other",
|
||||
vec![action_row(vec![
|
||||
vec![action_row(&dispatch, vec![
|
||||
("Open Dev Tools", IconType::CodeSnippet02),
|
||||
("Open Onboarding", IconType::Rocket02),
|
||||
("Open Launcher Data", IconType::Folder),
|
||||
|
|
@ -1142,7 +1144,7 @@ fn toggle_row(title: &'static str, on: State<bool>) -> Element {
|
|||
.into_element()
|
||||
}
|
||||
|
||||
fn action_row(buttons: Vec<(&'static str, IconType)>) -> Element {
|
||||
fn action_row(dispatch: &Actions, buttons: Vec<(&'static str, IconType)>) -> Element {
|
||||
let mut row = rect().horizontal().width(Size::fill()).spacing(12.);
|
||||
|
||||
for (text, icon) in buttons {
|
||||
|
|
@ -1152,6 +1154,7 @@ fn action_row(buttons: Vec<(&'static str, IconType)>) -> Element {
|
|||
.text(text);
|
||||
|
||||
if text == "Open Onboarding" {
|
||||
dispatch.reset_onboarding();
|
||||
button = button.on_press(|_| {
|
||||
let _ = RouterContext::get().replace(Route::OnboardingWelcome {});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use super::*;
|
|||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use oneclient_core::clusters::Cluster;
|
||||
|
||||
|
|
@ -11,7 +11,24 @@ use crate::hooks::use_settings_snapshot;
|
|||
use crate::layout::gradient_overlay_radial;
|
||||
use crate::theme::colors;
|
||||
|
||||
const BACKDROP_INTERVAL_SECS: u64 = 12;
|
||||
pub(super) const BACKDROP_INTERVAL_SECS: u64 = 12;
|
||||
|
||||
const ROTATION_PERIOD: Duration = Duration::from_secs(BACKDROP_INTERVAL_SECS);
|
||||
|
||||
fn since_epoch() -> Duration {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or(Duration::ZERO)
|
||||
}
|
||||
|
||||
pub(super) fn rotation_tick() -> usize {
|
||||
(since_epoch().as_secs() / BACKDROP_INTERVAL_SECS) as usize
|
||||
}
|
||||
|
||||
pub(super) fn next_rotation_delay() -> Duration {
|
||||
let into_period = since_epoch().as_nanos() % ROTATION_PERIOD.as_nanos();
|
||||
ROTATION_PERIOD - Duration::from_nanos(into_period as u64)
|
||||
}
|
||||
|
||||
const PARALLAX_SCALE: f32 = 1.10;
|
||||
const PARALLAX_STRENGTH: f32 = 0.008;
|
||||
|
|
@ -28,7 +45,10 @@ impl Component for LoadingBackdrop {
|
|||
fn render(&self) -> impl IntoElement {
|
||||
let clusters = &self.clusters;
|
||||
let count = clusters.len().max(1);
|
||||
let mut index = use_state(|| 0usize);
|
||||
// Offset against the shared tick so the first art shown is still the
|
||||
// first cluster
|
||||
let start = use_hook(rotation_tick);
|
||||
let mut tick = use_state(rotation_tick);
|
||||
|
||||
let stop = use_hook(|| Arc::new(AtomicBool::new(false)));
|
||||
|
||||
|
|
@ -46,20 +66,19 @@ impl Component for LoadingBackdrop {
|
|||
|
||||
spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(BACKDROP_INTERVAL_SECS)).await;
|
||||
tokio::time::sleep(next_rotation_delay()).await;
|
||||
|
||||
if stop.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
|
||||
let next = (*index.peek() + 1) % count;
|
||||
index.set(next);
|
||||
tick.set(rotation_tick());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let current = *index.read() % count;
|
||||
let current = (*tick.read()).wrapping_sub(start) % count;
|
||||
|
||||
let parallax_enabled = use_settings_snapshot().settings.dynamic_background_enabled;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
use super::*;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use super::backdrop::{next_rotation_delay, rotation_tick};
|
||||
use crate::theme::colors;
|
||||
|
||||
const ONBOARDING_TIPS_BACKUP: &[&str] = &[
|
||||
|
|
@ -35,7 +39,7 @@ fn parse_funfacts(text: &str) -> Vec<String> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// One stable random tip for the lifetime of the component
|
||||
/// A random tip that rotates in step with the backdrop art
|
||||
pub(super) fn use_onboarding_tip() -> String {
|
||||
let mut tips = use_state(|| {
|
||||
ONBOARDING_TIPS_BACKUP
|
||||
|
|
@ -78,18 +82,46 @@ pub(super) fn use_onboarding_tip() -> String {
|
|||
});
|
||||
});
|
||||
|
||||
// Random offset against the shared tick so the run does not always open on
|
||||
// the same fact
|
||||
let seed = use_hook(|| {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.subsec_nanos() as usize)
|
||||
.unwrap_or(0)
|
||||
});
|
||||
let mut tick = use_state(rotation_tick);
|
||||
|
||||
let stop = use_hook(|| Arc::new(AtomicBool::new(false)));
|
||||
|
||||
use_drop({
|
||||
let stop = stop.clone();
|
||||
move || stop.store(true, Ordering::Relaxed)
|
||||
});
|
||||
|
||||
use_hook({
|
||||
let stop = stop.clone();
|
||||
move || {
|
||||
spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(next_rotation_delay()).await;
|
||||
|
||||
if stop.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
|
||||
tick.set(rotation_tick());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Wrapped at read time the list is swapped out once the remote facts land
|
||||
let list = tips.read();
|
||||
if list.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
list[seed % list.len()].clone()
|
||||
list[seed.wrapping_add(*tick.read()) % list.len()].clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue