add topbar dragging! also fix a lot of perf issues with rerenders
This commit is contained in:
parent
574340749b
commit
43d76ca7a0
4 changed files with 128 additions and 69 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -2071,7 +2071,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"spirv",
|
"spirv",
|
||||||
"strum",
|
"strum 0.26.3",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
|
@ -2845,6 +2845,8 @@ dependencies = [
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"strum 0.27.1",
|
||||||
|
"strum_macros 0.27.1",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
@ -3225,9 +3227,15 @@ version = "0.26.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum_macros",
|
"strum_macros 0.26.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.27.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum_macros"
|
name = "strum_macros"
|
||||||
version = "0.26.4"
|
version = "0.26.4"
|
||||||
|
@ -3241,6 +3249,19 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.27.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "svg_fmt"
|
name = "svg_fmt"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
|
|
@ -15,6 +15,8 @@ iced_video_player = {path = "./iced_video_player"}
|
||||||
url = "2.5.4"
|
url = "2.5.4"
|
||||||
rust-embed = "8.7.0"
|
rust-embed = "8.7.0"
|
||||||
file-format = "0.26.0"
|
file-format = "0.26.0"
|
||||||
|
strum = "0.27.1"
|
||||||
|
strum_macros = "0.27.1"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true # Automatically strip symbols from the binary.
|
strip = true # Automatically strip symbols from the binary.
|
||||||
|
|
|
@ -10,27 +10,27 @@ use std::{marker::PhantomData, sync::atomic::Ordering};
|
||||||
use std::{sync::Arc, time::Instant};
|
use std::{sync::Arc, time::Instant};
|
||||||
|
|
||||||
/// Video player widget which displays the current frame of a [`Video`](crate::Video).
|
/// Video player widget which displays the current frame of a [`Video`](crate::Video).
|
||||||
pub struct VideoPlayer<Message, Theme = iced::Theme, Renderer = iced::Renderer>
|
pub struct VideoPlayer<'a, Message, Theme = iced::Theme, Renderer = iced::Renderer>
|
||||||
where
|
where
|
||||||
Renderer: PrimitiveRenderer
|
Renderer: PrimitiveRenderer
|
||||||
{
|
{
|
||||||
video: Video,
|
video: &'a Video,
|
||||||
content_fit: iced::ContentFit,
|
content_fit: iced::ContentFit,
|
||||||
width: iced::Length,
|
width: iced::Length,
|
||||||
height: iced::Length,
|
height: iced::Length,
|
||||||
on_end_of_stream: Option<Message>,
|
on_end_of_stream: Option<Message>,
|
||||||
on_new_frame: Option<Message>,
|
on_new_frame: Option<Message>,
|
||||||
on_subtitle_text: Option<Box<dyn Fn(Option<String>) -> Message>>,
|
on_subtitle_text: Option<Box<dyn Fn(Option<String>) -> Message + 'a>>,
|
||||||
on_error: Option<Box<dyn Fn(&glib::Error) -> Message>>,
|
on_error: Option<Box<dyn Fn(&glib::Error) -> Message + 'a>>,
|
||||||
_phantom: PhantomData<(Theme, Renderer)>,
|
_phantom: PhantomData<(Theme, Renderer)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, Theme, Renderer> VideoPlayer<Message, Theme, Renderer>
|
impl<'a, Message, Theme, Renderer> VideoPlayer<'a, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: PrimitiveRenderer
|
Renderer: PrimitiveRenderer
|
||||||
{
|
{
|
||||||
/// Creates a new video player widget for a given video.
|
/// Creates a new video player widget for a given video.
|
||||||
pub fn new(video: Video) -> Self {
|
pub fn new(video: &'a Video) -> Self {
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
video,
|
video,
|
||||||
content_fit: iced::ContentFit::default(),
|
content_fit: iced::ContentFit::default(),
|
||||||
|
@ -108,7 +108,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
||||||
for VideoPlayer<Message, Theme, Renderer>
|
for VideoPlayer<'_, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
Message: Clone,
|
Message: Clone,
|
||||||
Renderer: PrimitiveRenderer,
|
Renderer: PrimitiveRenderer,
|
||||||
|
@ -292,14 +292,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, Theme, Renderer> From<VideoPlayer<Message, Theme, Renderer>>
|
impl<'a, Message, Theme, Renderer> From<VideoPlayer<'a, Message, Theme, Renderer>>
|
||||||
for Element<'_, Message, Theme, Renderer>
|
for Element<'a, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
Message: 'static + Clone,
|
Message: 'a + Clone,
|
||||||
Theme: 'static,
|
Theme: 'a,
|
||||||
Renderer: 'static + PrimitiveRenderer,
|
Renderer: 'a + PrimitiveRenderer,
|
||||||
{
|
{
|
||||||
fn from(video_player: VideoPlayer<Message, Theme, Renderer>) -> Self {
|
fn from(video_player: VideoPlayer<'a, Message, Theme, Renderer>) -> Self {
|
||||||
Self::new(video_player)
|
Self::new(video_player)
|
||||||
}
|
}
|
||||||
}
|
}
|
126
src/main.rs
126
src/main.rs
|
@ -1,19 +1,19 @@
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use file_format::FileFormat;
|
use file_format::FileFormat;
|
||||||
use ::image::ImageReader;
|
use ::image::{DynamicImage, ImageReader};
|
||||||
use iced::{
|
use iced::{
|
||||||
alignment::Vertical::Top, border, gradient, mouse, widget::{button, center, column, container, image, mouse_area, row, stack, text, Column, Space}, window::{self, icon, Settings}, Alignment::Center, Color, Element, Font, Length, Point, Renderer, Size, Subscription, Task, Theme
|
alignment::Vertical::Top, border, gradient, mouse, wgpu::naga::back, widget::{button, center, column, container, image, mouse_area, row, stack, text, Column, Space}, window::{self, icon, Settings}, Alignment::Center, Color, Element, Font, Length, Point, Renderer, Size, Subscription, Task, Theme
|
||||||
};
|
};
|
||||||
use iced_video_player::{Video, VideoPlayer};
|
use iced_video_player::{Video, VideoPlayer};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
use strum_macros::EnumIter;
|
||||||
use utils::img_utils::round_image;
|
use utils::img_utils::round_image;
|
||||||
use std::{
|
use std::{
|
||||||
env, fs::{self, create_dir_all, read_to_string}, io::{Cursor, Read, Write}, path::PathBuf, sync::Arc
|
collections::HashMap, env, fs::{self, create_dir_all, read_to_string}, io::{Cursor, Read, Write}, path::PathBuf, sync::Arc
|
||||||
};
|
};
|
||||||
mod utils;
|
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use iced::event::{self, Event};
|
|
||||||
use iced::keyboard::Event as KeyboardEvent;
|
|
||||||
use iced::mouse::Event as MouseEvent;
|
|
||||||
|
|
||||||
#[derive(rust_embed::Embed)]
|
#[derive(rust_embed::Embed)]
|
||||||
#[folder = "resources"]
|
#[folder = "resources"]
|
||||||
|
@ -38,7 +38,7 @@ pub fn main() -> iced::Result {
|
||||||
max_size: None,
|
max_size: None,
|
||||||
min_size: None,
|
min_size: None,
|
||||||
visible: true,
|
visible: true,
|
||||||
resizable: true,
|
resizable: false,
|
||||||
transparent: false,
|
transparent: false,
|
||||||
level: window::Level::Normal,
|
level: window::Level::Normal,
|
||||||
exit_on_close_request: true,
|
exit_on_close_request: true,
|
||||||
|
@ -52,7 +52,7 @@ pub fn main() -> iced::Result {
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, EnumIter, Default, Serialize, Deserialize)]
|
||||||
enum PossibleGames {
|
enum PossibleGames {
|
||||||
#[default]
|
#[default]
|
||||||
WutheringWaves,
|
WutheringWaves,
|
||||||
|
@ -64,31 +64,55 @@ enum PossibleGames {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Launcher {
|
enum Launcher {
|
||||||
Loading,
|
Loading,
|
||||||
Loaded(State),
|
Loaded(Box<State>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug)]
|
||||||
|
enum LauncherBackground {
|
||||||
|
Video(Video),
|
||||||
|
Image(image::Handle),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl LauncherBackground {
|
||||||
|
fn inner(&self) -> Element<Message> {
|
||||||
|
match self {
|
||||||
|
LauncherBackground::Video(video) => VideoPlayer::new(video).into(),
|
||||||
|
LauncherBackground::Image(handle) => image(handle).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
struct State {
|
struct State {
|
||||||
selected_game: PossibleGames,
|
selected_game: PossibleGames,
|
||||||
installed_games: Vec<PossibleGames>,
|
installed_games: Vec<PossibleGames>,
|
||||||
installed_game_servers: Vec<PossibleGames>,
|
installed_game_servers: Vec<PossibleGames>,
|
||||||
db_software_installed: bool,
|
db_software_installed: bool,
|
||||||
|
background: Option<LauncherBackground>,
|
||||||
|
icon_images: HashMap<PossibleGames, image::Handle>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
struct SavedState {
|
struct SavedState {
|
||||||
installed_games: Vec<PossibleGames>,
|
installed_games: Vec<PossibleGames>,
|
||||||
installed_game_servers: Vec<PossibleGames>,
|
installed_game_servers: Vec<PossibleGames>,
|
||||||
db_software_installed: bool,
|
db_software_installed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SavedState> for Box<State> {
|
||||||
|
fn from(val: SavedState) -> Self {
|
||||||
|
Box::new(State { installed_games: val.installed_games, installed_game_servers: val.installed_game_servers, db_software_installed: val.db_software_installed, ..State::default() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum LoadError {
|
enum LoadError {
|
||||||
File,
|
File,
|
||||||
Format,
|
Format,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
enum SaveError {
|
enum SaveError {
|
||||||
Write,
|
Write,
|
||||||
Format,
|
Format,
|
||||||
|
@ -96,7 +120,7 @@ enum SaveError {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
Loaded(Result<State, LoadError>),
|
Loaded(Result<SavedState, LoadError>),
|
||||||
DragStarted,
|
DragStarted,
|
||||||
GameSelected(PossibleGames)
|
GameSelected(PossibleGames)
|
||||||
}
|
}
|
||||||
|
@ -151,8 +175,8 @@ fn rad(deg: f32) -> f32 {
|
||||||
deg * std::f32::consts::PI / 180.0
|
deg * std::f32::consts::PI / 180.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_game_background(game: &PossibleGames) -> Element<Message> {
|
fn get_game_background(state: &State) -> LauncherBackground {
|
||||||
let file_path: &str = match game {
|
let file_path: &str = match state.selected_game {
|
||||||
PossibleGames::WutheringWaves => "wutheringwaves-bg.mp4",
|
PossibleGames::WutheringWaves => "wutheringwaves-bg.mp4",
|
||||||
PossibleGames::ZenlessZoneZero => "zenlesszonezero-bg.png",
|
PossibleGames::ZenlessZoneZero => "zenlesszonezero-bg.png",
|
||||||
PossibleGames::HonkaiStarRail => "honkaistarrail-bg.png",
|
PossibleGames::HonkaiStarRail => "honkaistarrail-bg.png",
|
||||||
|
@ -170,8 +194,7 @@ fn get_game_background(game: &PossibleGames) -> Element<Message> {
|
||||||
match Video::new(url::Url::from_file_path(temp_path).unwrap()) {
|
match Video::new(url::Url::from_file_path(temp_path).unwrap()) {
|
||||||
Ok(mut video) => {
|
Ok(mut video) => {
|
||||||
video.set_looping(true);
|
video.set_looping(true);
|
||||||
|
LauncherBackground::Video(video)
|
||||||
VideoPlayer::new(video).into()
|
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
panic!("{:#?}", err)
|
panic!("{:#?}", err)
|
||||||
|
@ -183,20 +206,19 @@ fn get_game_background(game: &PossibleGames) -> Element<Message> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.decode()
|
.decode()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let handle = image::Handle::from_rgba(
|
LauncherBackground::Image(image::Handle::from_rgba(
|
||||||
img.width(),
|
img.width(),
|
||||||
img.height(),
|
img.height(),
|
||||||
img.to_rgba8().into_raw()
|
img.to_rgba8().into_raw()
|
||||||
);
|
))
|
||||||
image(handle).content_fit(iced::ContentFit::Fill).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Missing icon for {:?}, path: {}", game, file_path)
|
panic!("Missing icon for {:?}, path: {}", state.selected_game, file_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_game_icon(game: &PossibleGames) -> Element<Message> {
|
fn get_game_icon_handle(game: &PossibleGames) -> image::Handle {
|
||||||
let file_path: &str = match game {
|
let file_path: &str = match game {
|
||||||
PossibleGames::WutheringWaves => "wutheringwaves-icon.png",
|
PossibleGames::WutheringWaves => "wutheringwaves-icon.png",
|
||||||
PossibleGames::ZenlessZoneZero => "zenlesszonezero-icon.png",
|
PossibleGames::ZenlessZoneZero => "zenlesszonezero-icon.png",
|
||||||
|
@ -208,24 +230,22 @@ fn get_game_icon(game: &PossibleGames) -> Element<Message> {
|
||||||
let img = round_image(data_cursor)
|
let img = round_image(data_cursor)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.resize(126, 126, ::image::imageops::FilterType::Lanczos3);
|
.resize(126, 126, ::image::imageops::FilterType::Lanczos3);
|
||||||
let handle = image::Handle::from_rgba(
|
|
||||||
|
image::Handle::from_rgba(
|
||||||
img.width(),
|
img.width(),
|
||||||
img.height(),
|
img.height(),
|
||||||
img.to_rgba8().into_raw()
|
img.to_rgba8().into_raw()
|
||||||
);
|
)
|
||||||
container(image(handle).content_fit(iced::ContentFit::Contain).height(Length::Fixed(64.0)).filter_method(image::FilterMethod::Linear))
|
|
||||||
.style(move |_| {
|
|
||||||
container::Style {
|
|
||||||
border: border::rounded(20),
|
|
||||||
..container::Style::default()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.into()
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Missing icon for {:?}, path: {}", game, file_path)
|
panic!("Missing icon for {:?}, path: {}", game, file_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_game_icon<'a>(state: &'a State, game: &'a PossibleGames) -> Element<'a, Message> {
|
||||||
|
let handle = state.icon_images.get(game).unwrap();
|
||||||
|
container(image(handle).content_fit(iced::ContentFit::Contain).height(Length::Fixed(64.0)).filter_method(image::FilterMethod::Linear)).into()
|
||||||
|
}
|
||||||
|
|
||||||
fn style_container(direction: f32, use_gradient: bool) -> container::Style {
|
fn style_container(direction: f32, use_gradient: bool) -> container::Style {
|
||||||
let angle = rad(direction);
|
let angle = rad(direction);
|
||||||
let gradient: Option<iced::Background> = if use_gradient {
|
let gradient: Option<iced::Background> = if use_gradient {
|
||||||
|
@ -241,7 +261,18 @@ fn style_container(direction: f32, use_gradient: bool) -> container::Style {
|
||||||
}
|
}
|
||||||
impl Launcher {
|
impl Launcher {
|
||||||
fn boot() -> (Self, Task<Message>) {
|
fn boot() -> (Self, Task<Message>) {
|
||||||
(Self::Loaded(State::default()), Task::none())
|
let launcher_bg = get_game_background(&State::default());
|
||||||
|
let mut icons = HashMap::new();
|
||||||
|
for game in PossibleGames::iter() {
|
||||||
|
let icon = get_game_icon_handle(&game);
|
||||||
|
icons.insert(game, icon);
|
||||||
|
}
|
||||||
|
let final_state = State {
|
||||||
|
background: Some(launcher_bg),
|
||||||
|
icon_images: icons,
|
||||||
|
..State::default()
|
||||||
|
};
|
||||||
|
(Self::Loaded(Box::new(final_state)), Task::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
|
@ -251,8 +282,8 @@ impl Launcher {
|
||||||
fn update(&mut self, message: Message) -> Task<Message> {
|
fn update(&mut self, message: Message) -> Task<Message> {
|
||||||
match self {
|
match self {
|
||||||
Launcher::Loading => match message {
|
Launcher::Loading => match message {
|
||||||
Message::Loaded(Ok(state)) => {
|
Message::Loaded(Ok(save_state)) => {
|
||||||
*self = Launcher::Loaded(state);
|
*self = Launcher::Loaded(save_state.into());
|
||||||
Task::none()
|
Task::none()
|
||||||
},
|
},
|
||||||
_ => Task::none(),
|
_ => Task::none(),
|
||||||
|
@ -271,12 +302,16 @@ impl Launcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
|
println!("rerender triggered");
|
||||||
|
match self {
|
||||||
|
Launcher::Loading => center(text("Loading...").size(50)).into(),
|
||||||
|
Launcher::Loaded(state) => {
|
||||||
let game_selector = container(
|
let game_selector = container(
|
||||||
row![
|
row![
|
||||||
get_game_icon(&PossibleGames::WutheringWaves),
|
get_game_icon(state, &PossibleGames::WutheringWaves),
|
||||||
get_game_icon(&PossibleGames::ZenlessZoneZero),
|
get_game_icon(state, &PossibleGames::ZenlessZoneZero),
|
||||||
get_game_icon(&PossibleGames::HonkaiStarRail),
|
get_game_icon(state, &PossibleGames::HonkaiStarRail),
|
||||||
get_game_icon(&PossibleGames::GenshinImpact),
|
get_game_icon(state, &PossibleGames::GenshinImpact),
|
||||||
]
|
]
|
||||||
.spacing(10),
|
.spacing(10),
|
||||||
)
|
)
|
||||||
|
@ -286,10 +321,6 @@ impl Launcher {
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.style(move |_| style_container(0.0, true));
|
.style(move |_| style_container(0.0, true));
|
||||||
|
|
||||||
println!("whuh");
|
|
||||||
match self {
|
|
||||||
Launcher::Loading => center(text("Loading...").size(50)).into(),
|
|
||||||
Launcher::Loaded(state) => {
|
|
||||||
let topbar = container(
|
let topbar = container(
|
||||||
mouse_area(row![
|
mouse_area(row![
|
||||||
text("Reversed Rooms").size(25),
|
text("Reversed Rooms").size(25),
|
||||||
|
@ -322,8 +353,13 @@ impl Launcher {
|
||||||
column![topbar, Space::new(Length::Fill, Length::Fill), bottom_bar].width(Length::Fill);
|
column![topbar, Space::new(Length::Fill, Length::Fill), bottom_bar].width(Length::Fill);
|
||||||
|
|
||||||
let content = container(user_area).center(Length::Fill);
|
let content = container(user_area).center(Length::Fill);
|
||||||
|
let background = state.background.as_ref().unwrap();
|
||||||
|
let bg_element: Element<Message> = match background {
|
||||||
|
LauncherBackground::Video(video) => VideoPlayer::new(video).into(),
|
||||||
|
LauncherBackground::Image(handle) => image(handle.clone()).into(),
|
||||||
|
};
|
||||||
|
|
||||||
stack![get_game_background(&state.selected_game), game_selector, content].into()
|
stack![bg_element, game_selector, content].into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue