Add user settings management with custom DB path support

- Introduced `pastebar_settings.yaml` for storing user settings.
- Implemented commands for getting, setting, and removing the custom DB path.
- Added functionality to manage general key-value settings.
- Created a `UserConfig` struct to handle user settings serialization and deserialization.
- Implemented methods to load and save user configuration.
This commit is contained in:
Sergey Kurdin 2025-06-09 17:09:11 -04:00
parent 90e36f1761
commit 98d9673e30
14 changed files with 1227 additions and 237 deletions

210
package-lock.json generated
View File

@ -135,7 +135,7 @@
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@tailwindcss/line-clamp": "^0.4.4",
"@tauri-apps/cli": "^1.6.0",
"@tauri-apps/cli": "^1.6.3",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/bcryptjs": "^2.4.6",
"@types/codemirror": "^5.60.15",
@ -7000,10 +7000,14 @@
}
},
"node_modules/@tauri-apps/cli": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.0.tgz",
"integrity": "sha512-DBBpBl6GhTzm8ImMbKkfaZ4fDTykWrC7Q5OXP4XqD91recmDEn2LExuvuiiS3HYe7uP8Eb5B9NPHhqJb+Zo7qQ==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.3.tgz",
"integrity": "sha512-q46umd6QLRKDd4Gg6WyZBGa2fWvk0pbeUA5vFomm4uOs1/17LIciHv2iQ4UD+2Yv5H7AO8YiE1t50V0POiEGEw==",
"dev": true,
"license": "Apache-2.0 OR MIT",
"dependencies": {
"semver": ">=7.5.2"
},
"bin": {
"tauri": "tauri.js"
},
@ -7015,26 +7019,27 @@
"url": "https://opencollective.com/tauri"
},
"optionalDependencies": {
"@tauri-apps/cli-darwin-arm64": "1.6.0",
"@tauri-apps/cli-darwin-x64": "1.6.0",
"@tauri-apps/cli-linux-arm-gnueabihf": "1.6.0",
"@tauri-apps/cli-linux-arm64-gnu": "1.6.0",
"@tauri-apps/cli-linux-arm64-musl": "1.6.0",
"@tauri-apps/cli-linux-x64-gnu": "1.6.0",
"@tauri-apps/cli-linux-x64-musl": "1.6.0",
"@tauri-apps/cli-win32-arm64-msvc": "1.6.0",
"@tauri-apps/cli-win32-ia32-msvc": "1.6.0",
"@tauri-apps/cli-win32-x64-msvc": "1.6.0"
"@tauri-apps/cli-darwin-arm64": "1.6.3",
"@tauri-apps/cli-darwin-x64": "1.6.3",
"@tauri-apps/cli-linux-arm-gnueabihf": "1.6.3",
"@tauri-apps/cli-linux-arm64-gnu": "1.6.3",
"@tauri-apps/cli-linux-arm64-musl": "1.6.3",
"@tauri-apps/cli-linux-x64-gnu": "1.6.3",
"@tauri-apps/cli-linux-x64-musl": "1.6.3",
"@tauri-apps/cli-win32-arm64-msvc": "1.6.3",
"@tauri-apps/cli-win32-ia32-msvc": "1.6.3",
"@tauri-apps/cli-win32-x64-msvc": "1.6.3"
}
},
"node_modules/@tauri-apps/cli-darwin-arm64": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.0.tgz",
"integrity": "sha512-SNRwUD9nqGxY47mbY1CGTt/jqyQOU7Ps7Mx/mpgahL0FVUDiCEY/5L9QfEPPhEgccgcelEVn7i6aQHIkHyUtCA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.3.tgz",
"integrity": "sha512-fQN6IYSL8bG4NvkdKE4sAGF4dF/QqqQq4hOAU+t8ksOzHJr0hUlJYfncFeJYutr/MMkdF7hYKadSb0j5EE9r0A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
@ -7044,13 +7049,14 @@
}
},
"node_modules/@tauri-apps/cli-darwin-x64": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.0.tgz",
"integrity": "sha512-g2/uDR/eeH2arvuawA4WwaEOqv/7jDO/ZLNI3JlBjP5Pk8GGb3Kdy0ro1xQzF94mtk2mOnOXa4dMgAet4sUJ1A==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.3.tgz",
"integrity": "sha512-1yTXZzLajKAYINJOJhZfmMhCzweHSgKQ3bEgJSn6t+1vFkOgY8Yx4oFgWcybrrWI5J1ZLZAl47+LPOY81dLcyA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
@ -7060,13 +7066,14 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.0.tgz",
"integrity": "sha512-EVwf4oRkQyG8BpSrk0gqO7oA0sDM2MdNDtJpMfleYFEgCxLIOGZKNqaOW3M7U+0Y4qikmG3TtRK+ngc8Ymtrjg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.3.tgz",
"integrity": "sha512-CjTEr9r9xgjcvos09AQw8QMRPuH152B1jvlZt4PfAsyJNPFigzuwed5/SF7XAd8bFikA7zArP4UT12RdBxrx7w==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -7076,13 +7083,14 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.0.tgz",
"integrity": "sha512-YdpY17cAySrhK9dX4BUVEmhAxE2o+6skIEFg8iN/xrDwRxhaNPI9I80YXPatUTX54Kx55T5++25VJG9+3iw83A==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.3.tgz",
"integrity": "sha512-G9EUUS4M8M/Jz1UKZqvJmQQCKOzgTb8/0jZKvfBuGfh5AjFBu8LHvlFpwkKVm1l4951Xg4ulUp6P9Q7WRJ9XSA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -7092,13 +7100,14 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.0.tgz",
"integrity": "sha512-4U628tuf2U8pMr4tIBJhEkrFwt+46dwhXrDlpdyWSZtnop5RJAVKHODm0KbWns4xGKfTW1F3r6sSv+2ZxLcISA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.3.tgz",
"integrity": "sha512-MuBTHJyNpZRbPVG8IZBN8+Zs7aKqwD22tkWVBcL1yOGL4zNNTJlkfL+zs5qxRnHlUsn6YAlbW/5HKocfpxVwBw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -7108,13 +7117,14 @@
}
},
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.0.tgz",
"integrity": "sha512-AKRzp76fVUaJyXj5KRJT9bJyhwZyUnRQU0RqIRqOtZCT5yr6qGP8rjtQ7YhCIzWrseBlOllc3Qvbgw3Yl0VQcA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.3.tgz",
"integrity": "sha512-Uvi7M+NK3tAjCZEY1WGel+dFlzJmqcvu3KND+nqa22762NFmOuBIZ4KJR/IQHfpEYqKFNUhJfCGnpUDfiC3Oxg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -7124,13 +7134,14 @@
}
},
"node_modules/@tauri-apps/cli-linux-x64-musl": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.0.tgz",
"integrity": "sha512-0edIdq6aMBTaRMIXddHfyAFL361JqulLLd2Wi2aoOie7DkQ2MYh6gv3hA7NB9gqFwNIGE+xtJ4BkXIP2tSGPlg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.3.tgz",
"integrity": "sha512-rc6B342C0ra8VezB/OJom9j/N+9oW4VRA4qMxS2f4bHY2B/z3J9NPOe6GOILeg4v/CV62ojkLsC3/K/CeF3fqQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -7140,13 +7151,14 @@
}
},
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.0.tgz",
"integrity": "sha512-QwWpWk4ubcwJ1rljsRAmINgB2AwkyzZhpYbalA+MmzyYMREcdXWGkyixWbRZgqc6fEWEBmq5UG73qz5eBJiIKg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.3.tgz",
"integrity": "sha512-cSH2qOBYuYC4UVIFtrc1YsGfc5tfYrotoHrpTvRjUGu0VywvmyNk82+ZsHEnWZ2UHmu3l3lXIGRqSWveLln0xg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -7156,13 +7168,14 @@
}
},
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.0.tgz",
"integrity": "sha512-Vtw0yxO9+aEFuhuxQ57ALG43tjECopRimRuKGbtZYDCriB/ty5TrT3QWMdy0dxBkpDTu3Rqsz30sbDzw6tlP3Q==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.3.tgz",
"integrity": "sha512-T8V6SJQqE4PSWmYBl0ChQVmS6AR2hXFHURH2DwAhgSGSQ6uBXgwlYFcfIeQpBQA727K2Eq8X2hGfvmoySyHMRw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -7172,13 +7185,14 @@
}
},
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.0.tgz",
"integrity": "sha512-h54FHOvGi7+LIfRchzgZYSCHB1HDlP599vWXQQJ/XnwJY+6Rwr2E5bOe/EhqoG8rbGkfK0xX3KPAvXPbUlmggg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.3.tgz",
"integrity": "sha512-HUkWZ+lYHI/Gjkh2QjHD/OBDpqLVmvjZGpLK9losur1Eg974Jip6k+vsoTUxQBCBDfj30eDBct9E1FvXOspWeg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -7187,6 +7201,19 @@
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@ -22361,90 +22388,99 @@
"integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg=="
},
"@tauri-apps/cli": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.0.tgz",
"integrity": "sha512-DBBpBl6GhTzm8ImMbKkfaZ4fDTykWrC7Q5OXP4XqD91recmDEn2LExuvuiiS3HYe7uP8Eb5B9NPHhqJb+Zo7qQ==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.3.tgz",
"integrity": "sha512-q46umd6QLRKDd4Gg6WyZBGa2fWvk0pbeUA5vFomm4uOs1/17LIciHv2iQ4UD+2Yv5H7AO8YiE1t50V0POiEGEw==",
"dev": true,
"requires": {
"@tauri-apps/cli-darwin-arm64": "1.6.0",
"@tauri-apps/cli-darwin-x64": "1.6.0",
"@tauri-apps/cli-linux-arm-gnueabihf": "1.6.0",
"@tauri-apps/cli-linux-arm64-gnu": "1.6.0",
"@tauri-apps/cli-linux-arm64-musl": "1.6.0",
"@tauri-apps/cli-linux-x64-gnu": "1.6.0",
"@tauri-apps/cli-linux-x64-musl": "1.6.0",
"@tauri-apps/cli-win32-arm64-msvc": "1.6.0",
"@tauri-apps/cli-win32-ia32-msvc": "1.6.0",
"@tauri-apps/cli-win32-x64-msvc": "1.6.0"
"@tauri-apps/cli-darwin-arm64": "1.6.3",
"@tauri-apps/cli-darwin-x64": "1.6.3",
"@tauri-apps/cli-linux-arm-gnueabihf": "1.6.3",
"@tauri-apps/cli-linux-arm64-gnu": "1.6.3",
"@tauri-apps/cli-linux-arm64-musl": "1.6.3",
"@tauri-apps/cli-linux-x64-gnu": "1.6.3",
"@tauri-apps/cli-linux-x64-musl": "1.6.3",
"@tauri-apps/cli-win32-arm64-msvc": "1.6.3",
"@tauri-apps/cli-win32-ia32-msvc": "1.6.3",
"@tauri-apps/cli-win32-x64-msvc": "1.6.3",
"semver": ">=7.5.2"
},
"dependencies": {
"semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true
}
}
},
"@tauri-apps/cli-darwin-arm64": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.0.tgz",
"integrity": "sha512-SNRwUD9nqGxY47mbY1CGTt/jqyQOU7Ps7Mx/mpgahL0FVUDiCEY/5L9QfEPPhEgccgcelEVn7i6aQHIkHyUtCA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.3.tgz",
"integrity": "sha512-fQN6IYSL8bG4NvkdKE4sAGF4dF/QqqQq4hOAU+t8ksOzHJr0hUlJYfncFeJYutr/MMkdF7hYKadSb0j5EE9r0A==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-darwin-x64": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.0.tgz",
"integrity": "sha512-g2/uDR/eeH2arvuawA4WwaEOqv/7jDO/ZLNI3JlBjP5Pk8GGb3Kdy0ro1xQzF94mtk2mOnOXa4dMgAet4sUJ1A==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.3.tgz",
"integrity": "sha512-1yTXZzLajKAYINJOJhZfmMhCzweHSgKQ3bEgJSn6t+1vFkOgY8Yx4oFgWcybrrWI5J1ZLZAl47+LPOY81dLcyA==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-arm-gnueabihf": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.0.tgz",
"integrity": "sha512-EVwf4oRkQyG8BpSrk0gqO7oA0sDM2MdNDtJpMfleYFEgCxLIOGZKNqaOW3M7U+0Y4qikmG3TtRK+ngc8Ymtrjg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.3.tgz",
"integrity": "sha512-CjTEr9r9xgjcvos09AQw8QMRPuH152B1jvlZt4PfAsyJNPFigzuwed5/SF7XAd8bFikA7zArP4UT12RdBxrx7w==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-arm64-gnu": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.0.tgz",
"integrity": "sha512-YdpY17cAySrhK9dX4BUVEmhAxE2o+6skIEFg8iN/xrDwRxhaNPI9I80YXPatUTX54Kx55T5++25VJG9+3iw83A==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.3.tgz",
"integrity": "sha512-G9EUUS4M8M/Jz1UKZqvJmQQCKOzgTb8/0jZKvfBuGfh5AjFBu8LHvlFpwkKVm1l4951Xg4ulUp6P9Q7WRJ9XSA==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-arm64-musl": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.0.tgz",
"integrity": "sha512-4U628tuf2U8pMr4tIBJhEkrFwt+46dwhXrDlpdyWSZtnop5RJAVKHODm0KbWns4xGKfTW1F3r6sSv+2ZxLcISA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.3.tgz",
"integrity": "sha512-MuBTHJyNpZRbPVG8IZBN8+Zs7aKqwD22tkWVBcL1yOGL4zNNTJlkfL+zs5qxRnHlUsn6YAlbW/5HKocfpxVwBw==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-x64-gnu": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.0.tgz",
"integrity": "sha512-AKRzp76fVUaJyXj5KRJT9bJyhwZyUnRQU0RqIRqOtZCT5yr6qGP8rjtQ7YhCIzWrseBlOllc3Qvbgw3Yl0VQcA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.3.tgz",
"integrity": "sha512-Uvi7M+NK3tAjCZEY1WGel+dFlzJmqcvu3KND+nqa22762NFmOuBIZ4KJR/IQHfpEYqKFNUhJfCGnpUDfiC3Oxg==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-x64-musl": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.0.tgz",
"integrity": "sha512-0edIdq6aMBTaRMIXddHfyAFL361JqulLLd2Wi2aoOie7DkQ2MYh6gv3hA7NB9gqFwNIGE+xtJ4BkXIP2tSGPlg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.3.tgz",
"integrity": "sha512-rc6B342C0ra8VezB/OJom9j/N+9oW4VRA4qMxS2f4bHY2B/z3J9NPOe6GOILeg4v/CV62ojkLsC3/K/CeF3fqQ==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-win32-arm64-msvc": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.0.tgz",
"integrity": "sha512-QwWpWk4ubcwJ1rljsRAmINgB2AwkyzZhpYbalA+MmzyYMREcdXWGkyixWbRZgqc6fEWEBmq5UG73qz5eBJiIKg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.3.tgz",
"integrity": "sha512-cSH2qOBYuYC4UVIFtrc1YsGfc5tfYrotoHrpTvRjUGu0VywvmyNk82+ZsHEnWZ2UHmu3l3lXIGRqSWveLln0xg==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-win32-ia32-msvc": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.0.tgz",
"integrity": "sha512-Vtw0yxO9+aEFuhuxQ57ALG43tjECopRimRuKGbtZYDCriB/ty5TrT3QWMdy0dxBkpDTu3Rqsz30sbDzw6tlP3Q==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.3.tgz",
"integrity": "sha512-T8V6SJQqE4PSWmYBl0ChQVmS6AR2hXFHURH2DwAhgSGSQ6uBXgwlYFcfIeQpBQA727K2Eq8X2hGfvmoySyHMRw==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-win32-x64-msvc": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.0.tgz",
"integrity": "sha512-h54FHOvGi7+LIfRchzgZYSCHB1HDlP599vWXQQJ/XnwJY+6Rwr2E5bOe/EhqoG8rbGkfK0xX3KPAvXPbUlmggg==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.3.tgz",
"integrity": "sha512-HUkWZ+lYHI/Gjkh2QjHD/OBDpqLVmvjZGpLK9losur1Eg974Jip6k+vsoTUxQBCBDfj30eDBct9E1FvXOspWeg==",
"dev": true,
"optional": true
},

View File

@ -149,7 +149,7 @@
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@tailwindcss/line-clamp": "^0.4.4",
"@tauri-apps/cli": "^1.6.0",
"@tauri-apps/cli": "^1.6.3",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/bcryptjs": "^2.4.6",
"@types/codemirror": "^5.60.15",

File diff suppressed because one or more lines are too long

1
pastebar_settings.yaml Normal file
View File

@ -0,0 +1 @@
custom_db_path: "/Users/kurdin/"

222
src-tauri/Cargo.lock generated
View File

@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9c1d770875c536934a8e7150061b0dbddb919298f0ff762b0f8fc12c8928877"
dependencies = [
"appkit-nsworkspace-bindings",
"core-foundation",
"core-foundation 0.9.4",
"core-graphics 0.23.2",
"objc",
"windows 0.48.0",
@ -549,9 +549,9 @@ dependencies = [
[[package]]
name = "brotli"
version = "3.5.0"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@ -560,9 +560,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
version = "2.5.1"
version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@ -816,8 +816,8 @@ checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
dependencies = [
"bitflags 1.3.2",
"block",
"cocoa-foundation",
"core-foundation",
"cocoa-foundation 0.1.2",
"core-foundation 0.9.4",
"core-graphics 0.22.3",
"foreign-types 0.3.2",
"libc",
@ -826,15 +826,15 @@ dependencies = [
[[package]]
name = "cocoa"
version = "0.25.0"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
checksum = "ad36507aeb7e16159dfe68db81ccc27571c3ccd4b76fb2fb72fc59e7a4b1b64c"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.6.0",
"block",
"cocoa-foundation",
"core-foundation",
"core-graphics 0.23.2",
"cocoa-foundation 0.2.1",
"core-foundation 0.10.1",
"core-graphics 0.24.0",
"foreign-types 0.5.0",
"libc",
"objc",
@ -848,12 +848,25 @@ checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
dependencies = [
"bitflags 1.3.2",
"block",
"core-foundation",
"core-graphics-types",
"core-foundation 0.9.4",
"core-graphics-types 0.1.3",
"libc",
"objc",
]
[[package]]
name = "cocoa-foundation"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81411967c50ee9a1fc11365f8c585f863a22a9697c89239c452292c40ba79b0d"
dependencies = [
"bitflags 2.6.0",
"block",
"core-foundation 0.10.1",
"core-graphics-types 0.2.0",
"objc",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@ -938,6 +951,16 @@ dependencies = [
"libc",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
@ -951,8 +974,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-graphics-types",
"core-foundation 0.9.4",
"core-graphics-types 0.1.3",
"foreign-types 0.3.2",
"libc",
]
@ -964,8 +987,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-graphics-types",
"core-foundation 0.9.4",
"core-graphics-types 0.1.3",
"foreign-types 0.5.0",
"libc",
]
[[package]]
name = "core-graphics"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
dependencies = [
"bitflags 2.6.0",
"core-foundation 0.10.1",
"core-graphics-types 0.2.0",
"foreign-types 0.5.0",
"libc",
]
@ -977,7 +1013,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation 0.9.4",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
"bitflags 2.6.0",
"core-foundation 0.10.1",
"libc",
]
@ -1588,6 +1635,15 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "fluent-uri"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "flume"
version = "0.11.0"
@ -2450,9 +2506,9 @@ dependencies = [
[[package]]
name = "ico"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae"
checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98"
dependencies = [
"byteorder",
"png",
@ -2581,15 +2637,6 @@ dependencies = [
"serde",
]
[[package]]
name = "infer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f178e61cdbfe084aa75a2f4f7a25a5bb09701a47ae1753608f194b15783c937a"
dependencies = [
"cfb",
]
[[package]]
name = "infer"
version = "0.13.0"
@ -2809,6 +2856,18 @@ dependencies = [
"thiserror",
]
[[package]]
name = "json-patch"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc"
dependencies = [
"jsonptr",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "jsonpath-rust"
version = "0.4.0"
@ -2822,6 +2881,17 @@ dependencies = [
"thiserror",
]
[[package]]
name = "jsonptr"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627"
dependencies = [
"fluent-uri",
"serde",
"serde_json",
]
[[package]]
name = "keyring"
version = "2.3.3"
@ -3053,7 +3123,7 @@ name = "macos-accessibility-client"
version = "0.0.1"
source = "git+https://github.com/kurdin/macos-accessibility-client?branch=master#03025a91c471d4a115ad116739a8576216e527e2"
dependencies = [
"core-foundation",
"core-foundation 0.9.4",
"core-foundation-sys",
]
@ -3881,7 +3951,7 @@ dependencies = [
"chrono",
"clipboard-master",
"clokwerk",
"cocoa 0.25.0",
"cocoa 0.26.1",
"colored_json",
"diesel",
"diesel_migrations",
@ -4874,7 +4944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.6.0",
"core-foundation",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
"security-framework-sys",
@ -5048,9 +5118,9 @@ dependencies = [
[[package]]
name = "serialize-to-javascript"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb"
checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5"
dependencies = [
"serde",
"serde_json",
@ -5059,13 +5129,13 @@ dependencies = [
[[package]]
name = "serialize-to-javascript-impl"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.72",
]
[[package]]
@ -5355,15 +5425,11 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sys-locale"
version = "0.2.4"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"js-sys",
"libc",
"wasm-bindgen",
"web-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -5373,7 +5439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation 0.9.4",
"system-configuration-sys",
]
@ -5427,7 +5493,7 @@ dependencies = [
"cairo-rs",
"cc",
"cocoa 0.24.1",
"core-foundation",
"core-foundation 0.9.4",
"core-graphics 0.22.3",
"crossbeam-channel",
"dirs-next 2.0.0",
@ -5503,12 +5569,12 @@ dependencies = [
[[package]]
name = "tauri"
version = "1.7.1"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "336bc661a3f3250853fa83c6e5245449ed1c26dce5dcb28bdee7efedf6278806"
checksum = "3ae1f57c291a6ab8e1d2e6b8ad0a35ff769c9925deb8a89de85425ff08762d0c"
dependencies = [
"anyhow",
"base64 0.21.7",
"base64 0.22.1",
"bytes 1.7.1",
"cocoa 0.24.1",
"dirs-next 2.0.0",
@ -5525,7 +5591,8 @@ dependencies = [
"http",
"ignore",
"indexmap 1.9.3",
"infer 0.9.0",
"infer",
"log",
"minisign-verify",
"nix 0.26.4",
"notify-rust",
@ -5535,6 +5602,7 @@ dependencies = [
"os_info",
"os_pipe",
"percent-encoding",
"plist",
"png",
"rand 0.8.5",
"raw-window-handle",
@ -5576,7 +5644,7 @@ dependencies = [
"cargo_toml",
"dirs-next 2.0.0",
"heck 0.5.0",
"json-patch",
"json-patch 1.4.0",
"semver",
"serde",
"serde_json",
@ -5587,14 +5655,14 @@ dependencies = [
[[package]]
name = "tauri-codegen"
version = "1.4.4"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1aed706708ff1200ec12de9cfbf2582b5d8ec05f6a7293911091effbd22036b"
checksum = "53438d78c4a037ffe5eafa19e447eea599bedfb10844cb08ec53c2471ac3ac3f"
dependencies = [
"base64 0.21.7",
"brotli",
"ico",
"json-patch",
"json-patch 2.0.0",
"plist",
"png",
"proc-macro2",
@ -5613,9 +5681,9 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "1.4.5"
version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88f831d2973ae4f81a706a0004e67dac87f2e4439973bbe98efbd73825d8ede"
checksum = "233988ac08c1ed3fe794cd65528d48d8f7ed4ab3895ca64cdaa6ad4d00c45c0b"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@ -5651,9 +5719,9 @@ dependencies = [
[[package]]
name = "tauri-runtime"
version = "0.14.4"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3068ed62b63dedc705558f4248c7ecbd5561f0f8050949859ea0db2326f26012"
checksum = "8066855882f00172935e3fa7d945126580c34dcbabab43f5d4f0c2398a67d47b"
dependencies = [
"gtk",
"http",
@ -5672,9 +5740,9 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
version = "0.14.9"
version = "0.14.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c3db170233096aa30330feadcd895bf9317be97e624458560a20e814db7955"
checksum = "ce361fec1e186705371f1c64ae9dd2a3a6768bc530d0a2d5e75a634bb416ad4d"
dependencies = [
"arboard",
"cocoa 0.24.1",
@ -5693,9 +5761,9 @@ dependencies = [
[[package]]
name = "tauri-utils"
version = "1.6.0"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2826db448309d382dac14d520f0c0a40839b87b57b977e59cf5f296b3ace6a93"
checksum = "c357952645e679de02cd35007190fcbce869b93ffc61b029f33fe02648453774"
dependencies = [
"brotli",
"ctor",
@ -5703,8 +5771,8 @@ dependencies = [
"glob",
"heck 0.5.0",
"html5ever 0.26.0",
"infer 0.13.0",
"json-patch",
"infer",
"json-patch 2.0.0",
"kuchikiki",
"log",
"memchr",
@ -6806,15 +6874,6 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@ -6842,21 +6901,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.5"

View File

@ -8,7 +8,7 @@ edition = "2021"
rust-version = "1.75.0"
[build-dependencies.tauri-build]
version = "1.4"
version = "1.5"
features = []
[target.'cfg(target_os = "windows")'.dependencies]
@ -40,7 +40,7 @@ reqwest = "0.11.12"
nanoid = "0.4.0"
anyhow = "1.0.66"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.7.1", features = [ "api-all", "system-tray", "icon-png", "clipboard", "updater", "reqwest-client"] }
tauri = { version = "1.8.3", features = [ "api-all", "system-tray", "icon-png", "clipboard", "updater", "reqwest-client"] }
tokio = { version = "1.28.2", features = ["full"] }
#single-instance = "0.3.3"
@ -89,7 +89,7 @@ html-escape = "0.2.13"
[target.'cfg(target_os = "macos")'.dependencies]
macos-accessibility-client = { git = "https://github.com/kurdin/macos-accessibility-client", branch = "master", version = "0.0.1" }
objc = "0.2.7"
cocoa = "0.25.0"
cocoa = "0.26.1"
[target.'cfg(target_os = "linux")'.dependencies]
inputbotlinux = { path = "libs/inputbotlinux" }

View File

@ -299,58 +299,7 @@ impl ClipboardManager {
clipboard.set_text(text).map_err(|err| err.to_string())
}
pub fn read_image(&self) -> Result<String, String> {
let mut clipboard = Clipboard::new().unwrap();
let image = clipboard.get_image().map_err(|err| err.to_string())?;
let tmp_dir = tempfile::Builder::new()
.prefix("clipboard-img")
.tempdir()
.map_err(|err| err.to_string())?;
let fname = tmp_dir.path().join("clipboard-img.png");
let image2: RgbaImage = ImageBuffer::from_raw(
image.width.try_into().unwrap(),
image.height.try_into().unwrap(),
image.bytes.into_owned(),
)
.unwrap();
image2.save(fname.clone()).map_err(|err| err.to_string())?;
let mut file = File::open(fname.clone()).unwrap();
let mut buffer = vec![];
file.read_to_end(&mut buffer).unwrap();
let base64_str = general_purpose::STANDARD_NO_PAD.encode(buffer);
Ok(base64_str)
}
pub fn get_image_binary(&self) -> Result<ImageData, String> {
let mut clipboard = Clipboard::new().unwrap();
let image_data = clipboard.get_image().map_err(|err| err.to_string())?;
Ok(image_data)
}
pub fn read_image_binary(&self) -> Result<Vec<u8>, String> {
let mut clipboard = Clipboard::new().unwrap();
let image = clipboard.get_image().map_err(|err| err.to_string())?;
let tmp_dir = tempfile::Builder::new()
.prefix("clipboard-img")
.tempdir()
.map_err(|err| err.to_string())?;
let fname = tmp_dir.path().join("clipboard-img.png");
let image2: RgbaImage = ImageBuffer::from_raw(
image.width.try_into().unwrap(),
image.height.try_into().unwrap(),
image.bytes.into_owned(),
)
.unwrap();
image2.save(fname.clone()).map_err(|err| err.to_string())?;
let mut file = File::open(fname.clone()).unwrap();
let mut buffer = vec![];
file.read_to_end(&mut buffer).unwrap();
Ok(buffer)
}
// write_image function remains unchanged as it's writing, not reading
pub fn write_image(&self, base64_image: String) -> Result<(), String> {
let mut clipboard = Clipboard::new().unwrap();
let decoded = general_purpose::STANDARD_NO_PAD
@ -373,6 +322,139 @@ impl ClipboardManager {
.map_err(|err| err.to_string())?;
Ok(())
}
pub fn read_image(&self) -> Result<String, String> {
let mut clipboard = Clipboard::new().unwrap();
let image = clipboard.get_image().map_err(|err| err.to_string())?;
// Handle stride alignment
let bytes_per_pixel = 4; // RGBA
let expected_bytes_per_row = image.width * bytes_per_pixel;
let actual_bytes_per_row = image.bytes.len() / image.height;
let cleaned_bytes = if actual_bytes_per_row != expected_bytes_per_row {
// Remove stride padding
let mut cleaned = Vec::with_capacity(expected_bytes_per_row * image.height);
for row in 0..image.height {
let row_start = row * actual_bytes_per_row;
let row_end = row_start + expected_bytes_per_row;
cleaned.extend_from_slice(&image.bytes[row_start..row_end]);
}
cleaned
} else {
image.bytes.into_owned()
};
// Create image from cleaned bytes
let image2: RgbaImage = ImageBuffer::from_raw(
image.width.try_into().unwrap(),
image.height.try_into().unwrap(),
cleaned_bytes,
)
.ok_or_else(|| "Failed to create image from raw bytes".to_string())?;
// Save to temporary file and encode as base64
let tmp_dir = tempfile::Builder::new()
.prefix("clipboard-img")
.tempdir()
.map_err(|err| err.to_string())?;
let fname = tmp_dir.path().join("clipboard-img.png");
image2.save(&fname).map_err(|err| err.to_string())?;
let mut file = File::open(&fname).map_err(|err| err.to_string())?;
let mut buffer = vec![];
file
.read_to_end(&mut buffer)
.map_err(|err| err.to_string())?;
let base64_str = general_purpose::STANDARD_NO_PAD.encode(buffer);
Ok(base64_str)
}
pub fn get_image_binary(&self) -> Result<ImageData, String> {
let mut clipboard = Clipboard::new().unwrap();
let image_data = clipboard.get_image().map_err(|err| err.to_string())?;
// Only check for stride alignment on Windows
#[cfg(target_os = "windows")]
{
let bytes_per_pixel = 4; // RGBA
let expected_bytes_per_row = image_data.width * bytes_per_pixel;
let actual_bytes_per_row = image_data.bytes.len() / image_data.height;
if actual_bytes_per_row != expected_bytes_per_row {
// We have stride padding, need to remove it
let mut cleaned_bytes = Vec::with_capacity(expected_bytes_per_row * image_data.height);
for row in 0..image_data.height {
let row_start = row * actual_bytes_per_row;
let row_end = row_start + expected_bytes_per_row;
cleaned_bytes.extend_from_slice(&image_data.bytes[row_start..row_end]);
}
return Ok(ImageData {
width: image_data.width,
height: image_data.height,
bytes: Cow::Owned(cleaned_bytes),
});
}
}
// For macOS, Linux, and Windows without padding, return as-is
Ok(image_data)
}
// Function 2: Returns Vec<u8> of PNG file data
pub fn read_image_binary(&self) -> Result<Vec<u8>, String> {
let mut clipboard = Clipboard::new().unwrap();
let image = clipboard.get_image().map_err(|err| err.to_string())?;
// Handle stride alignment
let bytes_per_pixel = 4; // RGBA
let expected_bytes_per_row = image.width * bytes_per_pixel;
let actual_bytes_per_row = image.bytes.len() / image.height;
let cleaned_bytes = if actual_bytes_per_row != expected_bytes_per_row {
// Remove stride padding
let mut cleaned = Vec::with_capacity(expected_bytes_per_row * image.height);
for row in 0..image.height {
let row_start = row * actual_bytes_per_row;
let row_end = row_start + expected_bytes_per_row;
cleaned.extend_from_slice(&image.bytes[row_start..row_end]);
}
cleaned
} else {
image.bytes.into_owned()
};
// Create image from cleaned bytes
let image2: RgbaImage = ImageBuffer::from_raw(
image.width.try_into().unwrap(),
image.height.try_into().unwrap(),
cleaned_bytes,
)
.ok_or_else(|| "Failed to create image from raw bytes".to_string())?;
// Save to temporary file and read back
let tmp_dir = tempfile::Builder::new()
.prefix("clipboard-img")
.tempdir()
.map_err(|err| err.to_string())?;
let fname = tmp_dir.path().join("clipboard-img.png");
image2.save(&fname).map_err(|err| err.to_string())?;
let mut file = File::open(&fname).map_err(|err| err.to_string())?;
let mut buffer = vec![];
file
.read_to_end(&mut buffer)
.map_err(|err| err.to_string())?;
Ok(buffer)
}
}
/// Initializes the plugin.

View File

@ -9,3 +9,4 @@ pub(crate) mod security_commands;
pub(crate) mod shell_commands;
pub(crate) mod tabs_commands;
pub(crate) mod translations_commands;
pub(crate) mod user_settings_command;

View File

@ -0,0 +1,57 @@
use serde_yaml::Value;
use std::collections::HashMap;
use tauri::command;
use crate::services::user_settings_service::{
get_all_settings, get_custom_db_path, get_setting, remove_custom_db_path, remove_setting,
set_custom_db_path, set_setting,
};
/// Returns the current `custom_db_path` (if any).
#[command]
pub fn cmd_get_custom_db_path() -> Option<String> {
get_custom_db_path()
}
/// Insert or update a new `custom_db_path`.
#[command]
pub fn cmd_set_custom_db_path(new_path: String) -> Result<(), String> {
set_custom_db_path(&new_path)
}
/// Remove (clear) the `custom_db_path`.
#[command]
pub fn cmd_remove_custom_db_path() -> Result<(), String> {
remove_custom_db_path()
}
/// Return all key-value pairs from the `data` map.
#[command]
pub fn cmd_get_all_settings() -> HashMap<String, Value> {
get_all_settings()
}
/// Return a single setting by key (from the `data` map).
#[command]
pub fn cmd_get_setting(key: String) -> Option<Value> {
get_setting(&key)
}
/// Insert (or update) a setting in the `data` map.
/// `value_yaml` is a string containing valid YAML (e.g. `"true"`, `"42"`, `"some string"`).
#[command]
pub fn cmd_set_setting(key: String, value_yaml: String) -> Result<(), String> {
// If your front end only sends strings,
// you could store them directly as `Value::String(value_yaml)`.
// But here we parse the YAML so you can handle booleans, numbers, etc.
match serde_yaml::from_str::<Value>(&value_yaml) {
Ok(val) => set_setting(&key, val),
Err(e) => Err(format!("Failed to parse YAML string: {}", e)),
}
}
/// Remove a setting by key from the `data` map.
#[command]
pub fn cmd_remove_setting(key: String) -> Result<(), String> {
remove_setting(&key)
}

View File

@ -10,6 +10,7 @@ use diesel::connection::SimpleConnection;
use diesel::prelude::*;
use diesel::r2d2 as diesel_r2d2;
use crate::services::user_settings_service::load_user_config;
use diesel::sqlite::SqliteConnection;
// use diesel::connection::{set_default_instrumentation, Instrumentation, InstrumentationEvent};
@ -61,7 +62,7 @@ impl diesel::r2d2::CustomizeConnection<SqliteConnection, diesel::r2d2::Error>
}
}
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
pub fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
const VERBATIM_PREFIX: &str = r#"\\?\"#;
let p = p.as_ref().display().to_string();
if p.starts_with(VERBATIM_PREFIX) {
@ -217,6 +218,22 @@ fn db_file_exists() -> bool {
}
fn get_db_path() -> String {
let user_config = load_user_config();
if let Some(custom_path) = user_config.custom_db_path {
let final_path = adjust_custom_db_path(&custom_path);
// Check if it's valid/writable
if can_access_or_create(&final_path) {
return final_path;
} else {
eprintln!(
"Warning: custom_db_path=\"{}\" is invalid or not writable. Falling back to default...",
custom_path
);
}
}
if cfg!(debug_assertions) {
let app_dir = APP_CONSTANTS.get().unwrap().app_dev_data_dir.clone();
let path = if cfg!(target_os = "macos") {
@ -253,6 +270,101 @@ fn get_db_path() -> String {
}
}
fn can_access_or_create(db_path: &str) -> bool {
let path = std::path::Path::new(db_path);
if let Some(parent) = path.parent() {
if let Err(e) = std::fs::create_dir_all(parent) {
eprintln!(
"Failed to create parent directory '{}': {}",
parent.display(),
e
);
return false;
}
}
match std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
{
Ok(_file) => true,
Err(e) => {
eprintln!("Failed to open custom DB path '{}': {}", db_path, e);
false
}
}
}
fn adjust_custom_db_path(custom_path: &str) -> String {
use std::path::PathBuf;
let path = PathBuf::from(custom_path);
match fs::metadata(&path) {
Ok(metadata) => {
if metadata.is_dir() {
// It's a directory, so append "pastebar-db.data" to it
let mut dir_path = path.clone();
dir_path.push("pastebar-db.data");
dir_path.to_string_lossy().into_owned()
} else {
// It's a file or symlink, so leave it as is
custom_path.to_string()
}
}
Err(_) => {
// If we cant read metadata (e.g. it doesn't exist yet),
// we treat `custom_path` as a file path already.
custom_path.to_string()
}
}
}
pub fn get_config_file_path() -> PathBuf {
if cfg!(debug_assertions) {
let app_dir = APP_CONSTANTS.get().unwrap().app_dev_data_dir.clone();
if cfg!(target_os = "macos") {
PathBuf::from(format!(
"{}/pastebar_settings.yaml",
adjust_canonicalization(app_dir)
))
} else if cfg!(target_os = "windows") {
PathBuf::from(format!(
"{}\\pastebar_settings.yaml",
adjust_canonicalization(app_dir)
))
} else {
PathBuf::from(format!(
"{}/pastebar_settings.yaml",
adjust_canonicalization(app_dir)
))
}
} else {
// Release mode
let app_data_dir = APP_CONSTANTS.get().unwrap().app_data_dir.clone();
let data_dir = app_data_dir.as_path();
if cfg!(target_os = "macos") {
PathBuf::from(format!(
"{}/pastebar_settings.yaml",
adjust_canonicalization(data_dir)
))
} else if cfg!(target_os = "windows") {
PathBuf::from(format!(
"{}\\pastebar_settings.yaml",
adjust_canonicalization(data_dir)
))
} else {
PathBuf::from(format!(
"{}/pastebar_settings.yaml",
adjust_canonicalization(data_dir)
))
}
}
}
// fn simple_sql_logger() -> Option<Box<dyn Instrumentation>> {
// Some(Box::new(
// move |event: InstrumentationEvent<'_>| match event {

View File

@ -63,6 +63,8 @@ use commands::security_commands;
use commands::shell_commands;
use commands::tabs_commands;
use commands::translations_commands;
use commands::user_settings_command;
use db::AppConstants;
use mouse_position::mouse_position::Mouse;
use std::collections::HashMap;
@ -1182,6 +1184,13 @@ async fn main() {
security_commands::verify_os_password,
security_commands::delete_os_password,
security_commands::get_stored_os_password,
user_settings_command::cmd_get_custom_db_path,
user_settings_command::cmd_set_custom_db_path,
user_settings_command::cmd_remove_custom_db_path,
user_settings_command::cmd_get_all_settings,
user_settings_command::cmd_get_setting,
user_settings_command::cmd_set_setting,
user_settings_command::cmd_remove_setting,
open_osx_accessibility_preferences,
check_osx_accessibility_preferences,
open_path_or_app,

View File

@ -7,4 +7,5 @@ pub mod settings_service;
pub mod shell_service;
pub mod tabs_service;
pub mod translations;
pub mod user_settings_service;
pub mod utils;

View File

@ -0,0 +1,99 @@
use serde::{Deserialize, Serialize};
use serde_yaml;
use std::collections::HashMap;
use crate::db::get_config_file_path;
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct UserConfig {
/// The custom DB path, if user specified one.
pub custom_db_path: Option<String>,
/// General-purpose key-value settings.
#[serde(default)]
pub data: HashMap<String, serde_yaml::Value>,
}
pub fn load_user_config() -> UserConfig {
let path = get_config_file_path();
if !path.exists() {
return UserConfig::default();
}
match std::fs::read_to_string(&path) {
Ok(contents) => match serde_yaml::from_str::<UserConfig>(&contents) {
Ok(cfg) => cfg,
Err(e) => {
eprintln!("Error parsing user config YAML: {:#}", e);
UserConfig::default()
}
},
Err(e) => {
eprintln!("Error reading user config file: {:#}", e);
UserConfig::default()
}
}
}
/// Save the `UserConfig` back to `pastebar_settings.yaml`.
pub fn save_user_config(cfg: &UserConfig) -> Result<(), String> {
let path = get_config_file_path();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.map_err(|e| format!("Failed to create config directory: {}", e))?;
}
let yaml_str =
serde_yaml::to_string(cfg).map_err(|e| format!("Failed to serialize config to YAML: {}", e))?;
std::fs::write(&path, yaml_str).map_err(|e| format!("Failed to write config file: {}", e))?;
Ok(())
}
// ===========================
// Custom DB Path Methods
// ===========================
/// Get the current `custom_db_path` (if any).
pub fn get_custom_db_path() -> Option<String> {
load_user_config().custom_db_path
}
/// Insert or update the `custom_db_path`.
pub fn set_custom_db_path(new_path: &str) -> Result<(), String> {
let mut config = load_user_config();
config.custom_db_path = Some(new_path.to_string());
save_user_config(&config)
}
/// Remove (clear) the `custom_db_path`.
pub fn remove_custom_db_path() -> Result<(), String> {
let mut config = load_user_config();
config.custom_db_path = None;
save_user_config(&config)
}
// ===========================
// KeyValue data Methods
// ===========================
pub fn get_setting(key: &str) -> Option<serde_yaml::Value> {
let config = load_user_config();
config.data.get(key).cloned()
}
pub fn set_setting(key: &str, value: serde_yaml::Value) -> Result<(), String> {
let mut config = load_user_config();
config.data.insert(key.to_string(), value);
save_user_config(&config)
}
pub fn remove_setting(key: &str) -> Result<(), String> {
let mut config = load_user_config();
config.data.remove(key);
save_user_config(&config)
}
pub fn get_all_settings() -> HashMap<String, serde_yaml::Value> {
load_user_config().data
}

View File

@ -39,11 +39,32 @@ impl<R: Runtime> WindowToolBar for Window<R> {
let miniaturize = window.standardWindowButton_(NSWindowButton::NSWindowMiniaturizeButton);
let zoom = window.standardWindowButton_(NSWindowButton::NSWindowZoomButton);
window
.standardWindowButton_(NSWindowButton::NSWindowDocumentIconButton)
.setCanHide_(cocoa::base::YES);
// Check if standard buttons exist
if close.is_null() || miniaturize.is_null() || zoom.is_null() {
eprintln!("Warning: Window buttons are null, skipping traffic light positioning");
return;
}
let title_bar_container_view = close.superview().superview();
let document_icon = window.standardWindowButton_(NSWindowButton::NSWindowDocumentIconButton);
if !document_icon.is_null() {
let mut doc_rect: NSRect = NSView::frame(document_icon);
doc_rect.origin.x = -200.0; // Move it off-screen
// document_icon.setFrameOrigin(doc_rect.origin);
// document_icon.setCanHide_(cocoa::base::YES);
}
// Check superviews exist
let superview = close.superview();
if superview.is_null() {
eprintln!("Warning: Close button superview is null");
return;
}
let title_bar_container_view = superview.superview();
if title_bar_container_view.is_null() {
eprintln!("Warning: Title bar container view is null");
return;
}
let close_rect: NSRect = msg_send![close, frame];
let button_height = close_rect.size.height;