Skip to content

Commit 326b1f5

Browse files
authored
feat: impl list_app_with_metadata_in() (#361)
* feat: impl list_app_with_metadata_in() * docs: add link to serde_json::Number::from_u128() * fix: app search * chore: more default search paths for macOS
1 parent 0a7b445 commit 326b1f5

3 files changed

Lines changed: 105 additions & 57 deletions

File tree

src-tauri/Cargo.lock

Lines changed: 3 additions & 51 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ pizza-common = { git = "https://github.com/infinilabs/pizza-common", branch = "m
2727
tauri = { version = "2", features = ["protocol-asset", "macos-private-api", "tray-icon", "image-ico", "image-png", "unstable"] }
2828
tauri-plugin-shell = "2"
2929
serde = { version = "1", features = ["derive"] }
30-
serde_json = "1"
30+
# Need `arbitrary_precision` feature to support storing u128
31+
# see: https://docs.rs/serde_json/latest/serde_json/struct.Number.html#method.from_u128
32+
serde_json = { version = "1", features = ["arbitrary_precision"] }
3133
tauri-plugin-http = "2"
3234
tauri-plugin-websocket = "2"
3335
tauri-plugin-deep-link = "2.0.0"
@@ -41,7 +43,7 @@ tauri-plugin-drag = "2"
4143
tauri-plugin-macos-permissions = "2"
4244
tauri-plugin-fs-pro = "2"
4345
tauri-plugin-screenshots = "2"
44-
applications = "0.3.1"
46+
applications = { git = "https://github.com/infinilabs/applications-rs", rev = "2345d3b86b711b03aa9aee6920e0108d81a8edb9" }
4547

4648
tokio-native-tls = "0.3" # For wss connections
4749
tokio = { version = "1", features = ["full"] }

src-tauri/src/local/application.rs

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::common::document::{DataSourceReference, Document};
22
use crate::common::search::{QueryResponse, QuerySource, SearchQuery};
33
use crate::common::traits::{SearchError, SearchSource};
44
use crate::local::LOCAL_QUERY_SOURCE_TYPE;
5-
use applications::{AppInfo, AppInfoContext};
5+
use applications::{App, AppInfo, AppInfoContext};
66
use async_trait::async_trait;
77
use base64::encode;
88
use fuzzy_prefix_search::Trie;
@@ -17,8 +17,7 @@ pub fn get_default_search_paths() -> Vec<String> {
1717
let paths = applications::get_default_search_paths();
1818
let mut ret = Vec::with_capacity(paths.len());
1919
for search_path in paths {
20-
let path = search_path.path;
21-
let path_string = path
20+
let path_string = search_path
2221
.into_os_string()
2322
.into_string()
2423
.expect("path should be UTF-8 encoded");
@@ -29,6 +28,96 @@ pub fn get_default_search_paths() -> Vec<String> {
2928
ret
3029
}
3130

31+
/// List apps that are in the `search_path`.
32+
#[allow(unused)] // for now, will be used in https://github.com/infinilabs/coco-app/pull/346
33+
fn list_app_in(search_path: Vec<String>) -> Result<Vec<App>, String> {
34+
let search_path = search_path
35+
.into_iter()
36+
.map(PathBuf::from)
37+
.collect::<Vec<_>>();
38+
let apps = applications::get_all_apps(&search_path).map_err(|err| err.to_string())?;
39+
40+
Ok(apps
41+
.into_iter()
42+
.filter(|app| app.icon_path.is_none())
43+
.collect())
44+
}
45+
46+
#[derive(serde::Serialize)]
47+
pub struct AppMetadata {
48+
#[serde(rename = "Name")]
49+
name: String,
50+
#[serde(rename = "Where")]
51+
r#where: PathBuf,
52+
#[serde(rename = "Size")]
53+
size: u64,
54+
#[serde(rename = "Created")]
55+
created: u128,
56+
#[serde(rename = "Modified")]
57+
modified: u128,
58+
#[serde(rename = "Last opened")]
59+
last_opened: u128,
60+
}
61+
62+
/// List apps that are in the `search_path`.
63+
///
64+
/// Different from `list_app_in()`, every app is JSON object containing its metadata, e.g.:
65+
///
66+
/// ```json
67+
/// {
68+
/// "Name": "Finder",
69+
/// "Where": "/System/Library/CoreServices",
70+
/// "Size": 49283072,
71+
/// "Created": 1744625204,
72+
/// "Modified": 1744625204,
73+
/// "Last opened": 1744625250
74+
/// }
75+
/// ```
76+
#[tauri::command]
77+
pub async fn list_app_with_metadata_in(
78+
search_path: Vec<String>,
79+
) -> Result<Vec<AppMetadata>, String> {
80+
let apps = list_app_in(search_path)?;
81+
82+
let mut apps_with_meta = Vec::with_capacity(apps.len());
83+
84+
// name version where Type(hardcoded Application) Size Created Modify
85+
for app in apps {
86+
let app_path = if cfg!(target_os = "windows") {
87+
app.app_path_exe
88+
.clone()
89+
.unwrap_or(PathBuf::from("Path not found"))
90+
} else {
91+
app.app_desktop_path.clone()
92+
};
93+
let app_name = name(app_path.clone()).await;
94+
let app_path_where = {
95+
let mut app_path_clone = app_path.clone();
96+
let truncated = app_path_clone.pop();
97+
if !truncated {
98+
panic!("every app file should live somewhere");
99+
}
100+
101+
app_path_clone
102+
};
103+
104+
let raw_app_metadata = tauri_plugin_fs_pro::metadata(app_path.clone(), None).await?;
105+
106+
let app_metadata = AppMetadata {
107+
name: app_name,
108+
r#where: app_path_where,
109+
size: raw_app_metadata.size,
110+
created: raw_app_metadata.created_at,
111+
modified: raw_app_metadata.modified_at,
112+
last_opened: raw_app_metadata.accessed_at,
113+
};
114+
115+
apps_with_meta.push(app_metadata);
116+
}
117+
118+
Ok(apps_with_meta)
119+
}
120+
32121
pub struct ApplicationSearchSource {
33122
base_score: f64,
34123
icons: HashMap<String, PathBuf>,
@@ -43,7 +132,12 @@ impl ApplicationSearchSource {
43132
let application_paths = Trie::new();
44133
let mut icons = HashMap::new();
45134

46-
let mut ctx = AppInfoContext::new(vec![]);
135+
let default_search_path = if cfg!(target_os = "macos") {
136+
vec!["/Applications".into(), "/System/Applications".into(), "/System/Library/CoreServices".into()]
137+
} else {
138+
applications::get_default_search_paths()
139+
};
140+
let mut ctx = AppInfoContext::new(default_search_path);
47141
ctx.refresh_apps().map_err(|err| err.to_string())?; // must refresh apps before getting them
48142
let apps = ctx.get_all_apps();
49143

0 commit comments

Comments
 (0)