Add tab transitions
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
047c8e08c0
commit
3a6b9713f9
1 changed files with 120 additions and 41 deletions
|
@ -1,9 +1,14 @@
|
|||
use std::{
|
||||
rc::Rc,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use rand::{rngs::OsRng, seq::IndexedRandom, TryRngCore};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use ratzilla::ratatui;
|
||||
|
||||
use ratatui::{
|
||||
layout::{Constraint, Direction, Layout},
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Style, Stylize},
|
||||
widgets::{Block, Borders, Paragraph, Tabs},
|
||||
Frame,
|
||||
|
@ -15,10 +20,51 @@ use crate::app::password_locker::PasswordLocker;
|
|||
|
||||
mod password_locker;
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct SelectedTab {
|
||||
currently_selected: Rc<AtomicUsize>,
|
||||
transitioning_to: Rc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Shader for SelectedTab {
|
||||
fn name(&self) -> &'static str {
|
||||
"selected_tab"
|
||||
}
|
||||
|
||||
fn execute(
|
||||
&mut self,
|
||||
_duration: tachyonfx::Duration,
|
||||
_area: Rect,
|
||||
_buf: &mut ratatui::prelude::Buffer,
|
||||
) {
|
||||
self.currently_selected.store(
|
||||
self.transitioning_to.load(Ordering::Relaxed),
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
|
||||
fn done(&self) -> bool {
|
||||
self.currently_selected.load(Ordering::Relaxed)
|
||||
== self.transitioning_to.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn Shader> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn area(&self) -> Option<Rect> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set_area(&mut self, _area: Rect) {}
|
||||
|
||||
fn filter(&mut self, _filter: tachyonfx::CellFilter) {}
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
tabs: [&'static str; 3],
|
||||
transition_instant: Instant,
|
||||
selected_tab: usize,
|
||||
selected_tab: SelectedTab,
|
||||
password_locker: PasswordLocker,
|
||||
current_effect: Effect,
|
||||
}
|
||||
|
@ -68,57 +114,71 @@ impl App {
|
|||
Self {
|
||||
tabs: TABS.choose_multiple_array(&mut OsRng.unwrap_err()).unwrap(),
|
||||
transition_instant: Instant::now(),
|
||||
selected_tab: 0,
|
||||
selected_tab: SelectedTab::default(),
|
||||
password_locker: PasswordLocker::default(),
|
||||
current_effect: fx::fade_from_fg(Color::Black, (0, Interpolation::CircIn)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, frame: &mut Frame) {
|
||||
if self.password_locker.unlocked() {
|
||||
self.draw_rest(frame);
|
||||
}
|
||||
self.draw_passcode(frame);
|
||||
let area = frame.area();
|
||||
|
||||
self.current_effect.process(
|
||||
self.transition_instant.elapsed().into(),
|
||||
frame.buffer_mut(),
|
||||
area,
|
||||
);
|
||||
}
|
||||
let layout = Layout::new(
|
||||
Direction::Vertical,
|
||||
[Constraint::Length(3), Constraint::Min(0)],
|
||||
)
|
||||
.split(area);
|
||||
|
||||
pub fn draw_passcode(&mut self, frame: &mut Frame) {
|
||||
frame.render_widget(&mut self.password_locker, frame.area());
|
||||
if self.password_locker.unlocked() {
|
||||
frame.render_widget(
|
||||
Tabs::new(self.tabs)
|
||||
.select(self.selected_tab.transitioning_to.load(Ordering::Relaxed))
|
||||
.fg(Color::Rgb(226, 190, 89))
|
||||
.bg(Color::Black)
|
||||
.highlight_style(Style::new().bold())
|
||||
.block(Block::new().borders(Borders::all()).title("Coming soon")),
|
||||
layout[0],
|
||||
);
|
||||
|
||||
match self.selected_tab.currently_selected.load(Ordering::Relaxed) {
|
||||
0 => self.draw_first_tab(frame, layout[1]),
|
||||
1 | 2 => self.draw_second_tab(frame, layout[1]),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
frame.render_widget(&mut self.password_locker, area);
|
||||
if let Some(cursor_position) = self.password_locker.cursor_position() {
|
||||
if self.password_locker.current_effect_done() {
|
||||
frame.set_cursor_position(cursor_position);
|
||||
}
|
||||
}
|
||||
|
||||
self.current_effect.process(
|
||||
self.transition_instant.elapsed().into(),
|
||||
frame.buffer_mut(),
|
||||
layout[1],
|
||||
);
|
||||
}
|
||||
|
||||
pub fn draw_rest(&mut self, frame: &mut Frame) {
|
||||
let layout = Layout::new(
|
||||
Direction::Vertical,
|
||||
[Constraint::Length(3), Constraint::Min(0)],
|
||||
)
|
||||
.split(frame.area());
|
||||
frame.render_widget(
|
||||
Tabs::new(self.tabs)
|
||||
.select(self.selected_tab)
|
||||
.fg(Color::Rgb(226, 190, 89))
|
||||
.bg(Color::Black)
|
||||
.highlight_style(Style::new().bold())
|
||||
.block(Block::new().borders(Borders::all()).title("Coming soon")),
|
||||
layout[0],
|
||||
);
|
||||
pub fn draw_first_tab(&mut self, frame: &mut Frame, layout: Rect) {
|
||||
frame.render_widget(
|
||||
Paragraph::new(SPLASH)
|
||||
.alignment(ratatui::layout::Alignment::Center)
|
||||
.fg(Color::Rgb(226, 190, 89))
|
||||
.bg(Color::Black)
|
||||
.block(Block::new().borders(Borders::all())),
|
||||
layout[1],
|
||||
layout,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn draw_second_tab(&mut self, frame: &mut Frame, layout: Rect) {
|
||||
frame.render_widget(
|
||||
Block::new()
|
||||
.borders(Borders::all())
|
||||
.fg(Color::Rgb(226, 190, 89))
|
||||
.bg(Color::Black),
|
||||
layout,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -127,20 +187,39 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn next_tab(&mut self) {
|
||||
self.transition_instant = Instant::now();
|
||||
if self.selected_tab == self.tabs.len() - 1 {
|
||||
self.selected_tab = 0;
|
||||
} else {
|
||||
self.selected_tab += 1;
|
||||
if self
|
||||
.selected_tab
|
||||
.transitioning_to
|
||||
.fetch_add(1, Ordering::Relaxed)
|
||||
== self.tabs.len() - 1
|
||||
{
|
||||
self.selected_tab
|
||||
.transitioning_to
|
||||
.store(0, Ordering::Relaxed);
|
||||
}
|
||||
self.tab_transition();
|
||||
}
|
||||
|
||||
pub fn prev_tab(&mut self) {
|
||||
self.transition_instant = Instant::now();
|
||||
if self.selected_tab == 0 {
|
||||
self.selected_tab = self.tabs.len() - 1;
|
||||
} else {
|
||||
self.selected_tab -= 1;
|
||||
if self
|
||||
.selected_tab
|
||||
.transitioning_to
|
||||
.fetch_sub(1, Ordering::Relaxed)
|
||||
== 0
|
||||
{
|
||||
self.selected_tab
|
||||
.transitioning_to
|
||||
.store(self.tabs.len() - 1, Ordering::Relaxed);
|
||||
}
|
||||
self.tab_transition();
|
||||
}
|
||||
|
||||
fn tab_transition(&mut self) {
|
||||
self.transition_instant = Instant::now();
|
||||
self.current_effect = fx::sequence(&[
|
||||
fx::dissolve((5000, Interpolation::Linear)),
|
||||
Effect::new(self.selected_tab.clone()),
|
||||
fx::coalesce((10000, Interpolation::Linear)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue