Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: open with #80

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ tracing-journald = "0.3"
constcat = "0.5"
nucleo = "0.5"
futures = "0.3"
freedesktop-desktop-entry = "0.7.5"
memchr = "2.7.4"

[dependencies.libcosmic]
git = "https://github.com/pop-os/libcosmic"
Expand Down
4 changes: 3 additions & 1 deletion i18n/en/cosmic_ext_applet_clipboard_manager.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ clear_entries = Clear
show_qr_code = Show QR code
return_to_clipboard = Return to clipboard
qr_code_error = Error while generating the QR code
horizontal_layout = Horizontal
horizontal_layout = Horizontal
open = open
open_with = Open with
14 changes: 14 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use cosmic::iced_widget::{qr_code, Column};
use cosmic::widget::{button, icon, text, text_input, MouseArea, Space};

use cosmic::{Element, Theme};
use freedesktop_desktop_entry::DesktopEntry;
use futures::executor::block_on;

use crate::config::{Config, CONFIG_VERSION, PRIVATE_MODE};
Expand All @@ -33,6 +34,8 @@ use cosmic::cosmic_config;
use std::sync::atomic::{self, AtomicBool};
use std::thread;

use freedesktop_desktop_entry as fde;

pub const QUALIFIER: &str = "io.github";
pub const ORG: &str = "wiiznokes";
pub const APP: &str = "cosmic-ext-applet-clipboard-manager";
Expand All @@ -48,6 +51,7 @@ pub struct AppState {
pub focused: usize,
pub qr_code: Option<Result<qr_code::State, ()>>,
last_quit: Option<(i64, PopupKind)>,
pub desktop_entries: Vec<DesktopEntry<'static>>,
}

impl AppState {
Expand Down Expand Up @@ -208,6 +212,10 @@ impl cosmic::Application for AppState {

let db = block_on(async { db::Db::new(&config).await.unwrap() });

let desktop_entries = fde::Iter::new(fde::default_paths())
.entries(Some(&[] as &[&str]))
.collect::<Vec<_>>();

let window = AppState {
core,
config_handler: flags.config_handler,
Expand All @@ -218,6 +226,7 @@ impl cosmic::Application for AppState {
qr_code: None,
config,
last_quit: None,
desktop_entries,
};

#[cfg(debug_assertions)]
Expand Down Expand Up @@ -387,6 +396,11 @@ impl cosmic::Application for AppState {
config_set!(horizontal, horizontal);
}
},
AppMsg::Open(_) => todo!(),
AppMsg::OpenWith {
entry,
desktop_entry,
} => todo!(),
}
Command::none()
}
Expand Down
2 changes: 1 addition & 1 deletion src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const IMAGE_MIME_TYPES: [&str; 3] = ["image/png", "image/jpeg", "image/ico"];

// prefer popular formats
// orderer by priority
const TEXT_MIME_TYPES: [&str; 3] = ["text/plain;charset=utf-8", "UTF8_STRING", "text/plain"];
const TEXT_MIME_TYPES: [&str; 3] = ["text/plain", "text/plain;charset=utf-8", "UTF8_STRING"];

#[derive(Debug, Clone)]
pub enum ClipboardMessage {
Expand Down
6 changes: 6 additions & 0 deletions src/message.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use cosmic::iced::window::Id;
use freedesktop_desktop_entry::DesktopEntry;

use crate::{
clipboard::{self, ClipboardMessage},
Expand All @@ -24,6 +25,11 @@ pub enum AppMsg {
ShowQrCode(Entry),
ReturnToClipboard,
Config(ConfigMsg),
Open(Entry),
OpenWith {
entry: Entry,
desktop_entry: DesktopEntry<'static>,
},
}

#[derive(Clone, Debug)]
Expand Down
22 changes: 22 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,25 @@ pub fn remove_dir_contents(dir: &Path) {

let _ = inner(dir);
}

pub fn find_x_scheme_handler(a: &str) -> Option<String> {
if let Some(colon_index) = memchr::memchr(b':', a.as_bytes()) {
if a[colon_index..].starts_with("://") {
return Some(format!("x-scheme-handler/{}", &a[..colon_index]));
}
}
None
}

#[test]
fn find_x_scheme_handler_test() {
assert_eq!(
find_x_scheme_handler("https://github.com/wiiznokes/clipboard-manager"),
Some("x-scheme-handler/https".into())
);

assert_eq!(
find_x_scheme_handler("ddg://query%20terms"),
Some("x-scheme-handler/ddg".into())
);
}
107 changes: 103 additions & 4 deletions src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ use cosmic::{
button::{self},
column, container, context_menu, flex_row, grid,
icon::{self, Handle},
image, menu, mouse_area, row, text, text_input, toggler, Column, Container, Icon,
image, menu, mouse_area, row, text, text_input, toggler, Column, Container, Icon, Lazy,
MouseArea, Space, Text, TextEditor,
},
Element,
};

use freedesktop_desktop_entry as fde;

use anyhow::{anyhow, bail, Result};

use crate::{
Expand All @@ -29,7 +31,7 @@ use crate::{
db::{Content, Entry},
fl,
message::{AppMsg, ConfigMsg},
utils::{formatted_value, horizontal_padding, vertical_padding},
utils::{find_x_scheme_handler, formatted_value, horizontal_padding, vertical_padding},
};

impl AppState {
Expand Down Expand Up @@ -327,6 +329,66 @@ impl AppState {
btn.width(Length::Fill).into()
};

let open_with2 = Lazy::new(entry, |entry| {
println!("lazy");

let mut mimes: Vec<Cow<str>> = vec![Cow::Borrowed(entry.mime.as_ref())];

if let Ok(Content::Text(content)) = entry.get_content() {
if let Some(m) = find_x_scheme_handler(content) {
mimes.push(Cow::Owned(m));
}
}

let res = fde::Iter::new(fde::default_paths())
.entries(Some(&[] as &[&str]))
.filter_map(|e| {
e.mime_type()
.unwrap_or_default()
.iter()
.any(|de_mime| mimes.iter().any(|mime| mime == de_mime))
.then_some(
button::custom(text(e.appid.clone()))
.on_press(AppMsg::OpenWith {
entry: (*entry).clone(),
desktop_entry: e,
})
.width(Length::Fill)
.into(),
)
});

Column::with_children(res)
});

let open_with = {
let mut mimes: Vec<Cow<str>> = vec![Cow::Borrowed(entry.mime.as_ref())];

if let Ok(Content::Text(content)) = entry.get_content() {
if let Some(m) = find_x_scheme_handler(content) {
mimes.push(Cow::Owned(m));
}
}

self.desktop_entries
.iter()
.filter_map(|de| {
de.mime_type()
.unwrap_or_default()
.iter()
.any(|de_mime| mimes.iter().any(|mime| mime == de_mime))
.then_some(menu::Tree::new(
button::custom(text(de.appid.clone()))
.on_press(AppMsg::OpenWith {
entry: (*entry).clone(),
desktop_entry: de.clone(),
})
.width(Length::Fill),
))
})
.collect::<Vec<_>>()
};

context_menu(
btn,
Some(vec![
Expand All @@ -339,11 +401,48 @@ impl AppState {
menu::Tree::new(
button::text(fl!("show_qr_code"))
.on_press(AppMsg::ShowQrCode(entry.clone()))
.width(Length::Fill)
.style(Button::Destructive),
.width(Length::Fill),
),
menu::Tree::new(
button::text(fl!("open"))
.on_press(AppMsg::ShowQrCode(entry.clone()))
.width(Length::Fill),
),
menu::Tree::with_children(text(fl!("open_with")).width(Length::Fill), open_with),
menu::Tree::with_children(
text("Open with 2").width(Length::Fill),
vec![menu::Tree::new(open_with2)],
),
]),
)
.into()
}
}

mod test {

use freedesktop_desktop_entry as fde;

#[test]
fn t() {
let desktop_entries = fde::Iter::new(fde::default_paths())
.entries(Some(&[] as &[&str]))
.collect::<Vec<_>>();

let mimes = ["text/plain"];

let res = desktop_entries
.iter()
.filter(|e| {
e.mime_type()
.unwrap_or_default()
.iter()
.any(|e| mimes.contains(e))
})
.collect::<Vec<_>>();

for r in res {
println!("{}", r.appid);
}
}
}