I have done the initial agera::file
module of my rich internet applications SDK.
While it does not yet include "Open/Save As" as file dialogs, it is generally usable and already includes alternatives to its common File
object, such as FileReference
, which builds for the web browser and native platforms. I have not experimented anything yet when exporting the actual application to an executable, installer or web application. I have not worked on exporting the application as well, however I am already embedding installation files for the web browser by using something like let _ = File::application_directory().resolve_path(path).write_async(include_bytes!(...)).await;
in a bootstrap code after pattern matching on installation files specified by the application descriptor (agera-application.json
).
It includes synchronous and asynchronous operations, where only the browsers do not support synchronous operations because of the use of the origin-private file system. Additionally, the file:
scheme for File
objects is only supported in native platforms.
Here is a demo: the following output is what I get in a test function when using app:
.
use agera::file::*;
for file in File::application_directory().directory_listing()? {
println!("{}", file.url());
}
app://Cargo.toml
app://README.md
app://src
Note that File::new("app://")
is equivalent to File::application_directory()
, just as File::new("app-storage://")
is equivalent to File::application_storage_directory()
.
- I have made it so that every
app:
File is read-only.
The app:
URI should resolve to the installation's directory, while app-storage:
should resolve to the data storage's directory. What concerns me is that I am not sure if I am choosing the best paths for the installation directory and storage directory.
Here is what I am doing for internally determining the application paths for File
across all platforms:
fn application_directory() -> String {
if_native_platform! {{
cfg_if! {
if #[cfg(target_os = "android")] {
let path = if let Some(p) = crate::platforms::application().external_data_path() { p } else { crate::platforms::application().internal_data_path().unwrap() };
path.join("installFiles").to_string_lossy().into_owned()
} else if #[cfg(debug_assertions)] {
std::env::current_dir().unwrap().to_str().unwrap().into()
} else if #[cfg(target_os = "windows")] {
// dirs::data_local_dir().unwrap().join(&crate::application::id()).to_string_lossy().into_owned()
std::path::PathBuf::from(&std::env::current_exe().unwrap()).parent().unwrap().to_str().unwrap().into()
} else {
dirs::data_dir().unwrap().join(&crate::application::id()).join("installFiles").to_string_lossy().into_owned()
}
}
}}
if_browser! {{
"/installFiles".into()
}}
}
fn application_storage_directory() -> String {
if_native_platform! {{
cfg_if! {
if #[cfg(target_os = "android")] {
let path = if let Some(p) = crate::platforms::application().external_data_path() { p } else { crate::platforms::application().internal_data_path().unwrap() };
path.join("storageFiles").to_string_lossy().into_owned()
} else if #[cfg(debug_assertions)] {
std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("agera_sdk_build/debug_storage_files").to_string_lossy().into_owned()
} else if #[cfg(target_os = "windows")] {
dirs::data_dir().unwrap().join(&crate::application::id()).to_string_lossy().into_owned()
} else {
dirs::data_dir().unwrap().join(&crate::application::id()).join("storageFiles").to_string_lossy().into_owned()
}
}
}}
if_browser! {{
"/storageFiles".into()
}}
}