pub mod gradient_backdrop;
pub mod play_pause_icon;
pub mod time_text;
pub mod video_progress_bar;
use crate::drawing::{Drawable, Plan};
use crate::layouts::{EdgeLayout, EdgeLayoutElement, Edges, HasPlanner, Layout};
use crate::story_board::{StoryBoard, easing};
use skia_safe::{Canvas, Color, Color4f, Font, Paint, PaintStyle, PathBuilder, Point, Rect};
use std::cell::RefCell;
use std::f64::consts::PI;
use std::rc::Rc;
use gradient_backdrop::GradientBackdrop;
use play_pause_icon::PlayPauseIcon;
use time_text::TimeText;
use video_progress_bar::VideoProgressBar;
pub struct PlayBar {
sh_state: RefCell<StoryBoard>,
internal_layout: Rc<EdgeLayout>,
icon: Rc<PlayPauseIcon>,
progress: Rc<VideoProgressBar>,
text: Rc<TimeText>,
planner: RefCell<Option<Rc<dyn Layout>>>,
}
impl HasPlanner for PlayBar {
fn planner(&self) -> &RefCell<Option<Rc<dyn Layout>>> {
&self.planner
}
fn set_planner(&self, p: Option<Rc<dyn Layout>>) {
*self.planner.borrow_mut() = p;
}
}
impl Layout for PlayBar {
fn measure_child(&self, _c: &dyn Drawable, canvas: &Canvas) -> Rect {
self.get_planned_drawing_area(canvas)
}
}
impl Drawable for PlayBar {
fn draw(&self, canvas: &Canvas) -> anyhow::Result<()> {
let slide_offset = f64::from(&*self.sh_state.borrow()) as f32;
canvas.save();
canvas.translate(Point::new(0.0, slide_offset));
self.internal_layout.draw(canvas)?;
canvas.restore();
Ok(())
}
fn get_horizontal_plan(&self) -> Plan {
Plan::Fill
}
fn get_vertical_plan(&self) -> Plan {
Plan::Fill
}
}
impl PlayBar {
pub fn new(current_time: i64, video_length: i64, font: &Font) -> Rc<Self> {
let internal_layout = EdgeLayout::new();
let mut ring_paint = Paint::default();
ring_paint
.set_anti_alias(true)
.set_style(PaintStyle::Stroke)
.set_stroke_width(3.0)
.set_color4f(Color4f::new(0.26, 0.52, 0.96, 0.9), None);
let mut bg_paint = Paint::default();
bg_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(1.0, 1.0, 1.0, 0.2), None);
let mut progress_paint = Paint::default();
progress_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(0.26, 0.52, 0.96, 1.0), None);
let mut thumb_paint = Paint::default();
thumb_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(1.0, 1.0, 1.0, 1.0), None);
let mut text_paint = Paint::default();
text_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(0.95, 0.95, 0.95, 1.0), None);
let mut shadow_paint = Paint::default();
shadow_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(0.0, 0.0, 0.0, 0.6), None);
let mut icon_paint = Paint::default();
icon_paint.set_anti_alias(true);
let size = 9.0;
let mut builder = PathBuilder::new();
builder.move_to(Point::new(-size * 0.3, -size * 0.9));
builder.line_to(Point::new(size * 0.8, 0.0));
builder.line_to(Point::new(-size * 0.3, size * 0.9));
let backdrop = Rc::new(GradientBackdrop {
colors: [Color::from_argb(0, 0, 0, 0), Color::from_argb(199, 0, 0, 0)],
planner: RefCell::new(None),
});
let icon = Rc::new(PlayPauseIcon {
is_paused: RefCell::new(true),
pp_state: RefCell::new(StoryBoard::init(
0f64,
1f64,
200f64,
false,
easing::cubic_in_out,
)),
rotation_state: RefCell::new(StoryBoard::init(
0f64,
2f64 * PI,
3000f64,
true,
easing::linear,
)),
play_path: builder.detach(),
ring_paint,
icon_paint,
planner: RefCell::new(None),
});
let progress = Rc::new(VideoProgressBar {
current_time: RefCell::new(current_time),
video_length: RefCell::new(video_length),
bg_paint,
progress_paint,
thumb_paint,
planner: RefCell::new(None),
});
let text = Rc::new(TimeText {
current_time: RefCell::new(current_time),
video_length: RefCell::new(video_length),
font: font.clone(),
text_paint,
shadow_paint,
planner: RefCell::new(None),
});
internal_layout.add_child(
"backdrop",
EdgeLayoutElement {
drawable: backdrop.clone(),
l_edge: Edges::Left,
l_margin: 0.0,
r_edge: Edges::Right,
r_margin: 0.0,
t_edge: Edges::Bottom,
t_margin: 75.0,
b_edge: Edges::Bottom,
b_margin: 0.0,
},
);
internal_layout.add_child(
"icon",
EdgeLayoutElement {
drawable: icon.clone(),
l_edge: Edges::Left,
l_margin: 40.0,
r_edge: Edges::Left,
r_margin: 76.0, t_edge: Edges::Bottom,
t_margin: 45.0, b_edge: Edges::Bottom,
b_margin: 9.0,
},
);
internal_layout.add_child(
"progress",
EdgeLayoutElement {
drawable: progress.clone(),
l_edge: Edges::Left,
l_margin: 94.0, r_edge: Edges::Right,
r_margin: 40.0,
t_edge: Edges::Bottom,
t_margin: 30.0,
b_edge: Edges::Bottom,
b_margin: 24.0,
},
);
internal_layout.add_child(
"text",
EdgeLayoutElement {
drawable: text.clone(),
l_edge: Edges::Left,
l_margin: 94.0,
r_edge: Edges::Right,
r_margin: 40.0,
t_edge: Edges::Bottom,
t_margin: 62.0,
b_edge: Edges::Bottom,
b_margin: 42.0, },
);
let instance = Rc::new(Self {
sh_state: RefCell::new(StoryBoard::init(
100f64,
0f64,
500f64,
false,
easing::cubic_in_out,
)),
internal_layout: internal_layout.clone(),
icon,
progress,
text,
planner: RefCell::new(None),
});
internal_layout.set_planner(Some(instance.clone() as Rc<dyn Layout>));
instance
}
pub fn to_layout_element(self: &Rc<Self>) -> EdgeLayoutElement {
EdgeLayoutElement {
drawable: self.clone(),
l_edge: Edges::Left,
l_margin: 0.0,
r_edge: Edges::Right,
r_margin: 0.0,
b_edge: Edges::Bottom,
b_margin: 0.0,
t_edge: Edges::Bottom,
t_margin: 75.0,
}
}
pub fn set_status(&self, is_paused: bool, current_time: i64, video_length: i64) {
let mut is_paused_lock = self.icon.is_paused.borrow_mut();
if *is_paused_lock != is_paused {
self.icon.pp_state.borrow_mut().restart();
}
*is_paused_lock = is_paused;
*self.progress.current_time.borrow_mut() = current_time;
*self.progress.video_length.borrow_mut() = video_length;
*self.text.current_time.borrow_mut() = current_time;
*self.text.video_length.borrow_mut() = video_length;
}
pub fn toggle_sh(&self) {
let mut sh = self.sh_state.borrow_mut();
sh.reverse();
sh.restart();
}
}