chore: update iced
This commit is contained in:
parent
5c1887fb07
commit
6c401d7030
7 changed files with 1502 additions and 915 deletions
2159
Cargo.lock
generated
2159
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
26
Cargo.toml
26
Cargo.toml
|
|
@ -30,15 +30,21 @@ env_logger = "0.10"
|
|||
log = "0.4"
|
||||
|
||||
[dependencies.iced_video_player]
|
||||
git = "https://github.com/jackpot51/iced_video_player.git"
|
||||
branch = "prev-cosmic"
|
||||
git = "https://github.com/wash2/iced_video_player.git"
|
||||
branch = "iced-rebase"
|
||||
default-features = false
|
||||
|
||||
[dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic.git"
|
||||
branch = "prev-master"
|
||||
default-features = false
|
||||
features = ["tokio", "winit"]
|
||||
features = [
|
||||
"tokio",
|
||||
"winit",
|
||||
"multi-window",
|
||||
"surface-message",
|
||||
"wayland",
|
||||
"x11",
|
||||
]
|
||||
|
||||
[dependencies.mpris-server]
|
||||
version = "0.8.1"
|
||||
|
|
@ -56,15 +62,13 @@ wgpu = ["iced_video_player/wgpu", "libcosmic/wgpu"]
|
|||
inherits = "release"
|
||||
debug = true
|
||||
|
||||
# Keep cosmic-text at version compatible with prev-master of libcosmic
|
||||
[patch.'https://github.com/pop-os/cosmic-text'.cosmic-text]
|
||||
git = "https://github.com/pop-os/cosmic-text//"
|
||||
rev = "166b59f560c551dab391a864f7c1f503c1e18446"
|
||||
|
||||
# [patch.'https://github.com/jackpot51/iced_video_player']
|
||||
# iced_video_player = { path = "../../iced_video_player" }
|
||||
[patch.'https://github.com/wash2/iced_video_player']
|
||||
iced_video_player = { path = "../iced_video_player" }
|
||||
|
||||
# [patch.'https://github.com/pop-os/libcosmic']
|
||||
# libcosmic = { path = "../libcosmic" }
|
||||
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
||||
# cosmic-theme = { path = "../libcosmic/cosmic-theme" }
|
||||
# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "iced-rebase" }
|
||||
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "iced-rebase" }
|
||||
# cosmic-theme = { git = "https://github.com/pop-os/libcosmic//", branch = "iced-rebase" }
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
|
|||
//TODO: key bindings
|
||||
bind!([], Key::Character("f".into()), Fullscreen);
|
||||
bind!([Alt], Key::Named(Named::Enter), Fullscreen);
|
||||
bind!([], Key::Named(Named::Space), PlayPause);
|
||||
bind!([], Key::Character(" ".into()), PlayPause);
|
||||
bind!([], Key::Named(Named::ArrowLeft), SeekBackward);
|
||||
bind!([], Key::Named(Named::ArrowRight), SeekForward);
|
||||
|
||||
|
|
|
|||
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))
|
||||
}
|
||||
|
|
|
|||
23
src/menu.rs
23
src/menu.rs
|
|
@ -1,8 +1,12 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic::{
|
||||
Element, theme,
|
||||
widget::menu::{self, ItemHeight, ItemWidth, MenuBar, key_bind::KeyBind},
|
||||
theme,
|
||||
widget::{
|
||||
menu::{self, key_bind::KeyBind, ItemHeight, ItemWidth, MenuBar},
|
||||
RcElementWrapper,
|
||||
},
|
||||
Element,
|
||||
};
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
|
|
@ -39,6 +43,7 @@ pub fn menu_bar<'a>(
|
|||
for (i, path) in config_state.recent_files.iter().enumerate() {
|
||||
recent_files.push(menu::Item::Button(
|
||||
format_url(path),
|
||||
None,
|
||||
Action::FileOpenRecent(i),
|
||||
));
|
||||
}
|
||||
|
|
@ -46,6 +51,7 @@ pub fn menu_bar<'a>(
|
|||
recent_files.push(menu::Item::Divider);
|
||||
recent_files.push(menu::Item::Button(
|
||||
fl!("clear-recent"),
|
||||
None,
|
||||
Action::FileClearRecents,
|
||||
));
|
||||
}
|
||||
|
|
@ -59,6 +65,7 @@ pub fn menu_bar<'a>(
|
|||
for (i, path) in config_state.recent_projects.iter().enumerate() {
|
||||
recent_projects.push(menu::Item::Button(
|
||||
format_path(path),
|
||||
None,
|
||||
Action::FolderOpenRecent(i),
|
||||
));
|
||||
}
|
||||
|
|
@ -66,6 +73,7 @@ pub fn menu_bar<'a>(
|
|||
recent_projects.push(menu::Item::Divider);
|
||||
recent_projects.push(menu::Item::Button(
|
||||
fl!("clear-recent"),
|
||||
None,
|
||||
Action::FolderClearRecents,
|
||||
));
|
||||
}
|
||||
|
|
@ -74,24 +82,25 @@ pub fn menu_bar<'a>(
|
|||
for (folder_i, (name, _path)) in projects.iter().enumerate() {
|
||||
close_projects.push(menu::Item::Button(
|
||||
name.clone(),
|
||||
None,
|
||||
Action::FolderClose(folder_i),
|
||||
));
|
||||
}
|
||||
|
||||
MenuBar::new(vec![menu::Tree::with_children(
|
||||
menu::root(fl!("file")),
|
||||
RcElementWrapper::new(Element::from(menu::root(fl!("file")))),
|
||||
menu::items(
|
||||
key_binds,
|
||||
vec![
|
||||
menu::Item::Button(fl!("open-media"), Action::FileOpen),
|
||||
menu::Item::Button(fl!("open-media"), None, Action::FileOpen),
|
||||
menu::Item::Folder(fl!("open-recent-media"), recent_files),
|
||||
menu::Item::Button(fl!("close-file"), Action::FileClose),
|
||||
menu::Item::Button(fl!("close-file"), None, Action::FileClose),
|
||||
menu::Item::Divider,
|
||||
menu::Item::Button(fl!("open-media-folder"), Action::FolderOpen),
|
||||
menu::Item::Button(fl!("open-media-folder"), None, Action::FolderOpen),
|
||||
menu::Item::Folder(fl!("open-recent-media-folder"), recent_projects),
|
||||
menu::Item::Folder(fl!("close-media-folder"), close_projects),
|
||||
menu::Item::Divider,
|
||||
menu::Item::Button(fl!("quit"), Action::WindowClose),
|
||||
menu::Item::Button(fl!("quit"), None, Action::WindowClose),
|
||||
],
|
||||
),
|
||||
)])
|
||||
|
|
|
|||
29
src/mpris.rs
29
src/mpris.rs
|
|
@ -1,6 +1,9 @@
|
|||
use cosmic::iced::{
|
||||
futures::{self, SinkExt},
|
||||
subscription::{self, Subscription},
|
||||
use cosmic::{
|
||||
iced::{
|
||||
futures::{self, SinkExt, Stream},
|
||||
Subscription,
|
||||
},
|
||||
iced_futures::stream,
|
||||
};
|
||||
use mpris_server::{
|
||||
LoopStatus, Metadata, PlaybackRate, PlaybackStatus, PlayerInterface, Property, RootInterface,
|
||||
|
|
@ -377,15 +380,13 @@ impl PlaylistsInterface for Player {
|
|||
}
|
||||
*/
|
||||
|
||||
pub fn subscription() -> Subscription<Message> {
|
||||
struct MprisSubscription;
|
||||
subscription::channel(
|
||||
TypeId::of::<MprisSubscription>(),
|
||||
16,
|
||||
move |mut msg_tx| async move {
|
||||
fn watcher_stream() -> impl Stream<Item = Message> {
|
||||
stream::channel(
|
||||
5,
|
||||
move |mut msg_tx: futures::channel::mpsc::Sender<Message>| async move {
|
||||
let (event_tx, mut event_rx) = mpsc::unbounded_channel();
|
||||
let meta = MprisMeta::default();
|
||||
let state = MprisState::default();
|
||||
let meta: MprisMeta = MprisMeta::default();
|
||||
let state: MprisState = MprisState::default();
|
||||
msg_tx
|
||||
.send(Message::MprisChannel(meta.clone(), state.clone(), event_tx))
|
||||
.await
|
||||
|
|
@ -455,3 +456,9 @@ pub fn subscription() -> Subscription<Message> {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
pub fn subscription() -> Subscription<Message> {
|
||||
struct MprisSubscription;
|
||||
Subscription::run_with(TypeId::of::<MprisSubscription>(), |_| watcher_stream())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,11 +42,11 @@ pub fn main(
|
|||
}
|
||||
}?;
|
||||
|
||||
if let Some((width, height)) = size_opt {
|
||||
image = image.thumbnail(width, height);
|
||||
}
|
||||
// if let Some((width, height)) = size_opt {
|
||||
// image = image.thumbnail(width, height);
|
||||
// }
|
||||
|
||||
image.save_with_format(output, ImageFormat::Png)?;
|
||||
// image.save_with_format(output, ImageFormat::Png)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue