Skip to content
Closed
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
38 changes: 38 additions & 0 deletions plugins/fs/android/src/main/java/FsPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ package com.plugin.fs
import android.annotation.SuppressLint
import android.app.Activity
import android.content.res.AssetManager.ACCESS_BUFFER
import android.database.Cursor
import android.net.Uri
import android.os.ParcelFileDescriptor
import android.provider.OpenableColumns
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
Expand All @@ -33,6 +35,11 @@ class GetFileDescriptorArgs {
lateinit var mode: String
}

@InvokeArg
class GetFileNameArgs {
lateinit var uri: String
}

@TauriPlugin
class FsPlugin(private val activity: Activity): Plugin(activity) {
@SuppressLint("Recycle")
Expand Down Expand Up @@ -89,5 +96,36 @@ class FsPlugin(private val activity: Activity): Plugin(activity) {
}
}
}

@Command
fun getFileName(invoke: Invoke) {
val args = invoke.parseArgs(GetFileNameArgs::class.java)
val res = JSObject()
val name = getRealNameFromURI(Uri.parse(args.uri))
res.put("name", name)
invoke.resolve(res)
}

fun getRealNameFromURI(contentUri: Uri): String? {
var cursor: Cursor? = null
try {
val projection = arrayOf(OpenableColumns.DISPLAY_NAME)
cursor = activity.contentResolver.query(contentUri, projection, null, null, null)

cursor?.let {
val columnIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (it.moveToFirst()) {
val FileName = it.getString(columnIndex)
return FileName
}
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
cursor?.close()
}

return null // Return null if no file name could be resolved
}
}

2 changes: 1 addition & 1 deletion plugins/fs/api-iife.js

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion plugins/fs/guest-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,13 @@ async function size(path: string | URL): Promise<number> {
})
}

/**
* Get the file name from a file path (desktop) or content URI (android)
*/
async function fileName(filepath: string | URL): Promise<string> {
return await invoke('plugin:fs|file_name', { filepath })
}

export type {
CreateOptions,
OpenOptions,
Expand Down Expand Up @@ -1395,5 +1402,6 @@ export {
exists,
watch,
watchImmediate,
size
size,
fileName
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ commands.allow = [
"read_text_file_lines_next",
"exists",
"scope-app-recursive",
"file_name",
]
10 changes: 9 additions & 1 deletion plugins/fs/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH},
};

use crate::{scope::Entry, Error, SafeFilePath};
use crate::{scope::Entry, Error, FsExt, SafeFilePath};

#[derive(Debug, thiserror::Error)]
pub enum CommandError {
Expand Down Expand Up @@ -1100,6 +1100,14 @@ fn is_forbidden<P: AsRef<Path>>(
}
}

#[tauri::command]
pub async fn file_name<R: Runtime>(
webview: Webview<R>,
filepath: SafeFilePath,
) -> Result<String, String> {
webview.fs().file_name(filepath)
}

struct StdFileResource(Mutex<File>);

impl StdFileResource {
Expand Down
17 changes: 16 additions & 1 deletion plugins/fs/src/desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::path::PathBuf;

use tauri::{AppHandle, Runtime};

use crate::{FilePath, OpenOptions};
use crate::{FilePath, OpenOptions, SafeFilePath};

pub struct Fs<R: Runtime>(pub(crate) AppHandle<R>);

Expand All @@ -32,4 +32,19 @@ impl<R: Runtime> Fs<R> {
let path = path_or_err(path)?;
std::fs::OpenOptions::from(opts).open(path)
}

pub fn file_name(&self, filepath: SafeFilePath) -> Result<String, String> {
match filepath {
SafeFilePath::Path(_) => {
let Some(filepath) = filepath.as_path() else {
return Err("failed to obtain filepath".into());
};
let Some(file_name) = filepath.file_name() else {
return Err("failed to get file_name from filepath".into());
};
Ok(file_name.to_string_lossy().to_string())
}
SafeFilePath::Url(_) => unreachable!(), // We do not obtain a URL path in desktop
}
}
}
1 change: 1 addition & 0 deletions plugins/fs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
commands::write_text_file,
commands::exists,
commands::size,
commands::file_name,
#[cfg(feature = "watch")]
watcher::watch,
#[cfg(feature = "watch")]
Expand Down
23 changes: 22 additions & 1 deletion plugins/fs/src/mobile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use tauri::{
AppHandle, Runtime,
};

use crate::{models::*, FilePath, OpenOptions};
use crate::{models::*, FilePath, OpenOptions, SafeFilePath};

#[cfg(target_os = "android")]
const PLUGIN_IDENTIFIER: &str = "com.plugin.fs";
Expand Down Expand Up @@ -93,4 +93,25 @@ impl<R: Runtime> Fs<R> {
}
}
}

pub fn file_name(&self, filepath: SafeFilePath) -> Result<String, String> {
let uri;
match filepath {
SafeFilePath::Path(_) => unreachable!(), // Modern android uses content URIs so getting a path is not possible
SafeFilePath::Url(url) => {
uri = url.to_string();
}
}
let Ok(result) = self
.0
.run_mobile_plugin::<GetFileNameResponse>("getFileName", GetFileNamePayload { uri })
else {
return Err("Failed to invoke getFileName kotlin function".into());
};
if let Some(name) = result.name {
Ok(name)
} else {
Err("Failed to get file name".into())
}
}
}
12 changes: 12 additions & 0 deletions plugins/fs/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ pub struct GetFileDescriptorPayload {
pub mode: String,
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetFileNamePayload {
pub uri: String,
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetFileDescriptorResponse {
pub fd: Option<i32>,
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetFileNameResponse {
pub name: Option<String>,
}