chore: update iced
This commit is contained in:
parent
5c1887fb07
commit
6c401d7030
7 changed files with 1502 additions and 915 deletions
170
src/main.rs
170
src/main.rs
|
|
@ -2,17 +2,19 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic::{
|
||||
app::{command, message, Command, Core, Settings},
|
||||
action::{self, app},
|
||||
app::{Core, Settings, Task},
|
||||
command::set_theme,
|
||||
cosmic_config::{self, CosmicConfigEntry},
|
||||
cosmic_theme, executor, font,
|
||||
iced::{
|
||||
event::{self, Event},
|
||||
keyboard::{Event as KeyEvent, Key, Modifiers},
|
||||
mouse::{Event as MouseEvent, ScrollDelta},
|
||||
subscription::Subscription,
|
||||
window, Alignment, Background, Border, Color, ContentFit, Length, Limits,
|
||||
window::{self, set_mode},
|
||||
Alignment, Background, Border, Color, ContentFit, Length, Limits, Subscription,
|
||||
},
|
||||
iced_style, theme,
|
||||
theme,
|
||||
widget::{self, menu::action::MenuAction, nav_bar, segmented_button, Slider},
|
||||
Application, ApplicationExt, Element,
|
||||
};
|
||||
|
|
@ -26,7 +28,12 @@ use std::{
|
|||
ffi::{CStr, CString},
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process, thread,
|
||||
process,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
|
|
@ -34,6 +41,7 @@ use tokio::sync::mpsc;
|
|||
use crate::{
|
||||
config::{Config, ConfigState, CONFIG_VERSION, RepeatState},
|
||||
key_bind::{key_binds, KeyBind},
|
||||
mpris::subscription,
|
||||
project::ProjectNode,
|
||||
};
|
||||
|
||||
|
|
@ -254,7 +262,6 @@ impl AsRef<str> for TextCode {
|
|||
/// Messages that are used specifically by our [`App`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
None,
|
||||
Config(Config),
|
||||
ConfigState(ConfigState),
|
||||
DropdownToggle(DropdownKind),
|
||||
|
|
@ -351,15 +358,15 @@ impl App {
|
|||
was_open
|
||||
}
|
||||
|
||||
fn load(&mut self) -> Command<Message> {
|
||||
fn load(&mut self) -> Task<Message> {
|
||||
if self.close() {
|
||||
// Allow a redraw before trying to load again, to prevent deadlock
|
||||
return Command::perform(async { message::app(Message::Reload) }, |x| x);
|
||||
return Task::perform(async { action::app(Message::Reload) }, |x| x);
|
||||
}
|
||||
|
||||
let url = match &self.flags.url_opt {
|
||||
Some(some) => some.clone(),
|
||||
None => return Command::none(),
|
||||
None => return Task::none(),
|
||||
};
|
||||
|
||||
log::info!("Loading {}", url);
|
||||
|
|
@ -607,8 +614,8 @@ impl App {
|
|||
self.update_mpris_state();
|
||||
}
|
||||
|
||||
fn update_config(&mut self) -> Command<Message> {
|
||||
cosmic::app::command::set_theme(self.flags.config.app_theme.theme())
|
||||
fn update_config(&mut self) -> Task<Message> {
|
||||
set_theme(self.flags.config.app_theme.theme())
|
||||
}
|
||||
|
||||
fn update_flags(&mut self) {
|
||||
|
|
@ -800,10 +807,10 @@ impl App {
|
|||
self.nav_model.activate(active_id);
|
||||
}
|
||||
|
||||
fn update_title(&mut self) -> Command<Message> {
|
||||
fn update_title(&mut self) -> Task<Message> {
|
||||
//TODO: filename?
|
||||
let title = "COSMIC Media Player";
|
||||
self.set_window_title(title.to_string())
|
||||
self.set_window_title(title.to_string(), self.core.main_window_id().unwrap())
|
||||
}
|
||||
|
||||
/// Allow screen to dim or turn off if there is no input from the user.
|
||||
|
|
@ -850,7 +857,7 @@ impl Application for App {
|
|||
}
|
||||
|
||||
/// Creates the application, and optionally emits command on initialize.
|
||||
fn init(mut core: Core, flags: Self::Flags) -> (Self, Command<Self::Message>) {
|
||||
fn init(mut core: Core, flags: Self::Flags) -> (Self, Task<Self::Message>) {
|
||||
core.window.content_container = false;
|
||||
|
||||
#[cfg(feature = "xdg-portal")]
|
||||
|
|
@ -905,10 +912,13 @@ impl Application for App {
|
|||
.as_ref()
|
||||
.and_then(|url| url.to_file_path().ok());
|
||||
let command = match (app.flags.urls.take(), maybe_path) {
|
||||
(Some(urls), _) => command::message::app(Message::MultipleLoad(urls)),
|
||||
(None, Some(path)) if path.is_dir() => command::message::app(Message::FolderLoad(path)),
|
||||
_ => app.load(), //If there is no url args, we execute load for nothing?
|
||||
//If only one file is loaded, nothing is added to the navbar.
|
||||
(Some(urls), _) => {
|
||||
cosmic::task::message(cosmic::action::app(Message::MultipleLoad(urls)))
|
||||
}
|
||||
(None, Some(path)) if path.is_dir() => {
|
||||
cosmic::task::message(cosmic::action::app(Message::FolderLoad(path)))
|
||||
}
|
||||
_ => app.load(),
|
||||
};
|
||||
(app, command)
|
||||
}
|
||||
|
|
@ -917,15 +927,15 @@ impl Application for App {
|
|||
Some(&self.nav_model)
|
||||
}
|
||||
|
||||
fn on_escape(&mut self) -> Command<Self::Message> {
|
||||
fn on_escape(&mut self) -> Task<Self::Message> {
|
||||
if self.fullscreen {
|
||||
return self.update(Message::Fullscreen);
|
||||
} else {
|
||||
Command::none()
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
|
||||
fn on_nav_select(&mut self, id: nav_bar::Id) -> Command<Message> {
|
||||
fn on_nav_select(&mut self, id: nav_bar::Id) -> Task<Message> {
|
||||
// Toggle open state and get clone of node data
|
||||
let node_opt = match self.nav_model.data_mut::<ProjectNode>(id) {
|
||||
Some(node) => {
|
||||
|
|
@ -966,13 +976,13 @@ impl Application for App {
|
|||
// folder in condensed mode.
|
||||
self.core_mut().nav_bar_set_toggled(true);
|
||||
|
||||
Command::none()
|
||||
Task::none()
|
||||
}
|
||||
ProjectNode::File { path, .. } => match url::Url::from_file_path(&path) {
|
||||
Ok(url) => self.update(Message::FileLoad(url)),
|
||||
Err(()) => {
|
||||
log::warn!("failed to convert {:?} to url", path);
|
||||
Command::none()
|
||||
Task::none()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -984,21 +994,21 @@ impl Application for App {
|
|||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Option<theme::Application> {
|
||||
fn style(&self) -> Option<cosmic::iced_core::theme::Style> {
|
||||
// This ensures we have a solid background color even when using no content container
|
||||
Some(theme::Application::Custom(Box::new(|theme| {
|
||||
iced_style::application::Appearance {
|
||||
background_color: theme.cosmic().bg_color().into(),
|
||||
icon_color: theme.cosmic().on_bg_color().into(),
|
||||
text_color: theme.cosmic().on_bg_color().into(),
|
||||
}
|
||||
})))
|
||||
|
||||
let theme = self.core.system_theme();
|
||||
|
||||
Some(cosmic::iced_core::theme::Style {
|
||||
background_color: theme.cosmic().bg_color().into(),
|
||||
icon_color: theme.cosmic().on_bg_color().into(),
|
||||
text_color: theme.cosmic().on_bg_color().into(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Handle application events here.
|
||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
||||
match message {
|
||||
Message::None => {}
|
||||
Message::Config(config) => {
|
||||
if config != self.flags.config {
|
||||
log::info!("update config");
|
||||
|
|
@ -1031,17 +1041,17 @@ impl Application for App {
|
|||
Message::FileOpen => {
|
||||
//TODO: embed cosmic-files dialog (after libcosmic rebase works)
|
||||
#[cfg(feature = "xdg-portal")]
|
||||
return Command::perform(
|
||||
return Task::perform(
|
||||
async move {
|
||||
let dialog = cosmic::dialog::file_chooser::open::Dialog::new()
|
||||
.title(fl!("open-media"));
|
||||
match dialog.open_file().await {
|
||||
Ok(response) => {
|
||||
message::app(Message::FileLoad(response.url().to_owned()))
|
||||
action::app(Message::FileLoad(response.url().to_owned()))
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to open file: {}", err);
|
||||
message::none()
|
||||
action::none()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1095,7 +1105,7 @@ impl Application for App {
|
|||
Message::FolderOpen => {
|
||||
//TODO: embed cosmic-files dialog (after libcosmic rebase works)
|
||||
#[cfg(feature = "xdg-portal")]
|
||||
return Command::perform(
|
||||
return Task::perform(
|
||||
async move {
|
||||
let dialog = cosmic::dialog::file_chooser::open::Dialog::new()
|
||||
.title(fl!("open-media-folder"));
|
||||
|
|
@ -1103,16 +1113,16 @@ impl Application for App {
|
|||
Ok(response) => {
|
||||
let url = response.url();
|
||||
match url.to_file_path() {
|
||||
Ok(path) => message::app(Message::FolderLoad(path)),
|
||||
Ok(path) => action::app(Message::FolderLoad(path)),
|
||||
Err(()) => {
|
||||
log::warn!("unsupported folder URL {:?}", url);
|
||||
message::none()
|
||||
action::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to open folder: {}", err);
|
||||
message::none()
|
||||
action::none()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1156,17 +1166,18 @@ impl Application for App {
|
|||
//TODO: cleanest way to close dropdowns
|
||||
self.dropdown_opt = None;
|
||||
|
||||
self.fullscreen = !self.fullscreen;
|
||||
self.core.window.show_headerbar = !self.fullscreen;
|
||||
self.controls = !self.fullscreen;
|
||||
return window::change_mode(
|
||||
window::Id::MAIN,
|
||||
if self.fullscreen {
|
||||
window::Mode::Fullscreen
|
||||
} else {
|
||||
window::Mode::Windowed
|
||||
},
|
||||
);
|
||||
if let Some(window_id) = self.core.main_window_id() {
|
||||
self.fullscreen = !self.fullscreen;
|
||||
self.core.window.show_headerbar = !self.fullscreen;
|
||||
return set_mode(
|
||||
window_id,
|
||||
if self.fullscreen {
|
||||
window::Mode::Fullscreen
|
||||
} else {
|
||||
window::Mode::Windowed
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Message::Key(modifiers, key) => {
|
||||
for (key_bind, action) in self.key_binds.iter() {
|
||||
|
|
@ -1385,7 +1396,7 @@ impl Application for App {
|
|||
if let Some(video) = &mut self.video_opt {
|
||||
video.set_paused(true);
|
||||
}
|
||||
return Command::perform(
|
||||
return Task::perform(
|
||||
async move {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
match gst_pbutils::MissingPluginMessage::parse(&element) {
|
||||
|
|
@ -1419,7 +1430,7 @@ impl Application for App {
|
|||
"gstreamer registry update: {:?}",
|
||||
gst::Registry::update()
|
||||
);
|
||||
return message::app(Message::Reload);
|
||||
return action::app(Message::Reload);
|
||||
},
|
||||
_ => {
|
||||
log::warn!("failed to install plugins: {status}");
|
||||
|
|
@ -1433,7 +1444,7 @@ impl Application for App {
|
|||
log::warn!("failed to parse missing plugin message: {err}");
|
||||
}
|
||||
}
|
||||
message::none()
|
||||
action::none()
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
|
|
@ -1467,7 +1478,7 @@ impl Application for App {
|
|||
process::exit(0);
|
||||
}
|
||||
}
|
||||
Command::none()
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn header_start(&self) -> Vec<Element<'_, Self::Message>> {
|
||||
|
|
@ -1501,25 +1512,25 @@ impl Application for App {
|
|||
let Some(video) = &self.video_opt else {
|
||||
//TODO: use space variables
|
||||
let column = widget::column::with_capacity(4)
|
||||
.align_items(Alignment::Center)
|
||||
.align_x(Alignment::Center)
|
||||
.spacing(24)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.push(widget::vertical_space(Length::Fill))
|
||||
.push(widget::space::vertical())
|
||||
.push(
|
||||
widget::column::with_capacity(2)
|
||||
.align_items(Alignment::Center)
|
||||
.align_x(Alignment::Center)
|
||||
.spacing(8)
|
||||
.push(widget::icon::from_name("folder-symbolic").size(64))
|
||||
.push(widget::text::body(fl!("no-video-or-audio-file-open"))),
|
||||
)
|
||||
.push(widget::button::suggested(fl!("open-file")).on_press(Message::FileOpen))
|
||||
.push(widget::vertical_space(Length::Fill));
|
||||
.push(widget::space::vertical());
|
||||
|
||||
return widget::container(column)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.style(theme::Container::WindowBackground)
|
||||
.class(theme::Container::WindowBackground)
|
||||
.into();
|
||||
};
|
||||
|
||||
|
|
@ -1534,6 +1545,7 @@ impl Application for App {
|
|||
.on_new_frame(Message::NewFrame)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.id(cosmic::widget::Id::new("video-player".to_string()))
|
||||
.into();
|
||||
|
||||
let mut background_color = Color::BLACK;
|
||||
|
|
@ -1543,7 +1555,7 @@ impl Application for App {
|
|||
text_color_opt = Some(Color::from(theme.cosmic().on_bg_component_color()));
|
||||
|
||||
let mut col = widget::column();
|
||||
col = col.push(widget::vertical_space(Length::Fill));
|
||||
col = col.push(widget::space::vertical());
|
||||
if let Some(album_art) = &self.album_art_opt {
|
||||
col = col.push(
|
||||
widget::image(widget::image::Handle::from_path(album_art.path()))
|
||||
|
|
@ -1553,7 +1565,7 @@ impl Application for App {
|
|||
} else {
|
||||
col = col.push(widget::icon::from_name("audio-x-generic-symbolic").size(256));
|
||||
}
|
||||
col = col.push(widget::vertical_space(space_s));
|
||||
col = col.push(widget::space::vertical().height(space_s));
|
||||
if self.mpris_meta.title.is_empty() {
|
||||
col = col.push(widget::text::title4(fl!("untitled")));
|
||||
} else {
|
||||
|
|
@ -1566,7 +1578,7 @@ impl Application for App {
|
|||
col = col.push(widget::text::body(artist));
|
||||
}
|
||||
}
|
||||
col = col.push(widget::vertical_space(space_s));
|
||||
col = col.push(widget::space::vertical().height(space_s));
|
||||
if !self.mpris_meta.album.is_empty() {
|
||||
col = col.push(widget::text::body(fl!(
|
||||
"album",
|
||||
|
|
@ -1576,7 +1588,7 @@ impl Application for App {
|
|||
if let Some(year) = &self.mpris_meta.album_year_opt {
|
||||
col = col.push(widget::text::body(format!("{}", year)));
|
||||
}
|
||||
col = col.push(widget::vertical_space(Length::Fill));
|
||||
col = col.push(widget::space::vertical());
|
||||
|
||||
// Space to keep from going under control overlay
|
||||
let mut control_height = space_xxs + 32 + space_xxs;
|
||||
|
|
@ -1586,11 +1598,11 @@ impl Application for App {
|
|||
|
||||
// This is a hack to have the video player running but not visible (since the controls will cover it as an overlay)
|
||||
video_player = widget::row::with_children(vec![
|
||||
widget::horizontal_space(Length::Fill).into(),
|
||||
widget::space::horizontal().into(),
|
||||
widget::container(col.push(widget::container(video_player).height(control_height)))
|
||||
.width(320)
|
||||
.into(),
|
||||
widget::horizontal_space(Length::Fill).into(),
|
||||
widget::space::horizontal().into(),
|
||||
])
|
||||
.into();
|
||||
}
|
||||
|
|
@ -1629,7 +1641,7 @@ impl Application for App {
|
|||
.step(0.01)
|
||||
.into(),
|
||||
])
|
||||
.align_items(Alignment::Center)
|
||||
.align_y(Alignment::Center)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
|
@ -1668,14 +1680,14 @@ impl Application for App {
|
|||
|
||||
popup_items.push(
|
||||
widget::row::with_children(vec![
|
||||
widget::horizontal_space(Length::Fill).into(),
|
||||
widget::space::horizontal().into(),
|
||||
widget::container(column)
|
||||
.padding(1)
|
||||
//TODO: move style to libcosmic
|
||||
.style(theme::Container::custom(|theme| {
|
||||
.class(theme::Container::custom(|theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
let component = &cosmic.background.component;
|
||||
widget::container::Appearance {
|
||||
widget::container::Style {
|
||||
icon_color: Some(component.on.into()),
|
||||
text_color: Some(component.on.into()),
|
||||
background: Some(Background::Color(component.base.into())),
|
||||
|
|
@ -1694,8 +1706,8 @@ impl Application for App {
|
|||
);
|
||||
}
|
||||
if self.controls {
|
||||
let mut row = widget::row::with_capacity(8)
|
||||
.align_items(Alignment::Center)
|
||||
let mut row = widget::row::with_capacity(7)
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(space_xxs)
|
||||
.push(
|
||||
widget::button::icon(
|
||||
|
|
@ -1728,7 +1740,7 @@ impl Application for App {
|
|||
widget::tooltip::Position::Top,
|
||||
));
|
||||
if self.core.is_condensed() {
|
||||
row = row.push(widget::horizontal_space(Length::Fill));
|
||||
row = row.push(widget::space::horizontal());
|
||||
} else {
|
||||
row = row
|
||||
.push(widget::text(format_time(self.position)).font(font::mono()))
|
||||
|
|
@ -1777,7 +1789,7 @@ impl Application for App {
|
|||
popup_items.push(
|
||||
widget::container(row)
|
||||
.padding([space_xxs, space_xs])
|
||||
.style(theme::Container::WindowBackground)
|
||||
.class(theme::Container::WindowBackground)
|
||||
.into(),
|
||||
);
|
||||
|
||||
|
|
@ -1785,7 +1797,7 @@ impl Application for App {
|
|||
popup_items.push(
|
||||
widget::container(
|
||||
widget::row::with_capacity(3)
|
||||
.align_items(Alignment::Center)
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(space_xxs)
|
||||
.push(widget::text(format_time(self.position)).font(font::mono()))
|
||||
.push(
|
||||
|
|
@ -1799,7 +1811,7 @@ impl Application for App {
|
|||
),
|
||||
)
|
||||
.padding([space_xxs, space_xs])
|
||||
.style(theme::Container::WindowBackground)
|
||||
.class(theme::Container::WindowBackground)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
|
@ -1811,9 +1823,9 @@ impl Application for App {
|
|||
widget::container(popover)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.style(theme::Container::Custom(Box::new(move |_theme| {
|
||||
.class(theme::Container::Custom(Box::new(move |_theme| {
|
||||
let mut appearance =
|
||||
widget::container::Appearance::default().with_background(background_color);
|
||||
widget::container::Style::default().background(background_color);
|
||||
if let Some(text_color) = text_color_opt {
|
||||
appearance.text_color = Some(text_color);
|
||||
}
|
||||
|
|
@ -1828,7 +1840,7 @@ impl Application for App {
|
|||
struct ThemeSubscription;
|
||||
|
||||
let mut subscriptions = vec![
|
||||
event::listen_with(|event, _status| match event {
|
||||
event::listen_with(|event, _status, _window_id| match event {
|
||||
Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, .. }) => {
|
||||
Some(Message::Key(modifiers, key))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue