mirror of
https://github.com/koodo-reader/koodo-reader.git
synced 2026-06-16 11:50:41 -04:00
feat: add book path selection feature in edit dialog
- Added a new field for selecting and displaying the book path in the edit dialog. - Integrated Electron's IPC to allow users to select a book path from the file system. - Updated the state management to include the book path and ensure it is saved with the book details. - Enhanced the UI to provide options for locating and selecting the book path. - Added corresponding styles for the new book path UI elements.
This commit is contained in:
6
main.js
6
main.js
@@ -689,6 +689,12 @@ const createMainWin = () => {
|
||||
});
|
||||
return path.filePaths[0];
|
||||
});
|
||||
ipcMain.handle("select-book-path", async (event) => {
|
||||
var result = await dialog.showOpenDialog({
|
||||
properties: ["openFile"],
|
||||
});
|
||||
return result.filePaths[0];
|
||||
});
|
||||
ipcMain.handle("encrypt-data", async (event, config) => {
|
||||
const { TokenService } =
|
||||
await import("./src/assets/lib/kookit-extra.min.mjs");
|
||||
|
||||
2
src/assets/lib/kookit-extra-browser.min.js
vendored
2
src/assets/lib/kookit-extra-browser.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -264,6 +264,7 @@
|
||||
"Get debug logs": "获取调试日志",
|
||||
"To enjoy a faster and seamless synchronization experience.": "享受更快速无缝的同步体验。",
|
||||
"Your reading progress, notes, highlights, bookmarks, and other data will be stored and synced through our cloud service. Your books and covers will still be synced by your added data sources. All your data will be encrypted and stored securely in our cloud. You can disable this feature anytime in the settings.": "您的阅读进度、笔记、高亮、书签等数据将通过我们的云服务进行存储和同步。您的图书和封面仍然会通过您添加的数据源进行同步。您所有的数据将被加密后安全地存储在我们的云端。您可以随时在设置中禁用此功能。",
|
||||
"Book path": "图书路径",
|
||||
"Data in other devices is messed up, but the data in this device is normal. You can reset the sync record in this device, delete the KoodoReader/config folder in the data source(Turn off Koodo Sync if necessary), and sync again. This should resolve the issue": "其他设备上数据有问题,但此设备中的数据是正常的。您可以在此设备中重置同步记录,删除数据源中的 KoodoReader/config 文件夹(如有必要,请关闭 Koodo Sync),然后重新同步",
|
||||
"Tasks failed after multiple retries, please check the network connection or reauthorize the data source in the settings": "多次重试后任务失败,请检查网络连接或在设置中重新绑定数据源",
|
||||
"This data source already contains a library. If you need to merge local and cloud data, please turn off Koodo Sync and resync.": "此数据源已经存在了一个图书库,如果需要将本地和云端的数据合并。请关闭 Koodo Sync 后重新同步。",
|
||||
|
||||
@@ -6,6 +6,8 @@ import { EditDialogProps, EditDialogState } from "./interface";
|
||||
import toast from "react-hot-toast";
|
||||
import DatabaseService from "../../../utils/storage/databaseService";
|
||||
import CoverUtil from "../../../utils/file/coverUtil";
|
||||
import { isElectron } from "react-device-detect";
|
||||
declare var window: any;
|
||||
|
||||
class EditDialog extends React.Component<EditDialogProps, EditDialogState> {
|
||||
private nameRef = React.createRef<HTMLInputElement>();
|
||||
@@ -16,7 +18,7 @@ class EditDialog extends React.Component<EditDialogProps, EditDialogState> {
|
||||
|
||||
constructor(props: EditDialogProps) {
|
||||
super(props);
|
||||
this.state = { isCheck: false, coverPreview: "" };
|
||||
this.state = { isCheck: false, coverPreview: "", bookPath: "" };
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -37,6 +39,7 @@ class EditDialog extends React.Component<EditDialogProps, EditDialogState> {
|
||||
if (cover) {
|
||||
this.setState({ coverPreview: cover });
|
||||
}
|
||||
this.setState({ bookPath: this.props.currentBook.path || "" });
|
||||
}
|
||||
|
||||
handleCancel = () => {
|
||||
@@ -54,6 +57,14 @@ class EditDialog extends React.Component<EditDialogProps, EditDialogState> {
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
handleSelectBookPath = async () => {
|
||||
if (!isElectron) return;
|
||||
const { ipcRenderer } = window.require("electron");
|
||||
const filePath = await ipcRenderer.invoke("select-book-path");
|
||||
if (!filePath) return;
|
||||
this.setState({ bookPath: filePath });
|
||||
};
|
||||
|
||||
handleComfirm = async () => {
|
||||
const name = this.nameRef.current?.value || "";
|
||||
const author = this.authorRef.current?.value || "";
|
||||
@@ -64,6 +75,9 @@ class EditDialog extends React.Component<EditDialogProps, EditDialogState> {
|
||||
this.props.currentBook.author = author;
|
||||
this.props.currentBook.publisher = publisher;
|
||||
this.props.currentBook.description = description;
|
||||
if (this.state.bookPath) {
|
||||
this.props.currentBook.path = this.state.bookPath;
|
||||
}
|
||||
|
||||
// Handle cover update: if user picked a new image (base64 data URL)
|
||||
const { coverPreview } = this.state;
|
||||
@@ -155,6 +169,51 @@ class EditDialog extends React.Component<EditDialogProps, EditDialogState> {
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Book path */}
|
||||
<div className="edit-dialog-field">
|
||||
<div className="edit-dialog-path-row">
|
||||
<span className="edit-dialog-label">
|
||||
<Trans>Book path</Trans>
|
||||
</span>
|
||||
{isElectron && (
|
||||
<div style={{ display: "flex", gap: "6px" }}>
|
||||
<span
|
||||
className="change-location-button"
|
||||
onClick={() => {
|
||||
const { ipcRenderer } = window.require("electron");
|
||||
ipcRenderer.invoke("open-explorer-folder", {
|
||||
path: this.state.bookPath,
|
||||
isFolder: false,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Trans>Locate</Trans>
|
||||
</span>
|
||||
<span
|
||||
className="change-location-button"
|
||||
onClick={this.handleSelectBookPath}
|
||||
>
|
||||
<Trans>Select</Trans>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="setting-dialog-location-title"
|
||||
style={{
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
margin: "0px",
|
||||
boxSizing: "border-box",
|
||||
marginTop: "4px",
|
||||
marginBottom: "4px",
|
||||
}}
|
||||
>
|
||||
{this.state.bookPath || "-"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="edit-dialog-footer">
|
||||
|
||||
@@ -97,6 +97,24 @@
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
/* Book path row */
|
||||
.edit-dialog-path-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.edit-dialog-path-value {
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
opacity: 0.7;
|
||||
line-height: 1.4;
|
||||
padding: 4px 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(120, 120, 120, 0.3);
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
/* Fixed footer with buttons */
|
||||
.edit-dialog-footer {
|
||||
display: flex;
|
||||
|
||||
@@ -14,4 +14,5 @@ export interface EditDialogProps extends RouteComponentProps<any> {
|
||||
export interface EditDialogState {
|
||||
isCheck: boolean;
|
||||
coverPreview: string;
|
||||
bookPath: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user