Compare commits

...

3 Commits

8 changed files with 85 additions and 58 deletions

33
src-tauri/Cargo.lock generated
View File

@ -332,6 +332,7 @@ dependencies = [
"chrono", "chrono",
"image", "image",
"md-5", "md-5",
"mime_guess",
"mountpoints", "mountpoints",
"once_cell", "once_cell",
"serde", "serde",
@ -341,6 +342,7 @@ dependencies = [
"tauri-build", "tauri-build",
"thiserror", "thiserror",
"tokio", "tokio",
"urlencoding",
"uuid 1.3.0", "uuid 1.3.0",
"walkdir", "walkdir",
] ]
@ -1616,6 +1618,22 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
dependencies = [
"mime",
"unicase",
]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.6.2" version = "0.6.2"
@ -3207,6 +3225,15 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.10" version = "0.3.10"
@ -3252,6 +3279,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "urlencoding"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
[[package]] [[package]]
name = "utf-8" name = "utf-8"
version = "0.7.6" version = "0.7.6"

View File

@ -14,7 +14,7 @@ tauri-build = { version = "1.2", features = [] }
[dependencies] [dependencies]
once_cell = "1.17.0" once_cell = "1.17.0"
tauri = { version = "1.2", features = ["dialog-open", "fs-exists", "fs-read-dir", "fs-read-file", "protocol-asset", "shell-open"] } tauri = { version = "1.2", features = ["dialog-open", "fs-exists", "fs-read-dir", "fs-read-file", "protocol-all", "shell-open"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
chrono = { version = "0.4.23", features = ["serde"] } chrono = { version = "0.4.23", features = ["serde"] }
@ -27,6 +27,8 @@ image = "0.24.5"
uuid = "1.3.0" uuid = "1.3.0"
mountpoints = "0.2.1" mountpoints = "0.2.1"
md-5 = "0.10.5" md-5 = "0.10.5"
urlencoding = "2.1.2"
mime_guess = "2.0.4"
[features] [features]
# this feature is used for production builds or when `devPath` points to the filesystem # this feature is used for production builds or when `devPath` points to the filesystem

View File

@ -2,13 +2,16 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod commands; mod commands;
mod protocol;
mod utils; mod utils;
use commands::AppHold; use commands::AppHold;
use protocol::comic_protocol;
use tauri::Manager; use tauri::Manager;
fn main() { fn main() {
tauri::Builder::default() tauri::Builder::default()
.register_uri_scheme_protocol("comic", comic_protocol)
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
commands::prelude::scan_directory, commands::prelude::scan_directory,
commands::prelude::show_drives, commands::prelude::show_drives,

42
src-tauri/src/protocol.rs Normal file
View File

@ -0,0 +1,42 @@
use std::{error::Error, fs, path::Path};
use tauri::{
http::{Request, Response, ResponseBuilder},
AppHandle, Runtime,
};
use urlencoding::decode;
pub fn comic_protocol<R: Runtime>(
_app_handler: &AppHandle<R>,
request: &Request,
) -> Result<Response, Box<dyn Error>> {
let response_builder = ResponseBuilder::new();
let path = request
.uri()
.strip_prefix("comic://localhost/")
.map(|u| decode(u).unwrap())
.unwrap();
println!("[debug]request: {}", path);
if path.len() == 0 {
return response_builder
.mimetype("text/plain")
.status(404)
.body(Vec::new());
}
let path = Path::new(path.as_ref());
if !path.exists() {
return response_builder
.mimetype("text/plain")
.status(404)
.body(Vec::new());
}
let mimetype = mime_guess::from_path(path);
let content = fs::read(path)?;
response_builder
.mimetype(mimetype.first_or_text_plain().essence_str())
.status(200)
.body(content)
}

View File

@ -29,11 +29,7 @@
"writeFile": false "writeFile": false
}, },
"protocol": { "protocol": {
"all": false, "all": true
"asset": true,
"assetScope": [
"*"
]
}, },
"shell": { "shell": {
"all": false, "all": false,
@ -66,7 +62,7 @@
} }
}, },
"security": { "security": {
"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost" "csp": null
}, },
"updater": { "updater": {
"active": false "active": false

View File

@ -7,7 +7,6 @@ import { FC, useMemo } from 'react';
import { useMount } from 'react-use'; import { useMount } from 'react-use';
import { DirTree } from './components/DirTree'; import { DirTree } from './components/DirTree';
import { FileList } from './components/FileList'; import { FileList } from './components/FileList';
import { FileToolbar } from './components/FileTools';
import { loadDrives } from './queries/directories'; import { loadDrives } from './queries/directories';
const bgSelectFn = ifElse( const bgSelectFn = ifElse(
@ -59,7 +58,6 @@ export const NavMenu: FC = () => {
</Tabs.Panel> </Tabs.Panel>
<Tabs.Panel value="files" h="100%"> <Tabs.Panel value="files" h="100%">
<Stack spacing={8} py={4} w="100%" h="100%" align="center"> <Stack spacing={8} py={4} w="100%" h="100%" align="center">
<FileToolbar />
<FileList /> <FileList />
</Stack> </Stack>
</Tabs.Panel> </Tabs.Panel>

View File

@ -1,48 +0,0 @@
//@ts-nocheck
import { Button, Group, Tooltip } from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { IconFolder } from '@tabler/icons-react';
import { invoke } from '@tauri-apps/api';
import { open } from '@tauri-apps/api/dialog';
import EventEmitter from 'events';
import { length } from 'ramda';
import { FC, useCallback, useContext } from 'react';
import { EventBusContext } from '../EventBus';
import { useFileListStore } from '../states/files';
export const FileToolbar: FC = () => {
const storeFiles = useFileListStore.use.updateFiles();
const ebus = useContext<EventEmitter>(EventBusContext);
const handleOpenAction = useCallback(async () => {
try {
const directory = await open({
title: '打开要浏览的漫画所在的文件夹',
directory: true,
multiple: false
});
const files = await invoke('scan_directory', { target: directory });
console.log('[debug]获取到文件个数:', length(files));
storeFiles(files);
ebus.emit('reset_views');
} catch (e) {
console.error('[error]打开文件夹', e);
notifications.show({ title: '未能成功打开指定文件夹,请重试。', color: 'red' });
}
}, [storeFiles]);
return (
<Group align="start" w="100%" spacing={4}>
<Tooltip label="打开漫画所在文件夹">
<Button
size="xs"
variant="subtle"
fullWidth
leftIcon={<IconFolder stroke={1.5} size={14} />}
onClick={handleOpenAction}
>
</Button>
</Tooltip>
</Group>
);
};

View File

@ -24,7 +24,8 @@ export const useFileListStore = createStoreHook<FileListState & FileListActions>
updateFiles(files) { updateFiles(files) {
set(df => { set(df => {
df.files = addIndex<Omit<FileItem, 'sort'>, FileItem>(map)( df.files = addIndex<Omit<FileItem, 'sort'>, FileItem>(map)(
(item, index) => mergeLeft({ sort: index * 10, path: convertFileSrc(item.path) }, item), (item, index) =>
mergeLeft({ sort: index * 10, path: convertFileSrc(item.path, 'comic') }, item),
files files
); );
df.actives = []; df.actives = [];