From e752ebbaebad99314ee22289be1042b0249771e7 Mon Sep 17 00:00:00 2001 From: CodeDoctorDE Date: Wed, 1 Jan 2025 12:48:04 +0100 Subject: [PATCH] Add option to import svg as text, closes #596 --- api/lib/src/models/tool.dart | 2 +- api/lib/src/models/tool.g.dart | 1 + app/lib/handlers/asset.dart | 41 ++++++++++++++++++++ app/lib/l10n/app_en.arb | 3 +- app/lib/visualizer/tool.dart | 2 + app/pubspec.lock | 4 +- docs/pnpm-lock.yaml | 62 +++++++++++++++---------------- metadata/en-US/changelogs/127.txt | 1 + 8 files changed, 81 insertions(+), 35 deletions(-) diff --git a/api/lib/src/models/tool.dart b/api/lib/src/models/tool.dart index 437ecc2d66eb..b7c4875ebf25 100644 --- a/api/lib/src/models/tool.dart +++ b/api/lib/src/models/tool.dart @@ -37,7 +37,7 @@ enum LabelMode { markdown, text } enum Axis2D { horizontal, vertical } -enum ImportType { image, camera, svg, pdf, document, markdown, xopp } +enum ImportType { image, camera, svg, svgText, pdf, document, markdown, xopp } enum SelectMode { rectangle, lasso } diff --git a/api/lib/src/models/tool.g.dart b/api/lib/src/models/tool.g.dart index f87f64628ad5..d8aca3cbe3fc 100644 --- a/api/lib/src/models/tool.g.dart +++ b/api/lib/src/models/tool.g.dart @@ -375,6 +375,7 @@ const _$ImportTypeEnumMap = { ImportType.image: 'image', ImportType.camera: 'camera', ImportType.svg: 'svg', + ImportType.svgText: 'svgText', ImportType.pdf: 'pdf', ImportType.document: 'document', ImportType.markdown: 'markdown', diff --git a/app/lib/handlers/asset.dart b/app/lib/handlers/asset.dart index ab3a1271e175..40c570bd35e5 100644 --- a/app/lib/handlers/asset.dart +++ b/app/lib/handlers/asset.dart @@ -48,6 +48,47 @@ Future showImportAssetWizard(ImportType type, BuildContext context, return importAsset(AssetFileType.image, content); case ImportType.svg: return importWithDialog(AssetFileType.svg); + case ImportType.svgText: + final controller = TextEditingController(); + final result = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(AppLocalizations.of(context).import), + scrollable: true, + content: TextField( + maxLines: null, + minLines: 3, + controller: controller, + autocorrect: false, + autofocus: true, + decoration: InputDecoration( + hintText: AppLocalizations.of(context).svgText, + border: OutlineInputBorder(), + suffixIcon: IconButton( + icon: const Icon(PhosphorIconsLight.clipboard), + onPressed: () async { + final clipboard = + await Clipboard.getData(Clipboard.kTextPlain); + final data = clipboard?.text; + if (data != null) controller.text = data; + }, + ), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: Text(MaterialLocalizations.of(context).cancelButtonLabel), + ), + ElevatedButton( + onPressed: () => Navigator.pop(context, true), + child: Text(AppLocalizations.of(context).import), + ), + ], + ), + ); + if (result != true) return; + return importAsset(AssetFileType.svg, utf8.encode(controller.text)); case ImportType.pdf: return importWithDialog(AssetFileType.pdf); case ImportType.document: diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index e6428d052459..fdfd0819fb25 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -635,5 +635,6 @@ "unencryptWarning": "This will unencrypt the document. The password will be removed and everyone with access will be able to open it.", "confirmPassword": "Confirm password", "passwordMismatch": "The passwords do not match", - "action": "Action" + "action": "Action", + "svgText": "SVG text" } diff --git a/app/lib/visualizer/tool.dart b/app/lib/visualizer/tool.dart index f638ac859453..0e227f1384ab 100644 --- a/app/lib/visualizer/tool.dart +++ b/app/lib/visualizer/tool.dart @@ -162,6 +162,7 @@ extension ImportTypeVisualizer on ImportType { ImportType.image => AppLocalizations.of(context).image, ImportType.pdf => AppLocalizations.of(context).pdf, ImportType.svg => AppLocalizations.of(context).svg, + ImportType.svgText => AppLocalizations.of(context).svgText, ImportType.camera => AppLocalizations.of(context).camera, ImportType.markdown => AppLocalizations.of(context).markdown, ImportType.xopp => 'Xournal++', @@ -172,6 +173,7 @@ extension ImportTypeVisualizer on ImportType { ImportType.image => PhosphorIcons.image, ImportType.pdf => PhosphorIcons.filePdf, ImportType.svg => PhosphorIcons.fileSvg, + ImportType.svgText => PhosphorIcons.article, ImportType.camera => PhosphorIcons.camera, ImportType.markdown => PhosphorIcons.textbox, ImportType.xopp => PhosphorIcons.notebook, diff --git a/app/pubspec.lock b/app/pubspec.lock index efddd622a4a2..6e38957b5a41 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1590,10 +1590,10 @@ packages: dependency: transitive description: name: win32 - sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" + sha256: "154360849a56b7b67331c21f09a386562d88903f90a1099c5987afc1912e1f29" url: "https://pub.dev" source: hosted - version: "5.9.0" + version: "5.10.0" win32_registry: dependency: transitive description: diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index 56523e720296..312221fdb813 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -13,10 +13,10 @@ importers: version: 0.9.4(typescript@5.7.2) '@astrojs/react': specifier: ^4.1.2 - version: 4.1.2(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(jiti@2.4.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1) + version: 4.1.2(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(jiti@2.4.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0) '@astrojs/starlight': specifier: ^0.30.3 - version: 0.30.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1)) + version: 0.30.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0)) '@phosphor-icons/react': specifier: ^2.1.7 version: 2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -28,7 +28,7 @@ importers: version: 19.0.2(@types/react@19.0.2) astro: specifier: ^5.1.1 - version: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1) + version: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0) react: specifier: ^19.0.0 version: 19.0.0 @@ -2203,8 +2203,8 @@ packages: engines: {node: '>=10'} hasBin: true - tinyexec@0.3.1: - resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -2570,8 +2570,8 @@ packages: resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==} engines: {node: '>= 14'} - yaml@2.6.1: - resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} engines: {node: '>= 14'} hasBin: true @@ -2681,12 +2681,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@4.0.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1))': + '@astrojs/mdx@4.0.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0))': dependencies: '@astrojs/markdown-remark': 6.0.1 '@mdx-js/mdx': 3.1.0(acorn@8.14.0) acorn: 8.14.0 - astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1) + astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0) es-module-lexer: 1.6.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.4 @@ -2704,15 +2704,15 @@ snapshots: dependencies: prismjs: 1.29.0 - '@astrojs/react@4.1.2(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(jiti@2.4.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1)': + '@astrojs/react@4.1.2(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(jiti@2.4.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0)': dependencies: '@types/react': 19.0.2 '@types/react-dom': 19.0.2(@types/react@19.0.2) - '@vitejs/plugin-react': 4.3.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1)) + '@vitejs/plugin-react': 4.3.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0)) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) ultrahtml: 1.5.3 - vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1) + vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -2733,16 +2733,16 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.24.1 - '@astrojs/starlight@0.30.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1))': + '@astrojs/starlight@0.30.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0))': dependencies: - '@astrojs/mdx': 4.0.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1)) + '@astrojs/mdx': 4.0.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0)) '@astrojs/sitemap': 3.2.1 '@pagefind/default-ui': 1.3.0 '@types/hast': 3.0.4 '@types/js-yaml': 4.0.9 '@types/mdast': 4.0.4 - astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1) - astro-expressive-code: 0.38.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1)) + astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0) + astro-expressive-code: 0.38.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0)) bcp-47: 2.1.0 hast-util-from-html: 2.0.3 hast-util-select: 6.0.3 @@ -2777,7 +2777,7 @@ snapshots: '@astrojs/yaml2ts@0.2.2': dependencies: - yaml: 2.6.1 + yaml: 2.7.0 '@babel/code-frame@7.26.2': dependencies: @@ -3484,14 +3484,14 @@ snapshots: '@ungap/structured-clone@1.2.1': {} - '@vitejs/plugin-react@4.3.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1))': + '@vitejs/plugin-react@4.3.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1) + vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0) transitivePeerDependencies: - supports-color @@ -3591,12 +3591,12 @@ snapshots: astring@1.9.0: {} - astro-expressive-code@0.38.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1)): + astro-expressive-code@0.38.3(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0)): dependencies: - astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1) + astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0) rehype-expressive-code: 0.38.3 - astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.6.1): + astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass@1.83.0)(terser@5.37.0)(typescript@5.7.2)(yaml@2.7.0): dependencies: '@astrojs/compiler': 2.10.3 '@astrojs/internal-helpers': 0.4.2 @@ -3642,14 +3642,14 @@ snapshots: rehype: 13.0.2 semver: 7.6.3 shiki: 1.24.4 - tinyexec: 0.3.1 + tinyexec: 0.3.2 tsconfck: 3.1.4(typescript@5.7.2) ultrahtml: 1.5.3 unist-util-visit: 5.0.0 unstorage: 1.14.4 vfile: 6.0.3 - vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1) - vitefu: 1.0.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1)) + vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0) + vitefu: 1.0.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0)) which-pm: 3.0.0 xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 @@ -5352,7 +5352,7 @@ snapshots: source-map-support: 0.5.21 optional: true - tinyexec@0.3.1: {} + tinyexec@0.3.2: {} to-regex-range@5.0.1: dependencies: @@ -5493,7 +5493,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1): + vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0): dependencies: esbuild: 0.24.2 postcss: 8.4.49 @@ -5503,11 +5503,11 @@ snapshots: jiti: 2.4.2 sass: 1.83.0 terser: 5.37.0 - yaml: 2.6.1 + yaml: 2.7.0 - vitefu@1.0.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1)): + vitefu@1.0.4(vite@6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0)): optionalDependencies: - vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.6.1) + vite: 6.0.6(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(yaml@2.7.0) volar-service-css@0.0.62(@volar/language-service@2.4.11): dependencies: @@ -5665,7 +5665,7 @@ snapshots: yaml@2.2.2: {} - yaml@2.6.1: {} + yaml@2.7.0: {} yargs-parser@21.1.1: {} diff --git a/metadata/en-US/changelogs/127.txt b/metadata/en-US/changelogs/127.txt index e8c22b9ca168..3f5716b30dd9 100644 --- a/metadata/en-US/changelogs/127.txt +++ b/metadata/en-US/changelogs/127.txt @@ -7,6 +7,7 @@ * Add color property * Move grid into own tool * Add password protected notes ([#771](https://github.com/LinwoodDev/Butterfly/issues/771)) +* Add option to import svg as text ([#596](https://github.com/LinwoodDev/Butterfly/issues/596)) * Fix undo/redo tools not showing status correctly * Fix grid not working correctly * Fix capture thumbnail uses wrong position