├── .DS_Store
├── BLLaunch Screen.storyboard
├── BarcodeLabel.entitlements
├── BarcodeLabel.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── xcuserdata
│ │ ├── chinpinboo.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── WorkspaceSettings.xcsettings
│ │ └── technoriver.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcshareddata
│ └── xcschemes
│ │ ├── BarcodeLabel (iOS).xcscheme
│ │ └── BarcodeLabel (macOS).xcscheme
└── xcuserdata
│ ├── chinpinboo.xcuserdatad
│ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── technoriver.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── README.md
├── Shared
├── .DS_Store
├── Assets.xcassets
│ ├── .DS_Store
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon-BarcodeLabel.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-20.png
│ │ ├── Icon-20@3x.png
│ │ ├── Icon-29.png
│ │ ├── Icon-29@2x-1.png
│ │ ├── Icon-29@2x.png
│ │ ├── Icon-29@3x.png
│ │ ├── Icon-40.png
│ │ ├── Icon-40@2x-1.png
│ │ ├── Icon-40@2x.png
│ │ ├── Icon-40@3x-1.png
│ │ ├── Icon-40@3x.png
│ │ ├── Icon-41.png
│ │ ├── Icon-42.png
│ │ ├── Icon-512@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-76.png
│ │ ├── Icon-76@2x.png
│ │ └── Icon-83.5@2x.png
│ ├── Contents.json
│ └── LabelImage.imageset
│ │ ├── 15415.jpg
│ │ └── Contents.json
├── BarcodeLabel
│ ├── Barcodes
│ │ ├── Code39.swift
│ │ ├── Industrial2of5.swift
│ │ └── POSTNET.swift
│ ├── Fonts
│ │ ├── ConnectCode39_S3.otf
│ │ ├── ConnectCodeIND2of5_S3.otf
│ │ └── ConnectCodeIPostnet.otf
│ ├── Models
│ │ ├── AppSettings.swift
│ │ ├── LabelDocument.swift
│ │ ├── LabelTemplates.swift
│ │ ├── OptionSettings.swift
│ │ └── PageSettings.swift
│ ├── Shapes
│ │ ├── BarcodeX.swift
│ │ ├── EllipseX.swift
│ │ ├── ImageX.swift
│ │ ├── RectangleX.swift
│ │ ├── ShapeX.swift
│ │ ├── ShapesX.swift
│ │ └── TextX.swift
│ ├── Util
│ │ └── LabelAction.swift
│ ├── ViewModels
│ │ ├── BarcodePropertiesViewModel.swift
│ │ ├── BaseViewModel.swift
│ │ ├── FileViewModel.swift
│ │ ├── ImagePropertiesViewModel.swift
│ │ ├── ObjectBaseViewModel.swift
│ │ ├── PreviewViewModel.swift
│ │ ├── ShapePropertiesViewModel.swift
│ │ ├── TemplateViewModel.swift
│ │ └── TextPropertiesViewModel.swift
│ └── Views
│ │ ├── AlertWrapper.swift
│ │ ├── BarcodePropertiesViewX.swift
│ │ ├── DimensionsPropertiesViewX.swift
│ │ ├── FilesViewX.swift
│ │ ├── ImagePickerX.swift
│ │ ├── ImagePropertiesViewX.swift
│ │ ├── LabelDesignViewX.swift
│ │ ├── LabelMainViewX.swift
│ │ ├── LabelToolbarViewX.swift
│ │ ├── LabelViewX.swift
│ │ ├── MainPropertiesViewX.swift
│ │ ├── MainSheetViewX.swift
│ │ ├── OptionsPrintToolbarViewX.swift
│ │ ├── PageToolbarViewX.swift
│ │ ├── PreviewViewX.swift
│ │ ├── RulerHViewX.swift
│ │ ├── RulerVViewX.swift
│ │ ├── ShapePropertiesViewX.swift
│ │ ├── ShapeViewX.swift
│ │ ├── TemplateLabelViewX.swift
│ │ ├── TemplateViewX.swift
│ │ └── TextPropertiesViewX.swift
├── BarcodeLabelApp.swift
├── IMG_20200419_102525.jpg
└── test.jpg
├── Tests iOS
├── Info.plist
└── Tests_iOS.swift
├── Tests macOS
├── Info.plist
└── Tests_macOS.swift
├── iOS
└── Info.plist
└── macOS
├── Info.plist
└── macOS.entitlements
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/.DS_Store
--------------------------------------------------------------------------------
/BLLaunch Screen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/BarcodeLabel.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.assets.pictures.read-write
8 |
9 | com.apple.security.device.camera
10 |
11 | com.apple.security.files.user-selected.read-write
12 |
13 | com.apple.security.network.client
14 |
15 | com.apple.security.personal-information.photos-library
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/project.xcworkspace/xcuserdata/chinpinboo.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/BarcodeLabel.xcodeproj/project.xcworkspace/xcuserdata/chinpinboo.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/project.xcworkspace/xcuserdata/chinpinboo.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | IssueFilterStyle
12 | ShowActiveSchemeOnly
13 | LiveSourceIssuesEnabled
14 |
15 | ShowSharedSchemesAutomaticallyEnabled
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/project.xcworkspace/xcuserdata/technoriver.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/BarcodeLabel.xcodeproj/project.xcworkspace/xcuserdata/technoriver.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/xcshareddata/xcschemes/BarcodeLabel (iOS).xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
54 |
56 |
62 |
63 |
64 |
65 |
71 |
73 |
79 |
80 |
81 |
82 |
84 |
85 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/xcshareddata/xcschemes/BarcodeLabel (macOS).xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/xcuserdata/chinpinboo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/xcuserdata/chinpinboo.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | BarcodeLabel (iOS).xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | BarcodeLabel (macOS).xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 1
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | 01626BCC25C163D7001D69F4
21 |
22 | primary
23 |
24 |
25 | 01626BDC25C163D7001D69F4
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/BarcodeLabel.xcodeproj/xcuserdata/technoriver.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SketchEffects (iOS).xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | SketchEffects (macOS).xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 1
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwiftUI-WYSIWYG-Draw
2 |
3 | This source code explores how to use SwiftUI for developing a What-You-See-Is-What-You-Get (WYSIWYG) vector drawing app. A WYSIWYG vector drawing app can be thought of as one that renders different objects such as a rectangle, an ellipse, a text, or other shapes on a canvas;
4 | the moving of objects around a canvas by dragging; and changing object properties by tapping on objects.
5 | This is illustrated in the screenshot of an iOS app below.
6 | Specifically, this article explores the use of a SwiftUI View as the "Drawing Canvas" instead of using a Core Graphics Canvas or a SwiftUI Canvas.
7 |
8 |
9 |
10 | ## Some points on the design
11 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
12 |
13 | ## The proof of concept app
14 | Barcode & Label
15 |
16 | ## Why use SwiftUI View as the drawing canvas?
17 |
18 | When developing a vector drawing app in the Apple ecosystem, things that come immediately onto the mind are Core Graphics or SwiftUI Canvas. Both are extremely fast, easy to use, and provide a canvas for us to draw on. Naturally, both are good choices as the canvas of a drawing app. However, when the drawing app requires WYSIWYG behavior, a Swift developer realizes that handling of object interactions such as drag, move, and resize, requires the use of Apple's Gestures and Events.
19 |
20 | This makes it hard for a Swift developer to ignore the use of a SwiftUI View as the "Drawing Canvas". This is because all Apple's Gestures and Events are directly supported by a SwiftUI View. If one is to take a step back and think about it, a SwiftUI View is designed by Apple for User Interface (UI) development, and such a View already naturally supports all the behavior required by a WYSIWYG app: rendering views and objects, and supporting gestures and events. The use of a SwiftUI View as the "Drawing Canvas" also does not prevent us from using Core Graphics, SwiftUI Canvas, or even Metal for rendering the underlying object that requires special treatment, as all three can be represented as a SwiftUI View easily.
21 |
22 | ## Compiling the Source
23 |
24 | Prerequisites
25 | 1. Xcode 13
26 | 2. iOS 15
27 |
28 | Build
29 | 1. Download the Source
30 | 2. Launch Xcode and load BarcodeLabel.xcodeproj
31 | 3. Build and run on iPhone Simulator or Device
32 |
33 |
34 | ## Sister Project
35 |
36 | [Node based Image/Video Compositing on Mobile](https://github.com/Misfits-Rebels-Outcasts/Nodef)
37 |
38 |
--------------------------------------------------------------------------------
/Shared/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/.DS_Store
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/.DS_Store
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Icon-40.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "Icon-20@3x.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "Icon-29@2x.png",
17 | "idiom" : "iphone",
18 | "scale" : "2x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "Icon-29@3x.png",
23 | "idiom" : "iphone",
24 | "scale" : "3x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "Icon-40@2x.png",
29 | "idiom" : "iphone",
30 | "scale" : "2x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "Icon-40@3x.png",
35 | "idiom" : "iphone",
36 | "scale" : "3x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "Icon-40@3x-1.png",
41 | "idiom" : "iphone",
42 | "scale" : "2x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "filename" : "Icon-60@3x.png",
47 | "idiom" : "iphone",
48 | "scale" : "3x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "Icon-20.png",
53 | "idiom" : "ipad",
54 | "scale" : "1x",
55 | "size" : "20x20"
56 | },
57 | {
58 | "filename" : "Icon-41.png",
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "Icon-29.png",
65 | "idiom" : "ipad",
66 | "scale" : "1x",
67 | "size" : "29x29"
68 | },
69 | {
70 | "filename" : "Icon-29@2x-1.png",
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "Icon-42.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "40x40"
80 | },
81 | {
82 | "filename" : "Icon-40@2x-1.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "Icon-76.png",
89 | "idiom" : "ipad",
90 | "scale" : "1x",
91 | "size" : "76x76"
92 | },
93 | {
94 | "filename" : "Icon-76@2x.png",
95 | "idiom" : "ipad",
96 | "scale" : "2x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "Icon-83.5@2x.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "83.5x83.5"
104 | },
105 | {
106 | "filename" : "Icon-512@2x.png",
107 | "idiom" : "ios-marketing",
108 | "scale" : "1x",
109 | "size" : "1024x1024"
110 | }
111 | ],
112 | "info" : {
113 | "author" : "xcode",
114 | "version" : 1
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-20.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-20@3x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29@2x-1.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29@2x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-29@3x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@2x-1.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@3x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@3x-1.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-41.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-41.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-42.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-512@2x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/AppIcon-BarcodeLabel.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/LabelImage.imageset/15415.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/Assets.xcassets/LabelImage.imageset/15415.jpg
--------------------------------------------------------------------------------
/Shared/Assets.xcassets/LabelImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "15415.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Barcodes/Code39.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | /*
12 | https://www.barcoderesource.com/barcodelabelappleapp.shtml
13 |
14 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
15 | */
16 |
17 | import Foundation
18 |
19 | extension String {
20 | subscript (index: Int) -> Character {
21 | let charIndex = self.index(self.startIndex, offsetBy: index)
22 | return self[charIndex]
23 | }
24 |
25 | subscript (range: Range) -> Substring {
26 | let startIndex = self.index(self.startIndex, offsetBy: range.startIndex)
27 | let stopIndex = self.index(self.startIndex, offsetBy: range.startIndex + range.count)
28 | return self[startIndex.. Int {
52 |
53 | guard let cVal = CODE39MAP.firstIndex(of: "\(inputChar)") else {
54 | return -1
55 | }
56 |
57 | return cVal;
58 | }
59 |
60 | func filterInput (_ inputData:String) -> String {
61 | var retStr=""
62 | inputData.forEach { char in
63 | if (CODE39MAP.contains("\(char)"))
64 | {
65 | retStr = retStr + "\(char)"
66 | }
67 | }
68 | return retStr
69 | }
70 |
71 | public mutating func encode () -> String {
72 |
73 | var cd=""
74 | var result=""
75 | var filtereddata = filterInput(inputData)
76 | let filteredlength=filtereddata.count
77 |
78 | if (checkDigit==1)
79 | {
80 | if (filteredlength > 254)
81 | {
82 | filtereddata=String(filtereddata.prefix(254))
83 | }
84 | cd=generateCheckDigit(filtereddata);
85 | }
86 | else
87 | {
88 | if (filteredlength > 255)
89 | {
90 | filtereddata=String(filtereddata.prefix(255))
91 | }
92 | }
93 | result="*"+filtereddata+cd+"*"
94 | humanReadableText=result
95 | return result
96 |
97 |
98 | }
99 |
100 | public func getHumanReadableText()->String{
101 | return humanReadableText
102 | }
103 |
104 | func getCode39Character(_ inputdecimal:Int) -> String
105 | {
106 | let str=CODE39MAP[inputdecimal]
107 | return str
108 | }
109 |
110 | func generateCheckDigit(_ bdata:String)->String
111 | {
112 | var datalength=0
113 | var sum = 0
114 | var result = -1
115 | var strResult=""
116 |
117 | datalength=bdata.count
118 | //guard the for loop
119 | if datalength>0
120 | {
121 | for x in 0...datalength-1
122 | {
123 | let barcodechar = bdata[bdata.index(bdata.startIndex, offsetBy: x)]
124 | sum = sum + getCode39Value(barcodechar);
125 | }
126 | }
127 | result=sum % 43
128 | strResult=getCode39Character(result)
129 |
130 | return strResult
131 |
132 | }
133 |
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Barcodes/Industrial2of5.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | /*
12 | https://www.barcoderesource.com/barcodelabelappleapp.shtml
13 |
14 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
15 | */
16 |
17 |
18 | import Foundation
19 |
20 | public struct Industrial2of5 {
21 |
22 | public var inputData=""
23 | public var checkDigit=1
24 | public var humanReadableText=""
25 |
26 | init() {
27 | self.inputData="12345678"
28 | self.checkDigit=1
29 | }
30 |
31 | public init(_ inputData:String,_ checkDigit:Int) {
32 | self.inputData=inputData
33 | self.checkDigit=checkDigit
34 | }
35 |
36 | func filterInput (_ inputData:String) -> String {
37 | var retStr=""
38 |
39 | inputData.forEach { char in
40 | if let uchar = char.asciiValue {
41 | let barcodevalue=Int(uchar)
42 |
43 | if barcodevalue <= 57 && barcodevalue >= 48
44 | {
45 | retStr = retStr + "\(char)"
46 | }
47 | }
48 | }
49 |
50 | return retStr
51 | }
52 |
53 | public mutating func encode () -> String {
54 |
55 | var cd=""
56 | var result=""
57 | var filtereddata = filterInput(inputData)
58 | let filteredlength=filtereddata.count
59 |
60 | if (checkDigit == 1)
61 | {
62 | if (filteredlength > 254)
63 | {
64 | filtereddata=String(filtereddata.prefix(254))
65 | }
66 | cd=generateCheckDigit(filtereddata);
67 | }
68 | else{
69 |
70 | if (filteredlength > 255)
71 | {
72 | filtereddata=String(filtereddata.prefix(255))
73 | }
74 |
75 |
76 | }
77 | filtereddata = filtereddata + cd
78 | humanReadableText=filtereddata
79 |
80 | result="{"+filtereddata+"}"
81 |
82 |
83 | return result
84 | }
85 |
86 | public func getHumanReadableText()->String{
87 | return humanReadableText
88 | }
89 |
90 | func generateCheckDigit(_ bdata:String)->String
91 | {
92 | var datalength=0
93 | var lastcharpos = 0
94 | var result=0
95 | var strResult=""
96 | var barcodechar=0
97 | var barcodevalue=0
98 | var toggle=1
99 | var sum=0
100 |
101 | datalength=bdata.count
102 | lastcharpos=datalength-1
103 |
104 | var x=lastcharpos
105 | while (x>=0)
106 | {
107 | barcodechar=(Int)(bdata[x].asciiValue!)
108 | barcodevalue=barcodechar-48
109 | if toggle == 1
110 | {
111 | sum += (barcodevalue*3);
112 | toggle = 0;
113 | }
114 | else
115 | {
116 | sum += barcodevalue;
117 | toggle = 1;
118 | }
119 |
120 | x=x-1
121 | }
122 |
123 | if sum % 10 == 0
124 | {
125 | result=0+48
126 | }
127 | else{
128 | result = (10 - (sum % 10)) + 48
129 | }
130 |
131 | strResult=strResult+String(UnicodeScalar(result)!)
132 | return strResult
133 |
134 | }
135 |
136 |
137 | }
138 |
139 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Barcodes/POSTNET.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | /*
12 | https://www.barcoderesource.com/barcodelabelappleapp.shtml
13 |
14 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
15 | */
16 |
17 | import Foundation
18 |
19 | public struct POSTNET {
20 |
21 |
22 | public var inputData=""
23 | public var humanReadableText=""
24 |
25 | init() {
26 | self.inputData="12345678"
27 | }
28 |
29 | public init(_ inputData:String) {
30 | self.inputData=inputData
31 | }
32 |
33 | func getPOSTNETValue(_ inputChar:Character) -> Int {
34 | return (Int)(inputChar.asciiValue!) - 48
35 | }
36 |
37 | func filterInput (_ inputData:String) -> String {
38 | var retStr=""
39 |
40 | inputData.forEach { char in
41 | if let uchar = char.asciiValue {
42 | let barcodevalue=Int(uchar)
43 |
44 | if barcodevalue <= 57 && barcodevalue >= 48
45 | {
46 | retStr = retStr + "\(char)"
47 | }
48 | }
49 | }
50 |
51 | return retStr
52 |
53 | }
54 |
55 | public mutating func encode () -> String {
56 |
57 | var cd=""
58 | var result=""
59 | var filtereddata = filterInput(inputData)
60 | let filteredlength=filtereddata.count
61 |
62 | if (filteredlength > 11)
63 | {
64 | filtereddata=String(filtereddata.prefix(11))
65 | }
66 |
67 | cd=generateCheckDigit(filtereddata);
68 |
69 | humanReadableText=filtereddata+cd
70 | result="{"+filtereddata+cd+"}"
71 | return result
72 |
73 |
74 | }
75 |
76 | public func getHumanReadableText()->String{
77 | return humanReadableText
78 | }
79 |
80 | func getPOSTNETCharacter(_ inputdecimal:Int) -> String
81 | {
82 | return String(UnicodeScalar(inputdecimal+48)!)
83 | }
84 |
85 | func generateCheckDigit(_ bdata:String)->String
86 | {
87 | var datalength=0
88 | var sum = 0
89 | var result = -1
90 | var strResult=""
91 |
92 | datalength=bdata.count
93 | if datalength>0
94 | {
95 | for x in 0...datalength-1
96 | {
97 | let barcodechar = bdata[x]
98 | sum = sum + getPOSTNETValue(barcodechar)
99 | }
100 | }
101 |
102 | result=sum % 10
103 | if result != 0
104 | {
105 | result = 10 - result
106 | }
107 |
108 | strResult=getPOSTNETCharacter(result)
109 |
110 | return strResult
111 |
112 | }
113 |
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Fonts/ConnectCode39_S3.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/BarcodeLabel/Fonts/ConnectCode39_S3.otf
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Fonts/ConnectCodeIND2of5_S3.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/BarcodeLabel/Fonts/ConnectCodeIND2of5_S3.otf
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Fonts/ConnectCodeIPostnet.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/BarcodeLabel/Fonts/ConnectCodeIPostnet.otf
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Models/AppSettings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppSettings.swift
3 | //
4 | //
5 | // Created by on 15/3/22.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | class AppSettings: ObservableObject, Identifiable, Equatable {
12 |
13 | static func == (lhs: AppSettings, rhs: AppSettings) -> Bool {
14 | return lhs.id==rhs.id
15 | }
16 |
17 | var id = UUID()
18 |
19 | @Published var dpi: Double = 300.0
20 | @Published var dpiScale: Double = 300.0/72.0
21 | @Published var zoomFactor: Double = 1.0
22 | @Published var units: String = "Inches"
23 | @Published var zoomingOrScrollX: String = "scroll" //zoomIn, zoomOut, scroll
24 | @Published var zoomingOrScrollY: String = "scroll" //zoomIn, zoomOut, scroll
25 |
26 |
27 |
28 |
29 | init(_ dpi: Double, _ zoomFactor: Double) {
30 | self.dpi=dpi
31 | self.dpiScale=dpi/72.0
32 | self.zoomFactor=zoomFactor
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Models/LabelDocument.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageDocument.swift
3 | // ImportExport
4 | //
5 | // Created by Aaron Wright on 8/27/20.
6 | //
7 |
8 | import SwiftUI
9 | import UniformTypeIdentifiers
10 |
11 | struct LabelDocument: FileDocument {
12 |
13 | static var readableContentTypes: [UTType] { [.json] }
14 |
15 | var message: String
16 |
17 | init(message: String) {
18 | self.message = message
19 | }
20 |
21 | init(configuration: ReadConfiguration) throws {
22 | guard let data = configuration.file.regularFileContents,
23 | let string = String(data: data, encoding: .utf8)
24 | else {
25 | throw CocoaError(.fileReadCorruptFile)
26 | }
27 | message = string
28 | }
29 |
30 | func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
31 | return FileWrapper(regularFileWithContents: message.data(using: .utf8)!)
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Models/LabelTemplates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelTemplatesModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 |
8 |
9 | var labelTemplatesAll = [
10 |
11 | ["Standard SA4001","Labels","Standard","Address Label (A4) - 8x3","iso-a4","8.268","11.693","2.520","1.333","0.104","0.000","8","3","0.250","0.541"],
12 | ["Standard SA4002","Labels","Standard","Address Label (A4) - 7x3","iso-a4","8.268","11.693","2.500","1.500","0.100","0.000","7","3","0.283","0.625"],
13 | ["Standard SA4003","Labels","Standard","Address Label (A4) - 6x3","iso-a4","8.268","11.693","2.500","1.833","0.100","0.000","6","3","0.283","0.375"],
14 | ["Standard SA4004","Labels","Standard","Address Label (A4) - 8x2","iso-a4","8.268","11.693","3.900","1.333","0.100","0.000","8","2","0.184","0.541"],
15 | ["Standard SA4005","Labels","Standard","Address Label (A4) - 7x2","iso-a4","8.268","11.693","3.900","1.500","0.100","0.000","7","2","0.184","0.625"],
16 | ["Standard SA4006","Labels","Standard","Address Label (A4) - 4x2","iso-a4","8.268","11.693","3.900","2.667","0.100","0.000","4","2","0.184","0.542"],
17 |
18 | ["Standard SLE001","Labels","Standard","Address Label (Letter) - 10x2","iso-letter","8.500","11.000","4.000","1.000","0.189","0.000","10","2","0.156","0.500"],
19 | ["Standard SLE002","Labels","Standard","Address/Shipping (Letter) - 3x2","iso-letter","8.500","11.000","4.000","3.333","0.188","0.000","3","2","0.156","0.500"],
20 | ["Standard SLE003","Labels","Standard","Address/Shipping (Letter) - 5x2","iso-letter","8.500","11.000","4.000","2.000","0.188","0.000","5","2","0.156","0.500"],
21 | ["Standard SLE004","Labels","Standard","Address Label (Letter) - 7x2","iso-letter","8.500","11.000","4.000","1.333","0.188","0.000","7","2","0.156","0.833"],
22 | ["Standard SLE005","Labels","Standard","Address Label (Letter) - 10x3","iso-letter","8.500","11.000","2.625","1.000","0.125","0.000","10","3","0.188","0.500"],
23 |
24 | ]
25 | var labelTemplates = labelTemplatesAll.filter {
26 | $0[1].contains("Labels") && $0[2].contains("Standard")
27 | }
28 |
29 | var labelTemplatesCount = 11
30 |
31 | var categories = ["Labels"]
32 | //var categories = ["Labels","Envelopes","Cards & Tags","Papers"]
33 |
34 | var vendorsCards = ["Standard"]
35 |
36 | var vendorsLabels = ["Standard"]
37 |
38 | var vendors = vendorsLabels
39 |
40 | var fontNames = ["Helvetica","Helvetica Bold","American Typewriter Bold","Arial","Arial Bold","Arial Italic"]
41 |
42 | var barcodeFontNames = ["CCode39_S3","CCodeIPostnet","CCodeIND2of5_S3", "Arial"]
43 |
44 | var barcodeNames = ["Code 39","Industrial 2 of 5","POSTNET"]
45 |
46 | var measurementUnits = ["Inches","Centimeters"]
47 |
48 | var orientation = ["Portrait","Landscape"]
49 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Models/OptionSettings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by on 17/3/22.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | class OptionSettings: ObservableObject, Identifiable, Equatable {
12 |
13 | static func == (lhs: OptionSettings, rhs: OptionSettings) -> Bool {
14 | return lhs.id==rhs.id
15 | }
16 |
17 | var id = UUID()
18 |
19 | @Published var action: String = ""
20 | @Published var showPropertiesView: Int = 0
21 | @Published var showPropertiesSheet: Bool = false
22 | @Published var previewBorderWidth: Double = 4.0
23 | @Published var showAlert = false //display aleart for entering label name the textfield alert
24 | @Published var labelName: String = ""
25 | @Published var jsonLabelStringForSave: String = ""
26 | @Published var labelDocument: LabelDocument = LabelDocument(message: "")
27 | @Published var isExporting: Bool = false
28 | @Published var isImporting: Bool = false
29 | @Published var showingAlertMessage = false
30 | @Published var existingLabelExist = false
31 | @Published var enteredSaveFileName: String? // this is updated as the user types in the text field
32 | @Published var alertMessage: String? //"Label saved successfully." in AlertWrapper
33 |
34 | init(_ action: String) {
35 | self.action=action
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Models/PageSettings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageSettings.swift
3 | //
4 | //
5 | // Created by on 16/3/22.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct ILabel: Identifiable {
12 | var id = UUID()
13 | var label: Int
14 | var x:CGFloat
15 | var y:CGFloat
16 | }
17 |
18 | class PageSettings: Codable, ObservableObject, Identifiable, Equatable {
19 |
20 | static func == (lhs: PageSettings, rhs: PageSettings) -> Bool {
21 | return lhs.id==rhs.id
22 | }
23 |
24 | var id = UUID()
25 |
26 | //name,category,vendor,description,orientation
27 | @Published var name: String = "Standard SLE005"
28 | @Published var category: String = "Labels"
29 | @Published var vendor: String = "Standard"
30 | @Published var description: String = "Address Label (Letter) - 10x3"
31 | @Published var type: String = "iso-letter"
32 |
33 | @Published var pageWidth: Double = 8.5
34 | @Published var pageHeight: Double = 11.0
35 | @Published var leftMargin: Double = 0.188
36 | @Published var topMargin: Double = 0.5
37 | @Published var labelWidth: Double = 2.625
38 | @Published var labelHeight: Double = 1.0
39 | @Published var hSpace: Double = 0.125
40 | @Published var vSpace: Double = 0.0
41 | @Published var numRows: Int = 10
42 | @Published var numCols: Int = 3
43 | @Published var dpi: Double = 300.0//72.0
44 | @Published var labelList = [ILabel]()
45 |
46 | init() {
47 | generateLabels()
48 | }
49 | init(name: String,
50 | category: String,
51 | vendor: String,
52 | description: String,
53 | type: String,
54 | pageWidth: Double,
55 | pageHeight: Double,
56 | leftMargin: Double,
57 | topMargin: Double,
58 | labelWidth: Double,
59 | labelHeight: Double,
60 | hSpace: Double,
61 | vSpace: Double,
62 | numRows: Int,
63 | numCols: Int,
64 | dpi: Double) {
65 |
66 | self.name=name
67 | self.category=category
68 | self.vendor=vendor
69 | self.description=description
70 | self.type=type
71 | self.pageWidth=pageWidth
72 | self.pageHeight=pageHeight
73 | self.leftMargin=leftMargin
74 | self.topMargin=topMargin
75 | self.labelWidth=labelWidth
76 | self.labelHeight=labelHeight
77 | self.hSpace=hSpace
78 | self.vSpace=vSpace
79 | self.numRows=numRows
80 | self.numCols=numCols
81 | self.dpi=dpi
82 |
83 | generateLabels()
84 | }
85 |
86 | func generateLabels()
87 | {
88 | generateLabels(dpi:dpi)
89 | }
90 |
91 | func generateLabels(dpi :Double)
92 | {
93 | labelList = [ILabel]()
94 | var x = leftMargin * dpi
95 | var y = topMargin * dpi
96 | let adjustX = labelWidth / 2.0 * dpi
97 | let adjustY = labelHeight / 2.0 * dpi
98 | var count = 1
99 | //print ("Label:",numRows,":",numCols,":",pageWidth,":",pageHeight,":",labelWidth,":",labelHeight)
100 |
101 | for _ in 1...numRows {
102 | for _ in 1...numCols {
103 | labelList.append(ILabel(label: count, x: x + adjustX, y: y + adjustY))
104 | count=count+1
105 | x = x + hSpace * dpi
106 | x = x + labelWidth * dpi
107 | }
108 | x = leftMargin * dpi
109 | y = y + vSpace * dpi
110 | y = y + labelHeight * dpi
111 | }
112 | }
113 |
114 | enum CodingKeys: String, CodingKey {
115 | case name
116 | case category
117 | case vendor
118 | case description
119 | case type
120 | case pageWidth
121 | case pageHeight
122 | case leftMargin
123 | case topMargin
124 | case labelWidth
125 | case labelHeight
126 | case hSpace
127 | case vSpace
128 | case numRows
129 | case numCols
130 | case dpi
131 | }
132 |
133 | required init(from decoder: Decoder) throws {
134 | let values = try decoder.container(keyedBy: CodingKeys.self)
135 | name = try values.decodeIfPresent(String.self, forKey: .name) ?? "Standard"
136 | category = try values.decodeIfPresent(String.self, forKey: .category) ?? "Labels"
137 | vendor = try values.decodeIfPresent(String.self, forKey: .vendor) ?? "Standard"
138 | description = try values.decodeIfPresent(String.self, forKey: .description) ?? "Address Label (Letter) - 10x3"
139 | type = try values.decodeIfPresent(String.self, forKey: .type) ?? "iso-letter"
140 | pageWidth = try values.decodeIfPresent(Double.self, forKey: .pageWidth) ?? 8.5
141 | pageHeight = try values.decodeIfPresent(Double.self, forKey: .pageHeight) ?? 11.0
142 | leftMargin = try values.decodeIfPresent(Double.self, forKey: .leftMargin) ?? 0.188
143 | topMargin = try values.decodeIfPresent(Double.self, forKey: .topMargin) ?? 0.5
144 | labelWidth = try values.decodeIfPresent(Double.self, forKey: .labelWidth) ?? 2.625
145 | labelHeight = try values.decodeIfPresent(Double.self, forKey: .labelHeight) ?? 1.0
146 | hSpace = try values.decodeIfPresent(Double.self, forKey: .hSpace) ?? 0.125
147 | vSpace = try values.decodeIfPresent(Double.self, forKey: .vSpace) ?? 0.0
148 | numRows = try values.decodeIfPresent(Int.self, forKey: .numRows) ?? 10
149 | numCols = try values.decodeIfPresent(Int.self, forKey: .numCols) ?? 3
150 | dpi = try values.decodeIfPresent(Double.self, forKey: .dpi) ?? 300.0
151 | }
152 |
153 | func encode(to encoder: Encoder) throws {
154 | var container = encoder.container(keyedBy: CodingKeys.self)
155 | try container.encode(name, forKey: .name)
156 | try container.encode(category, forKey: .category)
157 | try container.encode(vendor, forKey: .vendor)
158 | try container.encode(description, forKey: .description)
159 | try container.encode(type, forKey: .type)
160 | try container.encode(pageWidth, forKey: .pageWidth)
161 | try container.encode(pageHeight, forKey: .pageHeight)
162 | try container.encode(leftMargin, forKey: .leftMargin)
163 | try container.encode(topMargin, forKey: .topMargin)
164 | try container.encode(labelWidth, forKey: .labelWidth)
165 | try container.encode(labelHeight, forKey: .labelHeight)
166 | try container.encode(hSpace, forKey: .hSpace)
167 | try container.encode(vSpace, forKey: .vSpace)
168 | try container.encode(numRows, forKey: .numRows)
169 | try container.encode(numCols, forKey: .numCols)
170 | try container.encode(dpi, forKey: .dpi)
171 | }
172 | }
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/BarcodeX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 |
13 | class BarcodeX: ShapeX {
14 |
15 | @Published var fontSize:CGFloat = 99.0 //18.0*300.0/72.0
16 | @Published var input:String = "1234"
17 | @Published var symbology:String = "Code 39"
18 | @Published var checkDigit:Bool = false
19 | @Published var barcode:String = "*1234*"
20 | @Published var humanReadableText:String = "*1234*"
21 | @Published var fontName:String = "CCode39_S3"
22 | @Published var textColor = Color.black
23 | @Published var horizontalTextAlignment:String = "Center"
24 |
25 | @Published var hrFontName:String = "Arial"
26 | @Published var hrTextColor = Color.black
27 | @Published var hrFontSize:CGFloat = 16.0*300.0/72.0
28 |
29 | init(_ dpi:Double, _ location: CGPoint, _ size: CGSize, _ canvasSize: CGSize, _ isSelected: Bool) {
30 |
31 | super.init(dpi,"Barcode",location,size,canvasSize,isSelected)
32 | fontSize = 23.76 * dpi / 72.0 //99.0 gives the same size as other platforms
33 | hrFontSize = 16.0*dpi/72.0
34 | }
35 |
36 | enum CodingKeys : String, CodingKey {
37 | case input
38 | case symbology
39 | case checkDigit
40 | case barcode
41 | case humanReadableText
42 |
43 | case fontSize
44 | case fontName
45 | case textColor
46 |
47 | case hrFontSize
48 | case hrFontName
49 | case hrTextColor
50 |
51 | case horizontalTextAlignment
52 | }
53 |
54 | required init(from decoder: Decoder) throws {
55 | try super.init(from: decoder)
56 | let values = try decoder.container(keyedBy: CodingKeys.self)
57 | input = try values.decodeIfPresent(String.self, forKey: .input) ?? "1234"
58 | symbology = try values.decodeIfPresent(String.self, forKey: .symbology) ?? "Code 39"
59 | checkDigit = try values.decodeIfPresent(Bool.self, forKey: .checkDigit) ?? false
60 |
61 | barcode = try values.decodeIfPresent(String.self, forKey: .barcode) ?? "1234"
62 | humanReadableText = try values.decodeIfPresent(String.self, forKey: .humanReadableText) ?? "1234"
63 |
64 | fontSize = try values.decodeIfPresent(CGFloat.self, forKey: .fontSize) ?? 18.0*dpi/72.0
65 | fontName = try values.decodeIfPresent(String.self, forKey: .fontName) ?? "CCode39_S3"
66 | let textColorData = try values.decodeIfPresent(Data.self, forKey: .textColor) ?? nil
67 | if textColorData != nil
68 | {
69 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: textColorData!)
70 | textColor = Color(color!)
71 | }
72 |
73 | hrFontSize = try values.decodeIfPresent(CGFloat.self, forKey: .hrFontSize) ?? 16.0*300.0/72.0
74 | hrFontName = try values.decodeIfPresent(String.self, forKey: .hrFontName) ?? "Arial"
75 | let hrTextColorData = try values.decodeIfPresent(Data.self, forKey: .hrTextColor) ?? nil
76 | if hrTextColorData != nil
77 | {
78 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: hrTextColorData!)
79 | hrTextColor = Color(color!)
80 | }
81 |
82 | horizontalTextAlignment = try values.decodeIfPresent(String.self, forKey: .horizontalTextAlignment) ?? "Center"
83 |
84 | }
85 |
86 | override func encode(to encoder: Encoder) throws {
87 | try super.encode(to: encoder)
88 | var container = encoder.container(keyedBy: CodingKeys.self)
89 |
90 | try container.encode(input, forKey: .input)
91 | try container.encode(symbology, forKey: .symbology)
92 | try container.encode(checkDigit, forKey: .checkDigit)
93 |
94 | try container.encode(barcode, forKey: .barcode)
95 | try container.encode(humanReadableText, forKey: .humanReadableText)
96 |
97 | try container.encode(fontName, forKey: .fontName)
98 | try container.encode(fontSize, forKey: .fontSize)
99 | let convertedTextColor = UIColor(textColor)
100 | let textColorData = try NSKeyedArchiver.archivedData(withRootObject: convertedTextColor, requiringSecureCoding: false)
101 | try container.encode(textColorData, forKey: .textColor)
102 |
103 | try container.encode(hrFontName, forKey: .hrFontName)
104 | try container.encode(hrFontSize, forKey: .hrFontSize)
105 | let hrconvertedTextColor = UIColor(hrTextColor)
106 | let hrTextColorData = try NSKeyedArchiver.archivedData(withRootObject: hrconvertedTextColor, requiringSecureCoding: false)
107 | try container.encode(hrTextColorData, forKey: .hrTextColor)
108 |
109 | try container.encode(horizontalTextAlignment, forKey: .horizontalTextAlignment)
110 |
111 | }
112 |
113 | override func view() -> AnyView {
114 | AnyView(
115 | VStack
116 | {
117 | HStack{
118 | if horizontalTextAlignment == "Right" { Spacer() }
119 | Text(self.barcode)
120 | .lineLimit(1)
121 | .font(.custom(self.fontName, size: self.fontSize))
122 | .foregroundColor(self.textColor)
123 | .fixedSize(horizontal: true, vertical: false)
124 | if horizontalTextAlignment == "Left" { Spacer() }
125 | }
126 |
127 | HStack{
128 | if horizontalTextAlignment == "Right" { Spacer() }
129 | Text(self.humanReadableText)
130 | .lineLimit(1)
131 | .font(.custom(self.hrFontName, size: self.hrFontSize))
132 | //.font(.custom("CCodeIND2of5_S3", size: self.hrFontSize))
133 | .foregroundColor(self.hrTextColor)
134 | .fixedSize(horizontal: true, vertical: false)
135 | if horizontalTextAlignment == "Left" { Spacer() }
136 | }
137 | }
138 | .frame(width: self.size.width, height: self.size.height)
139 | .clipShape(Rectangle())
140 | .position(self.location)
141 | )
142 | }
143 |
144 | override func useElipsisIfSizeTooSmall() {
145 |
146 | }
147 |
148 | }
149 |
150 |
151 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/EllipseX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 | class EllipseX: ShapeX {
13 |
14 | @Published var strokeWidth:Double = 0.25 * 300.0/72.0
15 | @Published var strokeColor = Color.black
16 | @Published var fillColor = Color.white
17 |
18 | init(_ dpi:Double, _ location: CGPoint, _ size: CGSize, _ canvasSize: CGSize, _ isSelected: Bool) {
19 | super.init(dpi,"Ellipse",location,size,canvasSize,isSelected)
20 | strokeWidth = 0.25 * dpi/72.0
21 | }
22 |
23 | enum CodingKeys : String, CodingKey {
24 | case strokeWidth
25 | case strokeColor
26 | case fillColor
27 | }
28 |
29 | required init(from decoder: Decoder) throws {
30 | try super.init(from: decoder)
31 | let values = try decoder.container(keyedBy: CodingKeys.self)
32 | strokeWidth = try values.decodeIfPresent(Double.self, forKey: .strokeWidth) ?? 0.25 * dpi/72.0
33 |
34 | let strokeColorData = try values.decodeIfPresent(Data.self, forKey: .strokeColor) ?? nil
35 | if strokeColorData != nil
36 | {
37 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: strokeColorData!)
38 | strokeColor = Color(color!)
39 | }
40 |
41 | let fillColorData = try values.decodeIfPresent(Data.self, forKey: .fillColor) ?? nil
42 | if fillColorData != nil
43 | {
44 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: fillColorData!)
45 | fillColor = Color(color!)
46 | }
47 | }
48 |
49 | override func encode(to encoder: Encoder) throws {
50 | try super.encode(to: encoder)
51 | var container = encoder.container(keyedBy: CodingKeys.self)
52 | try container.encode(strokeWidth, forKey: .strokeWidth)
53 |
54 | let convertedStrokeColor = UIColor(strokeColor)
55 | let strokeColorData = try NSKeyedArchiver.archivedData(withRootObject: convertedStrokeColor, requiringSecureCoding: false)
56 | try container.encode(strokeColorData, forKey: .strokeColor)
57 |
58 | let convertedFillColor = UIColor(fillColor)
59 | let fillColorData = try NSKeyedArchiver.archivedData(withRootObject: convertedFillColor, requiringSecureCoding: false)
60 | try container.encode(fillColorData, forKey: .fillColor)
61 | }
62 |
63 |
64 | override func view() -> AnyView {
65 | AnyView(
66 | Ellipse()
67 | .stroke(strokeColor, lineWidth: strokeWidth)
68 | .background(Ellipse().fill(fillColor))
69 | .frame(width: self.size.width, height: self.size.height)
70 | .position(self.location))
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/ImageX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 |
13 | //image orientation
14 | //https://stackoverflow.com/questions/42098390/swift-png-image-being-saved-with-incorrect-orientation
15 | class ImageX: ShapeX {
16 | @Published var image: UIImage = UIImage(named: "LabelImage")!
17 |
18 | init(_ dpi:Double, _ location: CGPoint, _ size: CGSize, _ canvasSize: CGSize, _ isSelected: Bool) {
19 | super.init(dpi,"Image",location,size,canvasSize,isSelected)
20 | print(location)
21 | print(size)
22 | print(canvasSize)
23 | print(isSelected)
24 | }
25 |
26 | enum CodingKeys : String, CodingKey {
27 | case image
28 | }
29 |
30 | required init(from decoder: Decoder) throws {
31 | try super.init(from: decoder)
32 | let container = try decoder.container(keyedBy: CodingKeys.self)
33 |
34 | let data = try container.decodeIfPresent(String.self, forKey: .image) ?? nil
35 | if data != nil
36 | {
37 | //https://stackoverflow.com/questions/11251340/convert-between-uiimage-and-base64-string
38 | self.image = convertBase64StringToImage(imageBase64String:data!)
39 | }
40 | }
41 |
42 | func convertImageToBase64String (img: UIImage) -> String {
43 | return img.jpegData(compressionQuality: 1)?.base64EncodedString() ?? ""
44 | }
45 |
46 | func convertBase64StringToImage (imageBase64String:String) -> UIImage {
47 | let imageData = Data(base64Encoded: imageBase64String)
48 | let image = UIImage(data: imageData!)
49 | return image!
50 | }
51 |
52 | override func encode(to encoder: Encoder) throws {
53 | try super.encode(to: encoder)
54 | var container = encoder.container(keyedBy: CodingKeys.self)
55 | try container.encode(convertImageToBase64String(img:image), forKey: .image)
56 |
57 | }
58 |
59 | override func view() -> AnyView {
60 | AnyView(
61 | Image(uiImage: image)
62 | .resizable()
63 | .frame(width: self.size.width, height: self.size.height)
64 | .position(self.location))
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/RectangleX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 |
13 | class RectangleX: ShapeX {
14 |
15 | @Published var strokeWidth:Double = 0.25 * 300.0/72.0
16 | @Published var strokeColor = Color.black
17 | @Published var fillColor = Color.white
18 |
19 | init(_ dpi:Double, _ location: CGPoint, _ size: CGSize, _ canvasSize: CGSize, _ isSelected: Bool) {
20 | super.init(dpi,"Rectangle",location,size,canvasSize,isSelected)
21 | strokeWidth = 0.25 * dpi/72.0
22 | }
23 |
24 | enum CodingKeys : String, CodingKey {
25 | case strokeWidth
26 | case strokeColor
27 | case fillColor
28 | }
29 |
30 | required init(from decoder: Decoder) throws {
31 | try super.init(from: decoder)
32 | let values = try decoder.container(keyedBy: CodingKeys.self)
33 | strokeWidth = try values.decodeIfPresent(Double.self, forKey: .strokeWidth) ?? 0.25 * dpi/72.0
34 |
35 | let strokeColorData = try values.decodeIfPresent(Data.self, forKey: .strokeColor) ?? nil
36 | if strokeColorData != nil
37 | {
38 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: strokeColorData!)
39 | strokeColor = Color(color!)
40 | }
41 |
42 | let fillColorData = try values.decodeIfPresent(Data.self, forKey: .fillColor) ?? nil
43 | if fillColorData != nil
44 | {
45 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: fillColorData!)
46 | fillColor = Color(color!)
47 | }
48 | }
49 |
50 | override func encode(to encoder: Encoder) throws {
51 | try super.encode(to: encoder)
52 | var container = encoder.container(keyedBy: CodingKeys.self)
53 | try container.encode(strokeWidth, forKey: .strokeWidth)
54 |
55 | let convertedStrokeColor = UIColor(strokeColor)
56 | let strokeColorData = try NSKeyedArchiver.archivedData(withRootObject: convertedStrokeColor, requiringSecureCoding: false)
57 | try container.encode(strokeColorData, forKey: .strokeColor)
58 |
59 | let convertedFillColor = UIColor(fillColor)
60 | let fillColorData = try NSKeyedArchiver.archivedData(withRootObject: convertedFillColor, requiringSecureCoding: false)
61 | try container.encode(fillColorData, forKey: .fillColor)
62 | }
63 |
64 | override func view() -> AnyView {
65 | AnyView(
66 | Rectangle()
67 | .stroke(strokeColor, lineWidth: strokeWidth)
68 | .background(Rectangle().fill(fillColor))
69 | //.fill(Color.white)
70 | .frame(width: self.size.width, height: self.size.height)
71 | //.border(Color.black)
72 | .position(self.location)
73 | )
74 |
75 | }
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/ShapeX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | /*
12 | https://www.barcoderesource.com/barcodelabelappleapp.shtml
13 |
14 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
15 | */
16 |
17 | import SwiftUI
18 |
19 | class ShapeX: Codable, ObservableObject, Identifiable, Equatable {
20 | static func == (lhs: ShapeX, rhs: ShapeX) -> Bool {
21 | return lhs.id==rhs.id
22 | }
23 |
24 | var id = UUID()
25 |
26 | @Published var dpi = 300.0
27 | @Published var type: String = ""
28 | @Published var location: CGPoint = CGPoint(x: 50, y: 50)
29 | @Published var size: CGSize = CGSize(width: 100, height: 100)
30 | @Published var canvasSize: CGSize = CGSize(width: 1, height: 1)
31 | @Published var isSelected = false
32 | @Published var zIndex = 0.0
33 |
34 | var width: Float = 0.0
35 | var height: Float = 0.0
36 |
37 | init()
38 | {
39 |
40 | }
41 | init(_ dpi:Double, _ type: String, _ location: CGPoint, _ size: CGSize, _ canvasSize: CGSize, _ isSelected: Bool) {
42 | self.dpi=dpi
43 | self.type=type
44 | self.location=location
45 | self.size=size
46 | self.canvasSize=canvasSize
47 | self.isSelected = isSelected
48 | }
49 |
50 | func useElipsisIfSizeTooSmall() {
51 |
52 | }
53 |
54 | func view() -> AnyView {
55 | AnyView(EmptyView())
56 | }
57 |
58 | enum CodingKeys: String, CodingKey {
59 | case dpi
60 | case type
61 | case location
62 | case size
63 | case canvasSize
64 | case isSelected
65 | case zIndex
66 | }
67 |
68 | required init(from decoder: Decoder) throws {
69 | let values = try decoder.container(keyedBy: CodingKeys.self)
70 | dpi = try values.decodeIfPresent(Double.self, forKey: .dpi) ?? 300.0
71 | type = try values.decodeIfPresent(String.self, forKey: .type) ?? ""
72 | location = try values.decodeIfPresent(CGPoint.self, forKey: .location) ?? CGPoint(x: 50, y: 50)
73 | size = try values.decodeIfPresent(CGSize.self, forKey: .size) ?? CGSize(width: 100, height: 100)
74 | canvasSize = try values.decodeIfPresent(CGSize.self, forKey: .canvasSize) ?? CGSize(width: 1, height: 1)
75 | isSelected = try values.decodeIfPresent(Bool.self, forKey: .isSelected) ?? false
76 | zIndex = try values.decodeIfPresent(Double.self, forKey: .zIndex) ?? 0
77 | }
78 |
79 | func encode(to encoder: Encoder) throws {
80 | var container = encoder.container(keyedBy: CodingKeys.self)
81 | try container.encode(dpi, forKey: .dpi)
82 | try container.encode(type, forKey: .type)
83 | try container.encode(location, forKey: .location)
84 | try container.encode(size, forKey: .size)
85 | try container.encode(canvasSize, forKey: .canvasSize)
86 | try container.encode(isSelected, forKey: .isSelected)
87 | try container.encode(zIndex, forKey: .zIndex)
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/ShapesX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | /*
12 | https://www.barcoderesource.com/barcodelabelappleapp.shtml
13 |
14 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
15 | */
16 |
17 | import SwiftUI
18 |
19 | class ShapesX: Codable, ObservableObject{
20 | @Published var shapeList = [ShapeX]()
21 |
22 | init() {
23 |
24 | }
25 |
26 | func deSelectAll() {
27 | shapeList.forEach
28 | {
29 | $0.isSelected = false
30 | }
31 | }
32 |
33 | func add(shape: ShapeX)
34 | {
35 | shapeList.append(shape)
36 | }
37 |
38 | enum CodingKeys: String, CodingKey {
39 | case shapelist
40 | }
41 |
42 | enum ShapeTypeKey: CodingKey {
43 | case type
44 | }
45 |
46 | enum ShapeTypes: String, Decodable {
47 | case rectangle = "Rectangle"
48 | case ellipse = "Ellipse"
49 | case text = "Text"
50 | case image = "Image"
51 | case barcode = "Barcode"
52 | }
53 |
54 |
55 | required init(from decoder: Decoder) throws {
56 | let container = try decoder.container(keyedBy: CodingKeys.self)
57 | var shapesArrayForType = try container.nestedUnkeyedContainer(forKey: CodingKeys.shapelist)
58 | var newShapeList = [ShapeX]()
59 | var shapesArray = shapesArrayForType
60 |
61 | while(!shapesArrayForType.isAtEnd)
62 | {
63 |
64 | let shape = try shapesArrayForType.nestedContainer(keyedBy: ShapeTypeKey.self) //causes the
65 | let type = try shape.decode(ShapeTypes.self, forKey: ShapeTypeKey.type)
66 |
67 | switch type {
68 | case .rectangle:
69 | print("found rectangle")
70 | newShapeList.append(try shapesArray.decode(RectangleX.self)) //since currentIndex of shapesArray is still at previous location, decode the object
71 | case .ellipse:
72 | print("found ellipse")
73 | newShapeList.append(try shapesArray.decode(EllipseX.self))
74 | case .image:
75 | print("found image")
76 | newShapeList.append(try shapesArray.decode(ImageX.self))
77 | case .text:
78 | print("found text")
79 | newShapeList.append(try shapesArray.decode(TextX.self))
80 | case .barcode:
81 | print("found barcode")
82 | newShapeList.append(try shapesArray.decode(BarcodeX.self))
83 | }
84 | }
85 | self.shapeList = newShapeList
86 | }
87 |
88 | func encode(to encoder: Encoder) throws {
89 | var container = encoder.container(keyedBy: CodingKeys.self)
90 | try container.encode(shapeList, forKey: .shapelist)
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Shapes/TextX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 |
13 | class TextX: ShapeX {
14 |
15 | @Published var fontSize:CGFloat = 16.0*300.0/72.0
16 | @Published var text:String = "Text"
17 | @Published var originalText:String = "Text"
18 | @Published var fontName:String = "Arial"
19 | @Published var textColor = Color.black
20 | @Published var horizontalTextAlignment:String = "Center"
21 |
22 | init(_ dpi:Double, _ location: CGPoint, _ size: CGSize, _ canvasSize: CGSize, _ isSelected: Bool) {
23 |
24 | super.init(dpi,"Text",location,size,canvasSize,isSelected)
25 | fontSize=16.0*dpi/72.0
26 |
27 | }
28 |
29 | enum CodingKeys : String, CodingKey {
30 | case fontSize
31 | case text
32 | //case originalText
33 | case fontName
34 | case textColor
35 | case horizontalTextAlignment
36 | }
37 |
38 | required init(from decoder: Decoder) throws {
39 | try super.init(from: decoder)
40 | let values = try decoder.container(keyedBy: CodingKeys.self)
41 | fontSize = try values.decodeIfPresent(CGFloat.self, forKey: .fontSize) ?? 18.0*dpi/72.0
42 | text = try values.decodeIfPresent(String.self, forKey: .text) ?? "Text"
43 | fontName = try values.decodeIfPresent(String.self, forKey: .fontName) ?? "Arial"
44 |
45 | let textColorData = try values.decodeIfPresent(Data.self, forKey: .textColor) ?? nil
46 | if textColorData != nil
47 | {
48 | let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: textColorData!)
49 | textColor = Color(color!)
50 | }
51 | horizontalTextAlignment = try values.decodeIfPresent(String.self, forKey: .horizontalTextAlignment) ?? "Center"
52 |
53 | }
54 |
55 | override func encode(to encoder: Encoder) throws {
56 | try super.encode(to: encoder)
57 | var container = encoder.container(keyedBy: CodingKeys.self)
58 | try container.encode(fontSize, forKey: .fontSize)
59 | try container.encode(text, forKey: .text)
60 | try container.encode(fontName, forKey: .fontName)
61 | let convertedTextColor = UIColor(textColor)
62 | let textColorData = try NSKeyedArchiver.archivedData(withRootObject: convertedTextColor, requiringSecureCoding: false)
63 | try container.encode(textColorData, forKey: .textColor)
64 | try container.encode(horizontalTextAlignment, forKey: .horizontalTextAlignment)
65 |
66 | }
67 |
68 | override func view() -> AnyView {
69 | AnyView(
70 | HStack{
71 | if horizontalTextAlignment == "Right" { Spacer() }
72 | Text(self.text)
73 | .lineLimit(1)
74 | .font(.custom(self.fontName, size: self.fontSize))
75 | .foregroundColor(self.textColor)
76 | .fixedSize(horizontal: true, vertical: false)
77 | if horizontalTextAlignment == "Left" { Spacer() }
78 | }
79 | .frame(width: self.size.width, height: self.size.height)
80 | .clipShape(Rectangle())
81 | .position(self.location)
82 | )
83 | }
84 |
85 | override func useElipsisIfSizeTooSmall() {
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Util/LabelAction.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import Foundation
12 | class LabelAction
13 | {
14 | let pageSettings: PageSettings
15 | let shapes: ShapesX
16 |
17 | init(shapes: ShapesX, pageSettings: PageSettings) {
18 | self.shapes = shapes
19 | self.pageSettings = pageSettings
20 | }
21 |
22 | func generate() -> String{
23 | let encoder=JSONEncoder()
24 | encoder.outputFormatting = .prettyPrinted
25 |
26 | let shapesData = (try? encoder.encode(shapes))!
27 | let shapesDataStr = String(data: shapesData, encoding: .utf8)!
28 | let pageSettingsData = (try? encoder.encode(pageSettings))!
29 | let pageSettingsDataStr = String(data: pageSettingsData, encoding: .utf8)!
30 |
31 | var jsonObject: [String: String] = [String: String]()
32 |
33 | jsonObject["page_settings"]=pageSettingsDataStr
34 | jsonObject["shapes"]=shapesDataStr
35 |
36 | if let jsonData = try? encoder.encode(jsonObject) {
37 | if let jsonString = String(data: jsonData, encoding: .utf8) {
38 | //print(jsonString)
39 |
40 | var jsonLabel: [String: String] = [String: String]()
41 | jsonLabel["label"]=jsonString
42 |
43 | if let jsonLabelData = try? encoder.encode(jsonLabel) {
44 | if let jsonLabelString = String(data: jsonLabelData, encoding: .utf8) {
45 |
46 | return jsonLabelString
47 |
48 | }
49 | }
50 |
51 | }
52 | }
53 |
54 | return ""
55 | }
56 |
57 | func load(jsonLabelStr: String)
58 | {
59 | if let data = jsonLabelStr.data(using: .utf8) {
60 | //do {
61 | let labelDictionary : [String: Any] = (try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any])!
62 | let labelStr = labelDictionary["label"] as? String
63 |
64 | if let attributesData = labelStr!.data(using: .utf8) {
65 | let attributesDictionary : [String: Any] = (try? JSONSerialization.jsonObject(with: attributesData, options: []) as? [String: Any])!
66 | let loadedPageSettingsStr = attributesDictionary["page_settings"] as? String
67 | let loadedPageSettings = (try? JSONDecoder().decode(PageSettings.self, from: loadedPageSettingsStr!.data(using: .utf8)!))!
68 | let loadedShapesStr = attributesDictionary["shapes"] as? String
69 | let loadedShapes = (try? JSONDecoder().decode(ShapesX.self, from: loadedShapesStr!.data(using: .utf8)!))!
70 | pageSettings.dpi=loadedPageSettings.dpi
71 | pageSettings.name=loadedPageSettings.name
72 | pageSettings.category=loadedPageSettings.category
73 | pageSettings.vendor=loadedPageSettings.vendor
74 | pageSettings.description=loadedPageSettings.description
75 | pageSettings.type=loadedPageSettings.type
76 | pageSettings.pageWidth=loadedPageSettings.pageWidth
77 | pageSettings.pageHeight=loadedPageSettings.pageHeight
78 | pageSettings.labelWidth=loadedPageSettings.labelWidth
79 | pageSettings.labelHeight=loadedPageSettings.labelHeight
80 | pageSettings.leftMargin=loadedPageSettings.leftMargin
81 | pageSettings.topMargin=loadedPageSettings.topMargin
82 | pageSettings.labelWidth=loadedPageSettings.labelWidth
83 | pageSettings.hSpace=loadedPageSettings.hSpace
84 | pageSettings.vSpace=loadedPageSettings.vSpace
85 | pageSettings.numRows=loadedPageSettings.numRows
86 | pageSettings.numCols=loadedPageSettings.numCols
87 | pageSettings.dpi=loadedPageSettings.dpi
88 |
89 | shapes.shapeList=loadedShapes.shapeList
90 | pageSettings.generateLabels() //File Open
91 |
92 | print("loadedPageSettings:",loadedPageSettings.name,":",loadedPageSettings.numRows,":",loadedPageSettings.numCols)
93 |
94 | }
95 |
96 | //} catch {
97 | // print(error.localizedDescription)
98 | //}
99 | }
100 |
101 |
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/BarcodePropertiesViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class BarcodePropertiesViewModel: ObjectBaseViewModel {
10 |
11 | @Published var input: String = "1234"
12 | @Published var symbology: String = "Code 39"
13 | @Published var checkDigit: Bool = false
14 | @Published var barcode: String = "*1234*"
15 |
16 | @Published var humanReadableText: String = "*1234*"
17 |
18 | @Published var fontName: String = "CCode39_S3"
19 | @Published var fontSize: Double = 18.0
20 | @Published var textColor = Color.black
21 |
22 | @Published var hrFontName: String = "Arial"
23 | @Published var hrFontSize: Double = 16.0
24 | @Published var hrTextColor = Color.black
25 |
26 | @Published var alignment: String = "Center"
27 |
28 | var skipOnChange = false
29 | func setupSelectedProperties()
30 | {
31 |
32 | self.shapes.shapeList.forEach
33 | {
34 | if $0.isSelected == true {
35 | let selectedText = $0 as! BarcodeX
36 |
37 | self.input = selectedText.input
38 |
39 | self.checkDigit = selectedText.checkDigit
40 | print(selectedText.checkDigit)
41 |
42 | self.symbology = selectedText.symbology
43 | //bad fix
44 | if self.symbology == "Code 39"
45 | {
46 | skipOnChange=false
47 | }
48 | else
49 | {
50 | skipOnChange=true
51 | }
52 | self.barcode = selectedText.barcode
53 | self.humanReadableText = selectedText.humanReadableText
54 |
55 | self.textColor = selectedText.textColor
56 | self.fontName = selectedText.fontName
57 | print(fontName)
58 | self.fontSize = selectedText.fontSize
59 |
60 | self.hrTextColor = selectedText.hrTextColor
61 | self.hrFontName = selectedText.hrFontName
62 | self.hrFontSize = selectedText.hrFontSize
63 |
64 | self.alignment = selectedText.horizontalTextAlignment
65 | //self.zIndex = String(format: "%.0f", selectedText.zIndex)
66 | let tX = (selectedText.location.x - CGFloat(selectedText.size.width)/2.0) * 72.0 / 300.0
67 | let tY = (selectedText.location.y - CGFloat(selectedText.size.height)/2.0) * 72.0 / 300.0
68 | let tWidth = selectedText.size.width * 72.0 / 300.0
69 | let tHeight = selectedText.size.height * 72.0 / 300.0
70 | let tzIndex = selectedText.zIndex
71 | super.setupSelectedProperties(x:tX,y:tY,width:tWidth,height:tHeight,zIndex:tzIndex)
72 |
73 | }
74 | }
75 | }
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/BaseViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 |
8 | import Foundation
9 |
10 | class BaseViewModel: ObservableObject {
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/FileViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class FilesViewModel: BaseViewModel {
10 |
11 | @Published var files: [String] = []
12 | @Published var selectedFileName: String = ""
13 |
14 | func setupSelectedProperties()
15 | {
16 |
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/ImagePropertiesViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class ImagePropertiesViewModel: ObjectBaseViewModel {
10 |
11 | func setupSelectedProperties()
12 | {
13 | self.shapes.shapeList.forEach
14 | {
15 | if $0.isSelected == true {
16 | if $0 is ImageX
17 | {
18 | let selectedShape = $0 as! ImageX
19 |
20 | let tX = (selectedShape.location.x - CGFloat(selectedShape.size.width)/2.0) * 72.0 / 300.0
21 | let tY = (selectedShape.location.y - CGFloat(selectedShape.size.height)/2.0) * 72.0 / 300.0
22 | let tWidth = selectedShape.size.width * 72.0 / 300.0
23 | let tHeight = selectedShape.size.height * 72.0 / 300.0
24 | let tzIndex = selectedShape.zIndex
25 | super.setupSelectedProperties(x:tX,y:tY,width:tWidth,height:tHeight,zIndex:tzIndex)
26 |
27 | }
28 |
29 | }
30 | }
31 | }
32 |
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/ObjectBaseViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 | class ObjectBaseViewModel: ObservableObject {
11 |
12 | @Published var x: String = ""
13 | @Published var y: String = ""
14 | @Published var width: String = ""
15 | @Published var height: String = ""
16 | @Published var zIndex: String = "0"
17 |
18 | let shapes: ShapesX
19 | init(shapes: ShapesX) {
20 | self.shapes = shapes
21 | }
22 |
23 | func setupSelectedProperties(x: CGFloat, y:CGFloat, width:CGFloat, height:CGFloat, zIndex: Double)
24 | {
25 | print("setup x:",x)
26 | self.x = String(format: "%.0f", x)
27 | self.y = String(format: "%.0f", y)
28 | self.width = String(format: "%.0f", width)
29 | self.height = String(format: "%.0f", height)
30 | self.zIndex = String(format: "%.0f", zIndex)
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/PreviewViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class PreviewViewModel: BaseViewModel {
10 |
11 | @Published var startLabel: String = "1"
12 | @Published var numPages: String = "1"
13 | @Published var orientation: String = "Landscape"
14 |
15 | @Published var istartLabel : Int = 1
16 | @Published var inumPages : Int = 1
17 | @Published var scaleFactor : Double = 0.11
18 | @Published var printBorder : Bool = true
19 |
20 | init(dpi : Double, pageType: String)
21 | {
22 | super.init()
23 | let dpiFactor = 300.0/dpi
24 | scaleFactor = pageType == "envelope-landscape" ? 0.05 : 0.11
25 | scaleFactor = scaleFactor*dpiFactor
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/ShapePropertiesViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class ShapePropertiesViewModel: ObjectBaseViewModel {
10 |
11 | @Published var strokeWidth: Double = 1.0
12 | @Published var strokeColor = Color.black
13 | @Published var fillColor = Color.white
14 | func setupSelectedProperties()
15 | {
16 | self.shapes.shapeList.forEach
17 | {
18 | if $0.isSelected == true {
19 | if $0 is RectangleX
20 | {
21 | let selectedShape = $0 as! RectangleX
22 | print(selectedShape.strokeWidth)
23 | self.strokeWidth = selectedShape.strokeWidth
24 | self.strokeColor = selectedShape.strokeColor
25 | self.fillColor = selectedShape.fillColor
26 | //self.zIndex = String(format: "%.0f", selectedShape.zIndex)
27 |
28 | let tX = (selectedShape.location.x - CGFloat(selectedShape.size.width)/2.0) * 72.0 / 300.0
29 | let tY = (selectedShape.location.y - CGFloat(selectedShape.size.height)/2.0) * 72.0 / 300.0
30 | let tWidth = selectedShape.size.width * 72.0 / 300.0
31 | let tHeight = selectedShape.size.height * 72.0 / 300.0
32 | let tzIndex = selectedShape.zIndex
33 | super.setupSelectedProperties(x:tX,y:tY,width:tWidth,height:tHeight,zIndex:tzIndex)
34 |
35 | }
36 | else if $0 is EllipseX
37 | {
38 | let selectedShape = $0 as! EllipseX
39 | self.strokeWidth = selectedShape.strokeWidth
40 | self.strokeColor = selectedShape.strokeColor
41 | self.fillColor = selectedShape.fillColor
42 | //self.zIndex = String(format: "%.0f", selectedShape.zIndex)
43 |
44 | let tX = (selectedShape.location.x - CGFloat(selectedShape.size.width)/2.0) * 72.0 / 300.0
45 | let tY = (selectedShape.location.y - CGFloat(selectedShape.size.height)/2.0) * 72.0 / 300.0
46 | let tWidth = selectedShape.size.width * 72.0 / 300.0
47 | let tHeight = selectedShape.size.height * 72.0 / 300.0
48 | let tzIndex = selectedShape.zIndex
49 | super.setupSelectedProperties(x:tX,y:tY,width:tWidth,height:tHeight,zIndex:tzIndex)
50 |
51 | }
52 |
53 | }
54 | }
55 | }
56 |
57 |
58 |
59 | }
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/TemplateViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class TemplateViewModel: BaseViewModel {
10 | @Published var name: String = "Standard SLE005"
11 | @Published var category: String = "Labels"
12 | @Published var vendor: String = "Standard"
13 | @Published var description: String = "Address Label (Letter) - 10x3"
14 | @Published var type: String = "iso-letter"
15 | @Published var units: String = "Inches"
16 | @Published var pageWidth: String = "8.5"
17 | @Published var pageHeight: String = "11.0"
18 | @Published var leftMargin: String = "0.188"
19 | @Published var topMargin: String = "0.5"
20 | @Published var labelWidth: String = "2.625"
21 | @Published var labelHeight: String = "1.0"
22 | @Published var hSpace: String = "0.125"
23 | @Published var vSpace: String = "0.0"
24 | @Published var numRows: String = "10"
25 | @Published var numCols: String = "3"
26 | @Published var selectedTemplateIndex: Int = 0
27 | @Published var templateCount: Int = 11
28 |
29 | @Published var previewFactor: Double = 0.25
30 |
31 | let pageSettings: PageSettings
32 | init(units: String, pageSettings: PageSettings) {
33 | self.units=units
34 | self.pageSettings = pageSettings
35 |
36 | name = pageSettings.name
37 | category = pageSettings.category
38 | print("PS:",pageSettings.vendor)
39 | vendor = pageSettings.vendor
40 | description = pageSettings.description
41 | type = pageSettings.type
42 |
43 | var inchOrCM = 1.0
44 | if units != "Inches"
45 | {
46 | inchOrCM = 2.54
47 | }
48 | pageWidth = String(format: "%.3f", pageSettings.pageWidth*inchOrCM)
49 | pageHeight = String(format: "%.3f", pageSettings.pageHeight*inchOrCM)
50 | leftMargin = String(format: "%.3f", pageSettings.leftMargin*inchOrCM)
51 | topMargin = String(format: "%.3f", pageSettings.topMargin*inchOrCM)
52 | labelWidth = String(format: "%.3f", pageSettings.labelWidth*inchOrCM)
53 | labelHeight = String(format: "%.3f", pageSettings.labelHeight*inchOrCM)
54 | hSpace = String(format: "%.3f", pageSettings.hSpace*inchOrCM)
55 | vSpace = String(format: "%.3f", pageSettings.vSpace*inchOrCM)
56 | numRows = String(pageSettings.numRows)
57 | numCols = String(pageSettings.numCols)
58 |
59 | }
60 |
61 | func setupPageSettingsAndTemplateModel(tempPageSettings: PageSettings, selectedTemplateIndex: Int)
62 | {
63 |
64 | let x = selectedTemplateIndex
65 | print("setupPageSettings:",x)
66 | tempPageSettings.name = labelTemplates[x][0]
67 | tempPageSettings.category = labelTemplates[x][1]
68 | tempPageSettings.vendor = labelTemplates[x][2]
69 | tempPageSettings.description = labelTemplates[x][3]
70 | tempPageSettings.type = labelTemplates[x][4]
71 | print(tempPageSettings.description)
72 | if tempPageSettings.type == "envelope-landscape"
73 | {
74 | tempPageSettings.pageHeight = Double(labelTemplates[x][5]) ?? 1.0
75 | tempPageSettings.pageWidth = Double(labelTemplates[x][6]) ?? 1.0
76 | tempPageSettings.labelHeight = Double(labelTemplates[x][7]) ?? 1.0
77 | tempPageSettings.labelWidth = Double(labelTemplates[x][8]) ?? 1.0
78 | tempPageSettings.vSpace = Double(labelTemplates[x][9]) ?? 0.0
79 | tempPageSettings.hSpace = Double(labelTemplates[x][10]) ?? 0.0
80 | tempPageSettings.numCols = Int(labelTemplates[x][11]) ?? 1
81 | tempPageSettings.numRows = Int(labelTemplates[x][12]) ?? 1
82 | tempPageSettings.topMargin = Double(labelTemplates[x][13]) ?? 0.0
83 | tempPageSettings.leftMargin = Double(labelTemplates[x][14]) ?? 0.0
84 | }
85 | else{
86 | tempPageSettings.pageWidth = Double(labelTemplates[x][5]) ?? 1.0
87 | tempPageSettings.pageHeight = Double(labelTemplates[x][6]) ?? 1.0
88 | tempPageSettings.labelWidth = Double(labelTemplates[x][7]) ?? 1.0
89 | tempPageSettings.labelHeight = Double(labelTemplates[x][8]) ?? 1.0
90 | tempPageSettings.hSpace = Double(labelTemplates[x][9]) ?? 0.0
91 | tempPageSettings.vSpace = Double(labelTemplates[x][10]) ?? 0.0
92 | tempPageSettings.numRows = Int(labelTemplates[x][11]) ?? 1
93 | tempPageSettings.numCols = Int(labelTemplates[x][12]) ?? 1
94 | tempPageSettings.leftMargin = Double(labelTemplates[x][13]) ?? 0.0
95 | tempPageSettings.topMargin = Double(labelTemplates[x][14]) ?? 0.0
96 | }
97 |
98 | tempPageSettings.generateLabels(dpi:72)
99 |
100 |
101 | name = tempPageSettings.name
102 | category = tempPageSettings.category
103 | vendor = tempPageSettings.vendor
104 | description = tempPageSettings.description
105 | type = tempPageSettings.type
106 | var inchOrCM = 1.0
107 | if units != "Inches"
108 | {
109 | inchOrCM = 2.54
110 | }
111 | pageWidth = String(format: "%.3f", tempPageSettings.pageWidth*inchOrCM)
112 | pageHeight = String(format: "%.3f", tempPageSettings.pageHeight*inchOrCM)
113 | leftMargin = String(format: "%.3f", tempPageSettings.leftMargin*inchOrCM)
114 | topMargin = String(format: "%.3f", tempPageSettings.topMargin*inchOrCM)
115 | labelWidth = String(format: "%.3f", tempPageSettings.labelWidth*inchOrCM)
116 | labelHeight = String(format: "%.3f", tempPageSettings.labelHeight*inchOrCM)
117 | hSpace = String(format: "%.3f", tempPageSettings.hSpace*inchOrCM)
118 | vSpace = String(format: "%.3f", tempPageSettings.vSpace*inchOrCM)
119 | numRows = String(tempPageSettings.numRows)
120 | numCols = String(tempPageSettings.numCols)
121 | }
122 |
123 |
124 | //use by create label only
125 | func setupPageSettings(selectedTemplateIndex: Int)
126 | {
127 | let x = selectedTemplateIndex
128 | print("setupPageSettings:",x)
129 | pageSettings.name = labelTemplates[x][0]
130 | pageSettings.category = labelTemplates[x][1]
131 | pageSettings.vendor = labelTemplates[x][2]
132 | pageSettings.description = labelTemplates[x][3]
133 | pageSettings.type = labelTemplates[x][4]
134 | if pageSettings.type == "envelope-landscape"
135 | {
136 | pageSettings.pageHeight = Double(labelTemplates[x][5]) ?? 1.0
137 | pageSettings.pageWidth = Double(labelTemplates[x][6]) ?? 1.0
138 | pageSettings.labelHeight = Double(labelTemplates[x][7]) ?? 1.0
139 | pageSettings.labelWidth = Double(labelTemplates[x][8]) ?? 1.0
140 | pageSettings.vSpace = Double(labelTemplates[x][9]) ?? 0.0
141 | pageSettings.hSpace = Double(labelTemplates[x][10]) ?? 0.0
142 | pageSettings.numCols = Int(labelTemplates[x][11]) ?? 1
143 | pageSettings.numRows = Int(labelTemplates[x][12]) ?? 1
144 | pageSettings.topMargin = Double(labelTemplates[x][13]) ?? 0.0
145 | pageSettings.leftMargin = Double(labelTemplates[x][14]) ?? 0.0
146 | }
147 | else{
148 | pageSettings.pageWidth = Double(labelTemplates[x][5]) ?? 1.0
149 | pageSettings.pageHeight = Double(labelTemplates[x][6]) ?? 1.0
150 | pageSettings.labelWidth = Double(labelTemplates[x][7]) ?? 1.0
151 | pageSettings.labelHeight = Double(labelTemplates[x][8]) ?? 1.0
152 | pageSettings.hSpace = Double(labelTemplates[x][9]) ?? 0.0
153 | pageSettings.vSpace = Double(labelTemplates[x][10]) ?? 0.0
154 | pageSettings.numRows = Int(labelTemplates[x][11]) ?? 1
155 | pageSettings.numCols = Int(labelTemplates[x][12]) ?? 1
156 | pageSettings.leftMargin = Double(labelTemplates[x][13]) ?? 0.0
157 | pageSettings.topMargin = Double(labelTemplates[x][14]) ?? 0.0
158 | }
159 |
160 | pageSettings.generateLabels()
161 | }
162 |
163 | }
164 |
165 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/ViewModels/TextPropertiesViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelMainViewModel.swift
3 | //
4 | //
5 | // Created by on 23/3/22.
6 | //
7 | import SwiftUI
8 |
9 | class TextPropertiesViewModel: ObjectBaseViewModel {
10 |
11 | @Published var text: String = "Text"
12 | @Published var fontName: String = "Arial"
13 | @Published var fontSize: Double = 18.0
14 | @Published var textColor = Color.black
15 | @Published var alignment: String = "Center"
16 | //@Published var zIndex: String = "0"
17 |
18 |
19 | func setupSelectedProperties()
20 | {
21 | self.shapes.shapeList.forEach
22 | {
23 | if $0.isSelected == true {
24 | let selectedText = $0 as! TextX
25 |
26 | self.text = selectedText.text
27 | self.textColor = selectedText.textColor
28 | self.fontName = selectedText.fontName
29 | self.fontSize = selectedText.fontSize
30 | self.alignment = selectedText.horizontalTextAlignment
31 | //self.zIndex = String(format: "%.0f", selectedText.zIndex)
32 |
33 |
34 |
35 | /*
36 | self.x = String(format: "%.0f", (selectedText.location.x - CGFloat(selectedText.size.width)/2.0) * 72.0 / 300.0)
37 | self.y = String(format: "%.0f", (selectedText.location.y - CGFloat(selectedText.size.height)/2.0) * 72.0 / 300.0)
38 | self.width = String(format: "%.0f", selectedText.size.width * 72.0 / 300.0)
39 | self.height = String(format: "%.0f", selectedText.size.height * 72.0 / 300.0)
40 | */
41 | let tX = (selectedText.location.x - CGFloat(selectedText.size.width)/2.0) * 72.0 / 300.0
42 | let tY = (selectedText.location.y - CGFloat(selectedText.size.height)/2.0) * 72.0 / 300.0
43 | let tWidth = selectedText.size.width * 72.0 / 300.0
44 | let tHeight = selectedText.size.height * 72.0 / 300.0
45 | let tzIndex = selectedText.zIndex
46 | super.setupSelectedProperties(x:tX,y:tY,width:tWidth,height:tHeight,zIndex:tzIndex)
47 |
48 | }
49 | }
50 | }
51 |
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/AlertWrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertWrapper.swift
3 | //
4 | //
5 | // Created by on 7/4/22.
6 | //
7 |
8 | import SwiftUI
9 | import Combine
10 | //https://stackoverflow.com/questions/56726663/how-to-add-a-textfield-to-alert-in-swiftui
11 | class TextFieldAlertViewController: UIViewController {
12 |
13 | /// Presents a UIAlertController (alert style) with a UITextField and a `Done` button
14 | /// - Parameters:
15 | /// - title: to be used as title of the UIAlertController
16 | /// - message: to be used as optional message of the UIAlertController
17 | /// - text: binding for the text typed into the UITextField
18 | /// - isPresented: binding to be set to false when the alert is dismissed (`Done` button tapped)
19 | init(title: String, message: String?, labelContent: String, text: Binding, isPresented: Binding?, saveSuccess: Binding?, existingLabelExist: Binding?, alertMessage: Binding) {
20 | self.alertTitle = title
21 | self.message = message
22 | self.labelContent = labelContent
23 | self._text = text
24 | self.isPresented = isPresented
25 | self.saveSuccess = saveSuccess
26 | self.existingLabelExist = existingLabelExist
27 | self._alertMessage = alertMessage
28 |
29 | super.init(nibName: nil, bundle: nil)
30 | }
31 |
32 | required init?(coder: NSCoder) {
33 | fatalError("init(coder:) has not been implemented")
34 | }
35 |
36 | // MARK: - Dependencies
37 | private let alertTitle: String
38 | private let message: String?
39 | private let labelContent: String
40 | @Binding private var text: String?
41 | private var isPresented: Binding?
42 | private var saveSuccess: Binding?
43 | private var existingLabelExist: Binding?
44 | @Binding private var alertMessage: String?
45 |
46 | // MARK: - Private Properties
47 | private var subscription: AnyCancellable?
48 |
49 | // MARK: - Lifecycle
50 | override func viewDidAppear(_ animated: Bool) {
51 | super.viewDidAppear(animated)
52 | presentAlertController()
53 | }
54 |
55 | private func presentAlertController() {
56 | guard subscription == nil else { return } // present only once
57 |
58 | let vc = UIAlertController(title: alertTitle, message: message, preferredStyle: .alert)
59 |
60 | // add a textField and create a subscription to update the `text` binding
61 | vc.addTextField { [weak self] textField in
62 | guard let self = self else { return }
63 | self.subscription = NotificationCenter.default
64 | .publisher(for: UITextField.textDidChangeNotification, object: textField)
65 | .map { ($0.object as? UITextField)?.text }
66 | .assign(to: \.text, on: self)
67 | }
68 |
69 | let caction = UIAlertAction(title: "Cancel", style: .default) { [weak self] _ in
70 | self?.isPresented?.wrappedValue = false
71 | self?.saveSuccess?.wrappedValue = false
72 |
73 | }
74 |
75 | // create a `Done` action that updates the `isPresented` binding when tapped
76 | // this is just for Demo only but we should really inject
77 | // an array of buttons (with their title, style and tap handler)
78 | let action = UIAlertAction(title: "Save", style: .default) { [weak self] _ in
79 | self?.isPresented?.wrappedValue = false
80 |
81 |
82 | if self!.text != nil
83 | {
84 |
85 | }
86 | else
87 | {
88 | self?.saveSuccess?.wrappedValue = true //actually not success but reuse
89 | self?.alertMessage = Optional.some("Please enter a valid label name for saving.")
90 | return
91 | }
92 |
93 | if self!.text! == ""
94 | {
95 | self?.saveSuccess?.wrappedValue = true //actually not success but reuse
96 | self?.alertMessage = Optional.some("Please enter a valid label name for saving.")
97 | return
98 | }
99 |
100 | print("Saving:",self!.text!)
101 |
102 | let file = self!.text!
103 |
104 | if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
105 |
106 | let fileURL = dir.appendingPathComponent(file)
107 | let fileManager = FileManager.default
108 | print(fileURL.path)
109 | print(file)
110 |
111 | if fileManager.fileExists(atPath: fileURL.path) {
112 | print("FILE AVAILABLE")
113 | self?.saveSuccess?.wrappedValue = true
114 | self?.alertMessage = Optional.some("An existing label with the same name already exist. Please enter another label name and try saving again.")
115 | } else {
116 | print("FILE NOT AVAILABLE")
117 | do {
118 | try self!.labelContent.write(to: fileURL, atomically: false, encoding: .utf8)
119 | self?.saveSuccess?.wrappedValue = true
120 | self?.alertMessage = Optional.some("Label saved successfully.")
121 | }
122 | catch {
123 | self?.text = Optional.some("")
124 | }
125 | }
126 | self?.text = Optional.some("")
127 |
128 | }
129 |
130 |
131 | }
132 |
133 | vc.addAction(caction)
134 | vc.addAction(action)
135 | present(vc, animated: true, completion: nil)
136 | }
137 | }
138 |
139 | struct TextFieldAlert {
140 |
141 | // MARK: Properties
142 | let title: String
143 | let message: String?
144 | let labelContent: String
145 | @Binding var text: String?
146 | var isPresented: Binding? = nil
147 | var saveSuccess: Binding? = nil
148 | var existingLabelExist: Binding? = nil
149 | @Binding var alertMessage: String?
150 |
151 | // MARK: Modifiers
152 | func dismissable(_ isPresented: Binding) -> TextFieldAlert {
153 | TextFieldAlert(title: title, message: message,labelContent:labelContent, text: $text, isPresented: isPresented, saveSuccess: saveSuccess, existingLabelExist: existingLabelExist,alertMessage: $alertMessage)
154 | }
155 | }
156 |
157 | extension TextFieldAlert: UIViewControllerRepresentable {
158 |
159 | typealias UIViewControllerType = TextFieldAlertViewController
160 |
161 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIViewControllerType {
162 | TextFieldAlertViewController(title: title, message: message, labelContent: labelContent, text: $text, isPresented: isPresented, saveSuccess: saveSuccess, existingLabelExist: existingLabelExist, alertMessage: $alertMessage)
163 | }
164 |
165 | func updateUIViewController(_ uiViewController: UIViewControllerType,
166 | context: UIViewControllerRepresentableContext) {
167 | // no update needed
168 | }
169 | }
170 |
171 | struct TextFieldWrapper: View {
172 |
173 | @Binding var isPresented: Bool
174 | let presentingView: PresentingView
175 | let content: () -> TextFieldAlert
176 |
177 | var body: some View {
178 | ZStack {
179 | if (isPresented) { content().dismissable($isPresented) }
180 | presentingView
181 | }
182 | }
183 | }
184 |
185 | extension View {
186 | func textFieldAlert(isPresented: Binding,
187 | content: @escaping () -> TextFieldAlert) -> some View {
188 | TextFieldWrapper(isPresented: isPresented,
189 | presentingView: self,
190 | content: content)
191 | }
192 | }
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/DimensionsPropertiesViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DimensionPropertiesViewX.swift
3 | //
4 | //
5 | // Created by on 21/4/22.
6 | //
7 | import SwiftUI
8 |
9 | struct DimensionsPropertiesViewX: View {
10 |
11 |
12 | @EnvironmentObject var shapes: ShapesX
13 | @StateObject var objectPropertiesViewModel: ObjectBaseViewModel
14 |
15 | var body: some View {
16 |
17 | Section(header: Text("Dimensions (Pixels)")){
18 |
19 | HStack{
20 | Text("X")
21 | Spacer()
22 |
23 | TextField("X", text: $objectPropertiesViewModel.x)
24 | .multilineTextAlignment(.trailing)
25 | .frame(width: 100)
26 | .fixedSize()
27 | .onChange(of: objectPropertiesViewModel.x) { newValue in
28 | self.shapes.shapeList.forEach
29 | {
30 | let trimStr = newValue.count > 4 ? String(newValue.prefix(4)) : newValue
31 | if $0.isSelected == true {
32 | let selectedText = $0 //as! TextX
33 | if let n = NumberFormatter().number(from: trimStr) {
34 |
35 | //number is assumed to be in inch x 72pixels
36 | let xIn72 = CGFloat(truncating: n)
37 | let widthIn300 = CGFloat($0.size.width)/2.0
38 | let finalX = xIn72*300.0/72.0 + widthIn300
39 | //print("imvs:",selectedText.imageViewSize.width)
40 | //print("sts:",selectedText.size.width)
41 | //print("fx:",finalX)
42 |
43 | if finalX >= 0.0 &&
44 | finalX <= selectedText.canvasSize.width
45 | {
46 | selectedText.location.x = finalX
47 | }
48 |
49 | //set to max so that behavior seems ok
50 | if finalX > selectedText.canvasSize.width
51 | {
52 | selectedText.location.x = selectedText.canvasSize.width
53 | }
54 |
55 | print(selectedText.location.x)
56 | }
57 | }
58 | }
59 | }
60 | }//HStack
61 | HStack{
62 | Text("Y")
63 | Spacer()
64 | TextField("Y", text: $objectPropertiesViewModel.y)
65 | .multilineTextAlignment(.trailing)
66 | .frame(width: 100)
67 | .fixedSize()
68 | .onChange(of: objectPropertiesViewModel.y) { newValue in
69 | self.shapes.shapeList.forEach
70 | {
71 | let trimStr = newValue.count > 4 ? String(newValue.prefix(4)) : newValue
72 | if $0.isSelected == true {
73 | let selectedText = $0 //as! TextX
74 | if let n = NumberFormatter().number(from: trimStr) {
75 |
76 | //number is assumed to be in inch x 72pixels
77 | let yIn72 = CGFloat(truncating: n)
78 | let heightIn300 = CGFloat($0.size.height)/2.0
79 | let finalY = yIn72*300.0/72.0 + heightIn300
80 |
81 | if finalY >= 0.0 &&
82 | finalY <= selectedText.canvasSize.height
83 | {
84 | selectedText.location.y = finalY
85 | }
86 |
87 | //set to max so that behavior seems ok
88 | if finalY > selectedText.canvasSize.height
89 | {
90 | selectedText.location.y = selectedText.canvasSize.height
91 | }
92 | print(selectedText.location.y)
93 | }
94 | }
95 | }
96 | }
97 | }//HStack
98 |
99 | HStack{
100 | Text("Width")
101 | Spacer()
102 | TextField("Width", text: $objectPropertiesViewModel.width)
103 | .multilineTextAlignment(.trailing)
104 | .frame(width: 100)
105 | .fixedSize()
106 | .onChange(of: objectPropertiesViewModel.width) { newValue in
107 | self.shapes.shapeList.forEach
108 | {
109 | let trimStr = newValue.count > 4 ? String(newValue.prefix(4)) : newValue
110 | if $0.isSelected == true {
111 | let selectedText = $0 //as! TextX
112 | if let n = NumberFormatter().number(from: trimStr) {
113 |
114 | //number is assumed to be in inch x 72pixels
115 | let widthIn72 = CGFloat(truncating: n)
116 | let finalWidth = widthIn72*300.0/72.0
117 |
118 | if finalWidth > 0.0 &&
119 | finalWidth < selectedText.canvasSize.width
120 | {
121 | selectedText.size.width = finalWidth
122 | }
123 |
124 | if finalWidth < 80.0
125 | {
126 | selectedText.size.width = 80.0
127 | }
128 |
129 | //set to max so that behavior seems ok
130 | if finalWidth > selectedText.canvasSize.width - 20
131 | {
132 | selectedText.size.width = selectedText.canvasSize.width - 20
133 | }
134 |
135 | //update x as width changes in both directions
136 | objectPropertiesViewModel.x = String(format: "%.0f", (selectedText.location.x - CGFloat(selectedText.size.width)/2.0) * 72.0 / 300.0)
137 | print(selectedText.size.width)
138 | }
139 | }
140 | }
141 | }
142 | }//HStack
143 |
144 | HStack{
145 | Text("Height")
146 | Spacer()
147 | TextField("Height", text: $objectPropertiesViewModel.height)
148 | .multilineTextAlignment(.trailing)
149 | .frame(width: 100)
150 | .fixedSize()
151 | .onChange(of: objectPropertiesViewModel.height) { newValue in
152 | self.shapes.shapeList.forEach
153 | {
154 | let trimStr = newValue.count > 4 ? String(newValue.prefix(4)) : newValue
155 | if $0.isSelected == true {
156 | let selectedText = $0 //as! TextX
157 | if let n = NumberFormatter().number(from: trimStr) {
158 |
159 | //number is assumed to be in inch x 72pixels
160 | let heightIn72 = CGFloat(truncating: n)
161 | let finalHeight = heightIn72*300.0/72.0
162 |
163 | if finalHeight > 0.0 &&
164 | finalHeight < selectedText.canvasSize.height
165 | {
166 | selectedText.size.height = finalHeight
167 | }
168 |
169 | if finalHeight < 80.0
170 | {
171 | selectedText.size.height = 80.0
172 | }
173 |
174 | //set to max so that behavior seems ok
175 | if finalHeight > selectedText.canvasSize.height - 20
176 | {
177 | selectedText.size.height = selectedText.canvasSize.height - 20
178 | }
179 | //update x as width changes in both directions
180 | objectPropertiesViewModel.y = String(format: "%.0f", (selectedText.location.y - CGFloat(selectedText.size.height)/2.0) * 72.0 / 300.0)
181 |
182 | print(selectedText.size.height)
183 | }
184 | }
185 | }
186 | }
187 | }//HStack
188 |
189 |
190 |
191 | }
192 | Section(header: Text("zIndex (Higher values are in front)")){
193 | HStack{
194 | TextField("zIndex", text: $objectPropertiesViewModel.zIndex)
195 | .onChange(of: objectPropertiesViewModel.zIndex) { newValue in
196 | self.shapes.shapeList.forEach
197 | {
198 | if $0.isSelected == true {
199 | let selectedText = $0 //as! ShapeX
200 | selectedText.zIndex = Double(newValue) ?? 0.0
201 | selectedText.zIndex = selectedText.zIndex > 100.0 ? 100.0 : selectedText.zIndex
202 | selectedText.zIndex = selectedText.zIndex < -100.0 ? -100.0 : selectedText.zIndex
203 |
204 | }
205 |
206 | }
207 | }
208 | }
209 | }
210 | }
211 |
212 | func setupViewModel()
213 | {
214 | //textPropertiesViewModel.setupSelectedProperties()
215 |
216 | }
217 |
218 | }
219 |
220 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/FilesViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilesView.swift
3 | //
4 | //
5 | // Created by on 8/4/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @available(iOS 15.0, *)
11 | struct FilesViewX: View {
12 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
13 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
14 |
15 | @EnvironmentObject var optionSettings: OptionSettings
16 | @EnvironmentObject var appSettings: AppSettings
17 | @EnvironmentObject var pageSettings: PageSettings
18 | @EnvironmentObject var shapes: ShapesX
19 | @StateObject var filesViewModel: FilesViewModel
20 | @State var showFileAlert = false
21 | @State private var toBeDeleted: IndexSet?
22 | @State var showingDeleteAlert = false
23 |
24 | var body: some View {
25 |
26 | NavigationView {
27 | Form {
28 | Section(header: Text("Tap to Open or Swipe Left to Delete")){
29 | List {
30 | ForEach(filesViewModel.files, id: \.self) { filename in
31 | Text(filename).onTapGesture {
32 | showFileAlert = true
33 | print(filename)
34 | filesViewModel.selectedFileName=filename
35 | }.swipeActions() {
36 | Button(role: .destructive) {
37 | print("delete")
38 | self.showingDeleteAlert = true
39 | filesViewModel.selectedFileName=filename
40 | } label: {
41 | Label("Delete", systemImage: "trash")
42 | }
43 | }.alert(isPresented: self.$showingDeleteAlert) {
44 |
45 | Alert(title: Text("Are you sure you want to delete this?"), message: Text("This label will be removed permanently."), primaryButton: .destructive(Text("Delete")) {
46 | let filename = filesViewModel.selectedFileName
47 | print(filename)
48 | if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
49 |
50 | let fileURL = dir.appendingPathComponent(filename)
51 | do {
52 | try FileManager.default.removeItem(at: fileURL)
53 | }
54 | catch {}
55 |
56 | }
57 |
58 | filesViewModel.files.remove(at: filesViewModel.files.firstIndex(of: filename)!)
59 | }, secondaryButton: .cancel() {
60 | //self.toBeDeleted = nil
61 | }
62 | )
63 | }
64 | }
65 |
66 | }
67 | .font(.subheadline)
68 | }
69 |
70 | }
71 | .navigationTitle("My Labels")
72 | .navigationBarTitleDisplayMode(.inline)
73 | }
74 | //.frame(height:290)
75 | .onAppear(perform: setupViewModel)
76 | .alert(isPresented: $showFileAlert) {
77 | Alert(
78 | title: Text("Are you sure you want to open this?"),
79 | message: Text("Your current label will be overwritten."),
80 | primaryButton: .default(Text("Open")) {
81 | //open label
82 | do {
83 | // Get the document directory url
84 | let documentDirectory = try FileManager.default.url(
85 | for: .documentDirectory,
86 | in: .userDomainMask,
87 | appropriateFor: nil,
88 | create: true
89 | )
90 | print("documentDirectory", documentDirectory.path)
91 |
92 | let fileURL = documentDirectory.appendingPathComponent(filesViewModel.selectedFileName)
93 |
94 | let jsonStr = try String(contentsOf: fileURL, encoding: .utf8)
95 | let labelAction = LabelAction(shapes: shapes, pageSettings: pageSettings)
96 | labelAction.load(jsonLabelStr: jsonStr)
97 | appSettings.dpi=pageSettings.dpi
98 | optionSettings.showAlert = false
99 | optionSettings.showPropertiesSheet = false
100 | appSettings.zoomFactor = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.5 : 0.28
101 |
102 | }
103 | catch {
104 | print(error)
105 | }
106 | },
107 | secondaryButton: .cancel()
108 | )
109 |
110 | }
111 | }
112 | func share()
113 | {
114 |
115 | }
116 |
117 | func delete(at offsets: IndexSet) {
118 |
119 | self.toBeDeleted = offsets
120 | self.showingDeleteAlert = true
121 | }
122 |
123 | func setupViewModel()
124 | {
125 | do {
126 | let documentDirectory = try FileManager.default.url(
127 | for: .documentDirectory,
128 | in: .userDomainMask,
129 | appropriateFor: nil,
130 | create: true
131 | )
132 | print("documentDirectory", documentDirectory.path)
133 | let directoryContents = try FileManager.default.contentsOfDirectory(
134 | at: documentDirectory,
135 | includingPropertiesForKeys: nil
136 | )
137 | for url in directoryContents {
138 | print(url.lastPathComponent)
139 | if (url.lastPathComponent != "Label.pdf")
140 | {
141 | filesViewModel.files.append(url.lastPathComponent)
142 | }
143 | }
144 | }
145 | catch {
146 | print(error)
147 | }
148 | }
149 | }
150 |
151 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/ImagePickerX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // imagePicker.swift
3 | //
4 | //
5 | // Created by on 27/01/2021.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | struct ImagePickerX: UIViewControllerRepresentable {
12 |
13 | @EnvironmentObject var shapes: ShapesX
14 | @EnvironmentObject var optionSettings: OptionSettings
15 | @Environment(\.presentationMode) var presentationMode
16 |
17 |
18 | class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
19 |
20 | var parent: ImagePickerX
21 |
22 | init(_ parent: ImagePickerX) {
23 | self.parent = parent
24 | }
25 |
26 |
27 | public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
28 |
29 | if parent.optionSettings.action == "NewImage"
30 | {
31 | var findshape: ShapeX? = nil
32 | parent.shapes.shapeList.forEach
33 | {
34 | if $0.isSelected == true {
35 | findshape = $0
36 | }
37 | }
38 | if let x = parent.shapes.shapeList.firstIndex(of: findshape!)
39 | {
40 | parent.shapes.shapeList.remove(at: x)
41 | }
42 | }
43 |
44 | print("dismis")
45 | parent.presentationMode.wrappedValue.dismiss()
46 | }
47 |
48 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
49 |
50 | print("get")
51 | if let uiImage = info[.originalImage] as? UIImage {
52 | //parent.image = uiImage
53 |
54 | parent.shapes.shapeList.forEach
55 | {
56 | if $0.isSelected == true {
57 | if $0 is ImageX
58 | {
59 | let selectedImage = $0 as! ImageX
60 | selectedImage.image = uiImage
61 | //selectedImage.width
62 | }
63 |
64 | }
65 | }
66 |
67 | }
68 |
69 | parent.presentationMode.wrappedValue.dismiss()
70 | }
71 |
72 | }
73 |
74 | func makeUIViewController(context: Context) -> UIImagePickerController {
75 | let picker = UIImagePickerController()
76 |
77 | picker.mediaTypes = ["public.image"]
78 | picker.delegate = context.coordinator
79 | return picker
80 |
81 | }
82 |
83 |
84 | func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
85 | }
86 |
87 | func makeCoordinator() -> Coordinator {
88 | Coordinator(self)
89 | }
90 |
91 | typealias UIViewControllerType = UIImagePickerController
92 | }
93 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/ImagePropertiesViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShapePropertiesX.swift
3 | //
4 | //
5 | // Created by on 25/3/22.
6 | //
7 |
8 |
9 | import SwiftUI
10 |
11 | struct ImagePropertiesViewX: View {
12 |
13 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
14 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
15 | @EnvironmentObject var optionSettings: OptionSettings
16 | @EnvironmentObject var shapes: ShapesX
17 | @StateObject var imagePropertiesViewModel: ImagePropertiesViewModel
18 | var body: some View {
19 |
20 |
21 | NavigationView {
22 | Form {
23 |
24 | DimensionsPropertiesViewX(objectPropertiesViewModel: imagePropertiesViewModel)
25 |
26 | }
27 | .navigationTitle("Image")
28 | //.navigationBarTitleDisplayMode(.inline)
29 | .toolbar {
30 |
31 | }
32 | }
33 | .navigationViewStyle(.stack)
34 | .frame(height:horizontalSizeClass == .regular && verticalSizeClass == .regular ? 400 : 290)
35 | .onAppear(perform: setupViewModel)
36 | .padding(.bottom, horizontalSizeClass == .regular && verticalSizeClass == .regular ? 70 : 0)
37 |
38 | }
39 |
40 | func setupViewModel()
41 | {
42 | imagePropertiesViewModel.setupSelectedProperties()
43 |
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/LabelDesignViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelDesignView.swift
3 | //
4 | //
5 | // Created by on 16/3/22.
6 | //
7 |
8 | import SwiftUI
9 | @available(macOS 12.0, *)
10 | @available(iOS 15.0, *)
11 | struct LabelDesignViewX: View {
12 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
13 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
14 |
15 | @State private var offsetX = CGFloat.zero
16 | @State private var offsetY = CGFloat.zero
17 |
18 | @EnvironmentObject var appSettings: AppSettings
19 | @EnvironmentObject var optionSettings: OptionSettings
20 | @EnvironmentObject var pageSettings: PageSettings
21 | @EnvironmentObject var shapes: ShapesX
22 |
23 |
24 | var body: some View {
25 |
26 | GeometryReader { geometry in
27 | VStack(spacing:0){
28 |
29 | RulerHViewX(offsetX: $offsetX, rulerWidth: geometry.size.width)
30 | //.frame(width: geometry.size.width, height: 0.37*72.0, alignment: .topLeading)
31 | .frame(width: geometry.size.width, height: horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.4*72.0 : 0.38*72.0, alignment: .topLeading)
32 | .border(Color.gray)
33 | .padding(0)
34 | HStack(spacing:0)
35 | {
36 | RulerVViewX(offsetY: $offsetY, rulerHeight: geometry.size.height)
37 | //.frame(width: 0.35*72.0, height: geometry.size.height, alignment: .leading)
38 | .frame(width: horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.4*72.0 : 0.38*72.0, height: geometry.size.height, alignment: .leading)
39 | .border(Color.gray)
40 | .padding(0)
41 | VStack(spacing:0){
42 | ScrollView([.horizontal, .vertical]) {
43 |
44 | VStack {
45 | LabelViewX()
46 | .frame(width: pageSettings.labelWidth*appSettings.dpi, height: pageSettings.labelHeight*appSettings.dpi, alignment: .center)
47 | .scaleEffect(appSettings.zoomFactor)
48 | }
49 | .frame(width: pageSettings.labelWidth*appSettings.dpi*appSettings.zoomFactor, height: pageSettings.labelHeight*appSettings.dpi*appSettings.zoomFactor, alignment: .center)
50 | .background(Color.white)
51 | .background(GeometryReader {
52 | Color.clear.preference(key: ViewOffsetKeyY.self,
53 | value: $0.frame(in: .named("scroll")).origin.y)
54 | Color.clear.preference(key: ViewOffsetKeyX.self,
55 | value: $0.frame(in: .named("scroll")).origin.x)
56 | })
57 | .onPreferenceChange(ViewOffsetKeyY.self) { newValue in
58 |
59 | let rulerThickness = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.4*72.0 : 0.38*72.0
60 | let labelHeight = pageSettings.labelHeight*appSettings.dpi*appSettings.zoomFactor
61 | let availableHeight = geometry.size.height - rulerThickness
62 | if offsetY != 0.0 ||
63 | appSettings.zoomingOrScrollY == "scroll" ||
64 | appSettings.zoomingOrScrollY == "zoomIn" ||
65 | (appSettings.zoomingOrScrollY == "zoomOut" &&
66 | offsetY == 0.0 &&
67 | labelHeight <= availableHeight)
68 | {
69 |
70 | offsetY=newValue//$0
71 | print("assigned new valueY")
72 |
73 | }
74 | appSettings.zoomingOrScrollY = "scroll"
75 |
76 | //}
77 | }
78 | .onPreferenceChange(ViewOffsetKeyX.self) { newValue in
79 |
80 | let rulerThickness = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.4*72.0 : 0.38*72.0
81 | let labelWidth = pageSettings.labelWidth*appSettings.dpi*appSettings.zoomFactor
82 | let availableWidth = geometry.size.width - rulerThickness
83 |
84 | if offsetX != 0.0 ||
85 | appSettings.zoomingOrScrollX == "scroll" ||
86 | appSettings.zoomingOrScrollX == "zoomIn" ||
87 | (appSettings.zoomingOrScrollX == "zoomOut" &&
88 | offsetX == 0.0 &&
89 | labelWidth <= availableWidth)
90 | {
91 | offsetX=newValue//$0
92 | print("assigned new valueX")
93 | }
94 | appSettings.zoomingOrScrollX = "scroll"
95 |
96 | //}
97 | }
98 |
99 |
100 | }
101 | .coordinateSpace(name: "scroll")
102 | .background(Color.gray)
103 | .onTapGesture {
104 | shapes.shapeList.forEach
105 | {
106 | $0.isSelected = false
107 | }
108 |
109 | optionSettings.showPropertiesView=0
110 | }
111 |
112 | }
113 | .frame(height: geometry.size.height, alignment: .leading)
114 |
115 |
116 | }.padding(0)
117 | }
118 | }
119 | }
120 | }
121 |
122 | struct ViewOffsetKeyY: PreferenceKey {
123 | typealias Value = CGFloat
124 | static var defaultValue = CGFloat.zero
125 | static func reduce(value: inout Value, nextValue: () -> Value) {
126 | value += nextValue()
127 | }
128 | }
129 |
130 | struct ViewOffsetKeyX: PreferenceKey {
131 | typealias Value = CGFloat
132 | static var defaultValue = CGFloat.zero
133 | static func reduce(value: inout Value, nextValue: () -> Value) {
134 | value += nextValue()
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/LabelMainViewX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 | import SwiftUI
11 | import CoreImage
12 | import CoreImage.CIFilterBuiltins
13 | import UniformTypeIdentifiers
14 |
15 | @available(iOS 15.0, *)
16 |
17 |
18 | struct LabelMainViewX: View {
19 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
20 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
21 | @EnvironmentObject var optionSettings: OptionSettings
22 | @EnvironmentObject var appSettings: AppSettings
23 | @EnvironmentObject var pageSettings: PageSettings
24 | @EnvironmentObject var shapes: ShapesX
25 |
26 | //https://stackoverflow.com/questions/57577462/get-width-of-a-view-using-in-swiftui
27 | //https://developer.apple.com/forums/thread/123012
28 |
29 | private func binding(for shape: ShapeX) -> Binding {
30 | guard let scrumIndex = shapes.shapeList.firstIndex(where: { $0.id == shape.id }) else {
31 | fatalError("Can't find scrum in array")
32 | }
33 | return $shapes.shapeList[scrumIndex]
34 | }
35 |
36 | var body: some View {
37 | NavigationView {
38 | VStack {
39 | LabelDesignViewX()
40 | .environmentObject(optionSettings)
41 | .environmentObject(pageSettings)
42 | .environmentObject(appSettings)
43 | .environmentObject(shapes)
44 | MainPropertiesViewX()
45 | .environmentObject(optionSettings)
46 | .environmentObject(pageSettings)
47 | .environmentObject(appSettings)
48 | .environmentObject(shapes)
49 | }
50 | .navigationTitle("Barcode & Label")
51 | .navigationBarTitleDisplayMode(.inline)
52 | .toolbar {
53 | ToolbarItemGroup(placement: .navigationBarLeading) {
54 | PageToolbarViewX()
55 | }
56 | ToolbarItemGroup(placement: .navigationBarTrailing) {
57 | OptionsPrintToolbarViewX()
58 | }
59 | }
60 | .ignoresSafeArea(.container, edges: [.bottom])
61 | } //navigationview
62 | .navigationViewStyle(StackNavigationViewStyle())
63 | .onAppear(perform: initAll)
64 | .alert(isPresented: $optionSettings.showingAlertMessage) {
65 | Alert(title: Text("Status"), message: Text(optionSettings.alertMessage!), dismissButton: .default(Text("OK")))
66 | }
67 | .sheet(isPresented: $optionSettings.showPropertiesSheet, onDismiss: dismissSheet) {
68 |
69 | MainSheetViewX()
70 | .environmentObject(appSettings)
71 | .environmentObject(optionSettings)
72 | .environmentObject(pageSettings)
73 | .environmentObject(shapes)
74 |
75 |
76 | } //sheet
77 | .textFieldAlert(isPresented: $optionSettings.showAlert) { () -> TextFieldAlert in
78 | TextFieldAlert(title: "Saving Label",
79 | message: "Please specify label name.",
80 | labelContent:optionSettings.jsonLabelStringForSave,
81 | text: $optionSettings.enteredSaveFileName,
82 | saveSuccess: $optionSettings.showingAlertMessage,
83 | existingLabelExist: $optionSettings.existingLabelExist,
84 | alertMessage: $optionSettings.alertMessage)
85 | }
86 | .fileImporter(
87 | isPresented: $optionSettings.isImporting,
88 | allowedContentTypes: [UTType.json],
89 | allowsMultipleSelection: false
90 | ) { result in
91 | do {
92 | guard let selectedFile: URL = try result.get().first else { return }
93 | guard selectedFile.startAccessingSecurityScopedResource() else { return }
94 | guard let message = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
95 | let labelAction = LabelAction(shapes: shapes, pageSettings: pageSettings)
96 | labelAction.load(jsonLabelStr: message)
97 | optionSettings.showAlert = false
98 | optionSettings.showPropertiesSheet = false
99 | appSettings.zoomFactor = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.5 : 0.28
100 |
101 | selectedFile.stopAccessingSecurityScopedResource()
102 | optionSettings.showingAlertMessage = true
103 | optionSettings.alertMessage="Label imported successfully."
104 | //import and open appSettings.dpi use the pageSttings one which is the onve saved
105 | appSettings.dpi=pageSettings.dpi
106 |
107 | } catch {
108 | print(error.localizedDescription)
109 | optionSettings.showingAlertMessage = true
110 | optionSettings.alertMessage="An error has occured while importing label - Invalid Label File."
111 | }
112 | }
113 | .fileExporter(
114 | isPresented: $optionSettings.isExporting,
115 | document: optionSettings.labelDocument,
116 | contentType: UTType.json,
117 | defaultFilename: "Label"
118 | ) { result in
119 | optionSettings.showingAlertMessage = true
120 | if case .success = result {
121 | optionSettings.alertMessage="Label exported successfully."
122 | print("Success!")
123 | } else {
124 | optionSettings.alertMessage="An error has occured while exporting label. Please try again or contact us."
125 | print("Something went wrong…")
126 | }
127 | }
128 |
129 | } //body
130 |
131 |
132 | func dismissSheet()
133 | {
134 | optionSettings.action = "Design"
135 | }
136 |
137 | func initLabel() {
138 | shapes.shapeList=[ShapeX]()
139 | }
140 |
141 | func initPage() {
142 | print("initPage:",labelTemplatesAll.count)
143 |
144 | //new and startup will use appSettings dpi
145 | pageSettings.dpi=appSettings.dpi
146 |
147 | pageSettings.name = labelTemplates[8][0]
148 | pageSettings.category = labelTemplates[8][1]
149 | pageSettings.vendor = labelTemplates[8][2]
150 | pageSettings.description = labelTemplates[8][3]
151 | pageSettings.type = labelTemplates[8][4]
152 | pageSettings.pageWidth = Double(labelTemplates[8][5]) ?? 1.0
153 | pageSettings.pageHeight = Double(labelTemplates[8][6]) ?? 1.0
154 | pageSettings.labelWidth = Double(labelTemplates[8][7]) ?? 1.0
155 | pageSettings.labelHeight = Double(labelTemplates[8][8]) ?? 1.0
156 | pageSettings.hSpace = Double(labelTemplates[8][9]) ?? 0.0
157 | pageSettings.vSpace = Double(labelTemplates[8][10]) ?? 0.0
158 | pageSettings.numRows = Int(labelTemplates[8][11]) ?? 1
159 | pageSettings.numCols = Int(labelTemplates[8][12]) ?? 1
160 | pageSettings.leftMargin = Double(labelTemplates[8][13]) ?? 0.0
161 | pageSettings.topMargin = Double(labelTemplates[8][14]) ?? 0.0
162 | pageSettings.generateLabels()
163 |
164 | let defaults = UserDefaults.standard
165 | if let unitstring = defaults.string(forKey: "units"), !unitstring.isEmpty {
166 | print("Getting:",unitstring)
167 | appSettings.units = unitstring
168 | }
169 | else{
170 | print("Setting:",appSettings.units)
171 | defaults.set(appSettings.units, forKey: "units")
172 | }
173 |
174 |
175 | }
176 | func convertStringToDictionary(text: String) -> [String:AnyObject]? {
177 | if let data = text.data(using: .utf8) {
178 | do {
179 | let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]
180 | return json
181 | } catch {
182 | print("Something went wrong")
183 | }
184 | }
185 | return nil
186 | }
187 |
188 | func initAll()
189 | {
190 | initLabel()
191 | initPage()
192 |
193 |
194 | //let timer2 =
195 | Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { timer in
196 | print("Timer fired!")
197 | appSettings.zoomFactor = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.5 : 0.28
198 | print(appSettings.zoomFactor)
199 | }
200 |
201 | }
202 | }
203 |
204 |
205 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/LabelViewX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 |
13 | struct LabelViewX: View {
14 |
15 |
16 | @EnvironmentObject var optionSettings: OptionSettings
17 | @EnvironmentObject var appSettings: AppSettings
18 | @EnvironmentObject var pageSettings: PageSettings
19 | @EnvironmentObject var shapes: ShapesX
20 |
21 | var body: some View {
22 |
23 | ZStack {
24 |
25 | ForEach(shapes.shapeList){
26 | shape in
27 | ShapeViewX(shape: shape, showPropertiesView: $optionSettings.showPropertiesView)
28 | }
29 |
30 | }
31 | .background(Color.white)
32 | .onTapGesture {
33 | shapes.shapeList.forEach
34 | {
35 | if ($0.isSelected == true)
36 | {
37 | print("set false")
38 | $0.isSelected = false
39 | }
40 | }
41 | optionSettings.showPropertiesView = 0
42 | }
43 | .clipShape(Rectangle())
44 | //.gesture(pressGesture)
45 |
46 | }
47 |
48 |
49 | }
50 |
51 | //https://stackoverflow.com/questions/70032739/why-does-swiftui-uihostingcontroller-have-extra-spacing
52 | extension UIHostingController {
53 | convenience public init(rootView: Content, ignoreSafeArea: Bool) {
54 | self.init(rootView: rootView)
55 |
56 | if ignoreSafeArea {
57 | disableSafeArea()
58 | }
59 | }
60 |
61 | func disableSafeArea() {
62 | guard let viewClass = object_getClass(view) else { return }
63 |
64 | let viewSubclassName = String(cString: class_getName(viewClass)).appending("_IgnoreSafeArea")
65 | if let viewSubclass = NSClassFromString(viewSubclassName) {
66 | object_setClass(view, viewSubclass)
67 | }
68 | else {
69 | guard let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String else { return }
70 | guard let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0) else { return }
71 |
72 | if let method = class_getInstanceMethod(UIView.self, #selector(getter: UIView.safeAreaInsets)) {
73 | let safeAreaInsets: @convention(block) (AnyObject) -> UIEdgeInsets = { _ in
74 | return .zero
75 | }
76 | class_addMethod(viewSubclass, #selector(getter: UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets), method_getTypeEncoding(method))
77 | }
78 |
79 | objc_registerClassPair(viewSubclass)
80 | object_setClass(view, viewSubclass)
81 | }
82 | }
83 | }
84 |
85 | extension CGSize {
86 | static func * (size: CGSize, value: CGFloat) -> CGSize {
87 | return CGSize(width: size.width * value, height: size.height * value)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/MainPropertiesViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainSheetViewX.swift
3 | //
4 | //
5 | // Created by on 21/4/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @available(iOS 15.0, *)
11 | struct MainPropertiesViewX: View {
12 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
13 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
14 |
15 | @EnvironmentObject var optionSettings: OptionSettings
16 | @EnvironmentObject var appSettings: AppSettings
17 | @EnvironmentObject var pageSettings: PageSettings
18 | @EnvironmentObject var shapes: ShapesX
19 |
20 | var body: some View {
21 | VStack{
22 |
23 | if optionSettings.showPropertiesView == 2
24 | {
25 | ForEach(shapes.shapeList){
26 | shape in
27 | if shape.isSelected == true && shape is TextX
28 | {
29 | TextPropertiesViewX(textPropertiesViewModel: TextPropertiesViewModel(shapes: shapes))
30 | }
31 | }
32 | }
33 | else if optionSettings.showPropertiesView == 3
34 | {
35 | ForEach(shapes.shapeList){
36 | shape in
37 | if shape.isSelected == true && (shape is RectangleX || shape is EllipseX)
38 | {
39 | ShapePropertiesViewX(shapePropertiesViewModel: ShapePropertiesViewModel(shapes: shapes))
40 | }
41 | }
42 | }
43 | else if optionSettings.showPropertiesView == 5
44 | {
45 | ForEach(shapes.shapeList){
46 | shape in
47 | if shape.isSelected == true && shape is BarcodeX
48 | {
49 | BarcodePropertiesViewX(barcodePropertiesViewModel: BarcodePropertiesViewModel(shapes: shapes))
50 | }
51 | }
52 | }
53 | else if optionSettings.showPropertiesView == 6
54 | {
55 | ForEach(shapes.shapeList){
56 | shape in
57 | if shape.isSelected == true && shape is ImageX
58 | {
59 | ImagePropertiesViewX(imagePropertiesViewModel: ImagePropertiesViewModel(shapes: shapes))
60 | }
61 | }
62 | }
63 | else
64 | {
65 | VStack (alignment: .trailing)
66 | {
67 | HStack{
68 | LabelToolbarViewX()
69 | }.frame(height: horizontalSizeClass == .regular && verticalSizeClass == .regular ? 85 : 85)
70 |
71 | }.frame(height: horizontalSizeClass == .regular && verticalSizeClass == .regular ? 85 : 85)
72 | }
73 |
74 |
75 | //Spacer() //for toolbar push up
76 | }
77 | .frame(height: (optionSettings.showPropertiesView != 0 ? 280 :
78 | (horizontalSizeClass == .regular && verticalSizeClass == .regular ? 85 : 85))) //so as to extend beyond the bottomn toolbar
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/MainSheetViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainSheetViewX.swift
3 | //
4 | //
5 | // Created by on 21/4/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @available(iOS 15.0, *)
11 | struct MainSheetViewX: View {
12 | @EnvironmentObject var optionSettings: OptionSettings
13 | @EnvironmentObject var appSettings: AppSettings
14 | @EnvironmentObject var pageSettings: PageSettings
15 | @EnvironmentObject var shapes: ShapesX
16 |
17 | var body: some View {
18 | if optionSettings.action == "NewLabel"
19 | {
20 |
21 | TemplateViewX(templateViewModel: TemplateViewModel(units: appSettings.units, pageSettings: self.pageSettings))
22 | .environmentObject(appSettings)
23 | .environmentObject(optionSettings)
24 | .environmentObject(pageSettings)
25 | .environmentObject(shapes)
26 |
27 | }
28 | else if optionSettings.action == "OpenLabel"
29 | {
30 | FilesViewX(filesViewModel: FilesViewModel())
31 | .environmentObject(optionSettings)
32 | }
33 | else if optionSettings.action == "Preview"
34 | {
35 | PreviewViewX(previewViewModel: PreviewViewModel(dpi: appSettings.dpi,pageType: pageSettings.type))
36 | .environmentObject(appSettings)
37 | .environmentObject(optionSettings)
38 | .environmentObject(pageSettings)
39 | .environmentObject(appSettings)
40 | .environmentObject(shapes)
41 | }
42 | else if optionSettings.action == "NewImage" || optionSettings.action == "EditImage" {
43 |
44 | ImagePickerX()
45 | .environmentObject(optionSettings)
46 | .environmentObject(shapes)
47 | }
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/OptionsPrintToolbarViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LaeblToolbarView.swift
3 | //
4 | //
5 | // Created by on 17/3/22.
6 | //
7 |
8 | import SwiftUI
9 | @available(iOS 15.0, *)
10 | struct OptionsPrintToolbarViewX: View {
11 | @Environment(\.colorScheme) var colorScheme
12 | @EnvironmentObject var appSettings: AppSettings
13 | @EnvironmentObject var optionSettings: OptionSettings
14 | @EnvironmentObject var pageSettings: PageSettings
15 | @EnvironmentObject var shapes: ShapesX
16 | @State private var showingAlert = false
17 |
18 | @State var measurementUnit : String = "Inches"
19 |
20 | var body: some View {
21 |
22 | Button(action: {
23 |
24 | shapes.deSelectAll();
25 |
26 | optionSettings.action = "Preview"
27 | //come back and change the name to showSheet
28 | optionSettings.showPropertiesSheet = true
29 |
30 | }, label: {
31 | Label("Print", systemImage: "printer")
32 | //.font(.system(size: 16))
33 | }).foregroundColor(.black)
34 |
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/PageToolbarViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LaeblToolbarView.swift
3 | //
4 | //
5 | // Created by on 17/3/22.
6 | //
7 |
8 | import SwiftUI
9 | import MobileCoreServices
10 | @available(iOS 15.0, *)
11 |
12 | @available(iOS 15.0, *)
13 | struct PageToolbarViewX: View {
14 | @Environment(\.colorScheme) var colorScheme
15 | @EnvironmentObject var appSettings: AppSettings
16 | @EnvironmentObject var optionSettings: OptionSettings
17 | @EnvironmentObject var pageSettings: PageSettings
18 | @EnvironmentObject var shapes: ShapesX
19 | @State private var showingAlert = false
20 |
21 | @State var measurementUnit : String = "Inches"
22 |
23 |
24 |
25 | var body: some View {
26 |
27 | Menu {
28 |
29 | Button(action: {
30 |
31 | shapes.deSelectAll();
32 |
33 | }, label: {
34 | Label("Labels", systemImage: "folder")
35 |
36 |
37 | })
38 | .contextMenu {
39 | Button(action: {
40 | shapes.deSelectAll();
41 | optionSettings.action = "NewLabel"
42 |
43 | optionSettings.showPropertiesSheet = true
44 |
45 |
46 |
47 | }) {
48 | Label("New", systemImage: "doc.badge.plus")
49 | }
50 |
51 | Button(action: {
52 | shapes.deSelectAll();
53 | optionSettings.action = "OpenLabel"
54 | /*
55 | pageSettings.dpi=72.0
56 | //pageSettings.generateLabels()
57 | */
58 | optionSettings.showPropertiesSheet = true
59 |
60 |
61 | }) {
62 | //Label("Open Label", systemImage: "doc.badge.gearshape")
63 | Label("My Labels", systemImage: "arrow.up.doc")
64 | }
65 |
66 |
67 |
68 | Button(action: {
69 | shapes.deSelectAll();
70 | optionSettings.action = "SaveLabel"
71 |
72 | let labelAction = LabelAction(shapes: shapes, pageSettings: pageSettings)
73 | optionSettings.jsonLabelStringForSave = labelAction.generate()
74 | optionSettings.showAlert = true
75 |
76 |
77 | }) {
78 | Label("Save", systemImage: "arrow.down.doc")
79 | }
80 |
81 | Button(action: {
82 | print("importing")
83 | shapes.deSelectAll();
84 | optionSettings.action = "Import"
85 | optionSettings.isImporting = true
86 | }) {
87 | Label("Import", systemImage: "square.and.arrow.down")
88 | }
89 |
90 | Button(action: {
91 | print("exporting")
92 |
93 | let labelAction = LabelAction(shapes: shapes, pageSettings: pageSettings)
94 | optionSettings.labelDocument.message = labelAction.generate()
95 |
96 |
97 | optionSettings.action = "Export"
98 | optionSettings.isExporting = true
99 | }) {
100 | Label("Export", systemImage: "square.and.arrow.up")
101 | }
102 |
103 |
104 | }
105 |
106 | Button(action: {
107 |
108 | shapes.deSelectAll();
109 |
110 | }, label: {
111 | Label("Options", systemImage: "doc.badge.gearshape")
112 |
113 |
114 | })
115 | .contextMenu {
116 |
117 | Menu("Measurements") {
118 | Picker("Units", selection: $appSettings.units) {
119 | ForEach(measurementUnits, id: \.self) {
120 | Text($0)
121 | }
122 | }
123 | .onChange(of: appSettings.units) { newValue in
124 | let defaults = UserDefaults.standard
125 | print("Setting:",appSettings.units)
126 | defaults.set(appSettings.units, forKey: "units")
127 |
128 | }
129 | }
130 |
131 | Menu("Help") {
132 | Link("Help", destination: URL(string: "https://www.barcoderesource.com/barcodelabelappleapp.shtml")!)
133 | .font(.title)
134 | //.foregroundColor(.red)
135 | Link("Open Source", destination: URL(string: "https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml")!)
136 | .font(.title)
137 | //.foregroundColor(.red)
138 | }
139 |
140 | }
141 |
142 |
143 |
144 |
145 | }
146 | label: {
147 | VStack {
148 |
149 | Image(systemName: "doc")
150 | .foregroundColor(colorScheme == .dark ? Color(UIColor(red: 0.9569, green: 0.9569, blue: 0.9569, alpha: 0.5) ) : Color.black)
151 | }
152 | }
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/RulerHViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RulerH.swift
3 | //
4 | //
5 | // Created by on 15/3/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @available(macOS 12.0, *)
11 | @available(iOS 15.0, *)
12 | struct RulerHViewX: View {
13 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
14 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
15 |
16 | @Binding var offsetX: CGFloat
17 | var rulerWidth: CGFloat
18 | @Environment(\.colorScheme) var colorScheme
19 | @EnvironmentObject var appSettings: AppSettings
20 | @EnvironmentObject var pageSettings: PageSettings
21 | var body: some View {
22 | Canvas { context, size in
23 |
24 | var dpi = 72.0*appSettings.dpiScale
25 | if appSettings.units != "Inches"
26 | {
27 | dpi = dpi / 2.54
28 | }
29 | //let widthx = 2.625*72.0*appSettings.dpiScale*appSettings.zoomFactor
30 | let widthx = pageSettings.labelWidth*72.0*appSettings.dpiScale*appSettings.zoomFactor
31 |
32 | //let thickness = 0.37*72.0
33 | let thickness = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.4*72.0 : 0.38*72.0
34 |
35 | let spacingx = 0.1*dpi*appSettings.zoomFactor
36 | let countx = widthx / spacingx
37 | let bottomy = thickness
38 | let heightSmallTicks = 0.1*72.0
39 |
40 | let spacingxBig = 1.0*dpi*appSettings.zoomFactor
41 | let countxBig = widthx / spacingxBig
42 | let bottomyBig = thickness
43 | let heightSmallTicksBig = 0.2*72.0
44 |
45 | let spacingxMed = 1.0*dpi*appSettings.zoomFactor
46 | let countxMed = widthx / spacingxMed
47 | let bottomyMed = thickness
48 | let heightSmallTicksMed = 0.15*72.0
49 |
50 |
51 |
52 | var currentx = 0.0
53 |
54 | var countzero = (offsetX + thickness) / spacingx
55 | //var darkColor: UIColor = UIColor.black
56 | let path = CGMutablePath()
57 | let xpath = CGMutablePath()
58 | currentx = offsetX + thickness
59 | countzero = countzero < 0.0 ? 0.0 : countzero
60 | for _ in 0...Int(countzero)
61 | {
62 | if (spacingx > 2.0) //prevent too small space between small ticks in centimeters
63 | {
64 | if currentx > 0.0
65 | {
66 | xpath.move(to: CGPoint(x: currentx, y: bottomy))
67 | xpath.addLine(to: CGPoint(x: currentx, y: bottomy-heightSmallTicks))
68 | currentx -= spacingx
69 | }
70 | }
71 | }
72 |
73 | let storecurrentx = currentx
74 |
75 | currentx = offsetX + thickness
76 |
77 | for _ in 0...Int(countx)
78 | {
79 | if (spacingx > 2.0) //prevent too small space between small ticks in centimeters
80 | {
81 | path.move(to: CGPoint(x: currentx, y: bottomy))
82 | path.addLine(to: CGPoint(x: currentx, y: bottomy-heightSmallTicks))
83 | currentx += spacingx
84 | }
85 | }
86 |
87 | currentx = offsetX + thickness + 0.0*dpi*appSettings.zoomFactor
88 |
89 |
90 | for tx in 0...Int(countxBig)+1
91 | {
92 |
93 | let textPoint = CGPoint(x: currentx, y: bottomyBig-heightSmallTicksBig-3)
94 | let text = Text(String(tx)).font(.system(size: 11))
95 | context.draw(text, at: textPoint, anchor: .center)
96 |
97 | path.move(to: CGPoint(x: currentx, y: bottomyBig))
98 | path.addLine(to: CGPoint(x: currentx, y: bottomyBig-heightSmallTicksBig+3))
99 | currentx += spacingxBig
100 | }
101 |
102 | currentx = offsetX + thickness + 0.5*dpi*appSettings.zoomFactor
103 | for _ in 0...Int(countxMed)
104 | {
105 | path.move(to: CGPoint(x: currentx, y: bottomyMed))
106 | path.addLine(to: CGPoint(x: currentx, y: bottomyBig-heightSmallTicksMed))
107 | currentx += spacingxMed
108 | }
109 |
110 | context.stroke(
111 | Path(path),
112 | with: .color(.black),
113 | lineWidth: 1)
114 |
115 | currentx = storecurrentx
116 | var countend = (rulerWidth - currentx) / spacingx
117 | countend = countend < 0.0 ? 0.0 : countend
118 |
119 | for _ in 0...Int(countend)
120 | {
121 | if (spacingx > 2.0) //prevent too small space between small ticks in centimeters
122 | {
123 |
124 | xpath.move(to: CGPoint(x: currentx, y: bottomy))
125 | xpath.addLine(to: CGPoint(x: currentx, y: bottomy-heightSmallTicks))
126 | currentx += spacingx
127 | }
128 | }
129 | context.stroke(
130 | Path(xpath),
131 | with: .color(.black),
132 | lineWidth: 1.0)
133 |
134 | }.background(colorScheme == .dark ? Color(UIColor.lightGray) : Color.white)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/RulerVViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RulerVView.swift
3 | //
4 | //
5 | // Created by on 15/3/22.
6 | //
7 |
8 | import SwiftUI
9 | @available(iOS 15.0, *)
10 | struct RulerVViewX: View {
11 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
12 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
13 |
14 | @Binding var offsetY: CGFloat
15 | var rulerHeight: CGFloat
16 | @Environment(\.colorScheme) var colorScheme
17 | @EnvironmentObject var appSettings: AppSettings
18 | @EnvironmentObject var pageSettings: PageSettings
19 | var body: some View {
20 | Canvas { context, size in
21 |
22 | var dpi = 72.0*appSettings.dpiScale
23 | if appSettings.units != "Inches"
24 | {
25 | dpi = dpi / 2.54
26 | }
27 | //let heighty = 1.0*72.0*appSettings.dpiScale*appSettings.zoomFactor
28 | let heighty = pageSettings.labelHeight*72.0*appSettings.dpiScale*appSettings.zoomFactor
29 | //let thickness = 0.35*72.0
30 | let thickness = horizontalSizeClass == .regular && verticalSizeClass == .regular ? 0.4*72.0 : 0.38*72.0
31 | //let heighty = 11*72.0
32 | let spacingy = 0.1*dpi*appSettings.zoomFactor
33 | let countx = heighty / spacingy
34 | //let rightx = thickness
35 | let heightSmallTicks = 0.1*72.0
36 |
37 |
38 | let spacingyBig = 1.0*dpi*appSettings.zoomFactor
39 | let countxBig = heighty / spacingyBig
40 | //print("countxBig:",countxBig,":",heighty,":",spacingyBig)
41 | //let rightxBig = thickness
42 | let heightBigTicks = 0.2*72.0
43 |
44 | let spacingyMed = 1.0*dpi*appSettings.zoomFactor
45 | let countxMed = heighty / spacingyMed
46 | //let rightxMed = thickness
47 | let heightMedTicks = 0.155*72.0
48 |
49 | //let pixelAdjust = 1.0
50 | //let stackSpaceAdjust = 2.0
51 |
52 |
53 | var countzero = offsetY / spacingy
54 | let xpath = CGMutablePath()
55 |
56 | countzero = countzero < 0.0 ? 0.0 : countzero
57 | var currenty = offsetY
58 | for _ in 0...Int(countzero)
59 | {
60 | if (spacingy > 2.0) //prevent too small space between small ticks in centimeters
61 | {
62 | if currenty > 0.0
63 | {
64 | xpath.move(to: CGPoint(x: thickness, y: currenty))
65 | xpath.addLine(to: CGPoint(x: thickness-heightSmallTicks , y: currenty))
66 | currenty -= spacingy
67 | }
68 | }
69 | }
70 |
71 |
72 | //var initialy = thickness + spacingy + stackSpaceAdjust + pixelAdjust //2 is the vstack spacing betwwen reular and displayview
73 | //var initialy = offsetY + 0.155*72.0 //+ thickness
74 | var initialy = offsetY
75 | //1 is a little adjustment
76 | currenty = initialy
77 | //var darkColor: UIColor = UIColor.black
78 | let path = CGMutablePath()
79 |
80 | for _ in 1...Int(countx)
81 | {
82 | if (spacingy > 2.0) //prevent too small space between small ticks in centimeters
83 | {
84 | path.move(to: CGPoint(x: thickness, y: currenty))
85 | path.addLine(to: CGPoint(x: thickness-heightSmallTicks , y: currenty))
86 | currenty += spacingy
87 | }
88 | }
89 | let storecurrenty=currenty
90 |
91 | //initialy = thickness + stackSpaceAdjust + pixelAdjust
92 | //initialy = offsetY + 0.155*72.0 //+ thickness
93 | initialy = offsetY
94 | currenty = initialy
95 |
96 | print("thickness:",thickness)
97 | print("offsetY:",offsetY)
98 | print("currenty:",currenty)
99 |
100 | for ty in 0...Int(countxBig)+1
101 | {
102 |
103 | let textPoint = CGPoint(x: thickness-heightBigTicks-6, y: currenty)
104 | let text = Text(String(ty)).font(.system(size: 11))
105 | context.draw(text, at: textPoint, anchor: .center)
106 |
107 | path.move(to: CGPoint(x: thickness, y: currenty))
108 | path.addLine(to: CGPoint(x: thickness-heightBigTicks , y: currenty))
109 | currenty += spacingyBig
110 | }
111 |
112 | let initialOffsetDueToRulerH = 0.5*dpi*appSettings.zoomFactor
113 |
114 |
115 | initialy = offsetY + initialOffsetDueToRulerH
116 |
117 | currenty = initialy
118 |
119 | for _ in 0...Int(countxMed)
120 | {
121 | path.move(to: CGPoint(x: thickness, y: currenty))
122 | path.addLine(to: CGPoint(x: thickness-heightMedTicks , y: currenty))
123 | currenty += spacingyMed
124 | }
125 |
126 | context.stroke(
127 | Path(path),
128 | with: .color(.black),
129 | lineWidth: 1)
130 |
131 | currenty = storecurrenty
132 | var countend = (rulerHeight - currenty) / spacingy
133 | //countend = countend < 0.0 ? 0.0 : countend
134 | countend = countend < 1.0 ? 1.0 : countend
135 | for _ in 1...Int(countend)
136 | {
137 | if (spacingy > 2.0) //prevent too small space between small ticks in centimeters
138 | {
139 | xpath.move(to: CGPoint(x: thickness, y: currenty))
140 | xpath.addLine(to: CGPoint(x: thickness-heightSmallTicks , y: currenty))
141 | currenty += spacingy
142 | }
143 | }
144 |
145 | context.stroke(
146 | Path(xpath),
147 | with: .color(.black),
148 | lineWidth: 1.0)
149 | }.background(colorScheme == .dark ? Color(UIColor.lightGray) : Color.white)
150 | }
151 | }
152 |
153 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/ShapePropertiesViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShapePropertiesX.swift
3 | //
4 | //
5 | // Created by on 25/3/22.
6 | //
7 |
8 |
9 | import SwiftUI
10 |
11 | struct ShapePropertiesViewX: View {
12 |
13 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
14 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
15 | @EnvironmentObject var optionSettings: OptionSettings
16 | @EnvironmentObject var shapes: ShapesX
17 | @StateObject var shapePropertiesViewModel: ShapePropertiesViewModel
18 | var body: some View {
19 |
20 |
21 | NavigationView {
22 | Form {
23 |
24 |
25 | Section(header: Text("Stroke")){
26 |
27 | HStack() {
28 | Text("Width")
29 | Spacer()
30 | Text(String(format: "%.0f", round(Double(shapePropertiesViewModel.strokeWidth * 72.0/300.0)+1)))
31 | //Text("\(Double(shapePropertiesViewModel.strokeWidth * 72.0/300.0))")
32 | }
33 | Slider(value: $shapePropertiesViewModel.strokeWidth, in: 0.2*300.0/72.0...29*300.0/72.0)
34 | .onChange(of: shapePropertiesViewModel.strokeWidth) { newValue in
35 | //print("sw changed to \(sw)!")
36 | //print("change")
37 | //print(newValue)
38 | shapes.shapeList.forEach
39 | {
40 | if $0.isSelected == true {
41 | if $0 is RectangleX
42 | {
43 | let selectedRect = $0 as! RectangleX
44 | selectedRect.strokeWidth=newValue
45 | }
46 | else if $0 is EllipseX
47 | {
48 | let selectedRect = $0 as! EllipseX
49 | selectedRect.strokeWidth=newValue
50 | }
51 | }
52 | }
53 | }
54 | HStack{
55 | Text("Color")
56 | Spacer()
57 | ColorPicker("", selection: $shapePropertiesViewModel.strokeColor, supportsOpacity: false)
58 | .onChange(of: shapePropertiesViewModel.strokeColor) { newValue in
59 |
60 | self.shapes.shapeList.forEach
61 | {
62 | if $0.isSelected == true {
63 | if $0 is RectangleX
64 | {
65 | let selectedRect = $0 as! RectangleX
66 | selectedRect.strokeColor = newValue
67 | }
68 | else if $0 is EllipseX
69 | {
70 | let selectedRect = $0 as! EllipseX
71 | selectedRect.strokeColor = newValue
72 | }
73 | }
74 | }
75 | }.frame(width:100, height:30, alignment: .trailing)
76 | }
77 |
78 | }
79 | Section(header: Text("Fill")){
80 |
81 | HStack{
82 | Text("Color")
83 | Spacer()
84 | ColorPicker("", selection: $shapePropertiesViewModel.fillColor, supportsOpacity: false)
85 | .onChange(of: shapePropertiesViewModel.fillColor) { newValue in
86 |
87 | self.shapes.shapeList.forEach
88 | {
89 | if $0.isSelected == true {
90 |
91 | if $0 is RectangleX
92 | {
93 | let selectedRect = $0 as! RectangleX
94 | selectedRect.fillColor = newValue
95 | }
96 | else if $0 is EllipseX
97 | {
98 | let selectedRect = $0 as! EllipseX
99 | selectedRect.fillColor = newValue
100 | }
101 | }
102 |
103 | }
104 | }.frame(width:100, height:30, alignment: .trailing)
105 | }
106 |
107 | }
108 |
109 | DimensionsPropertiesViewX(objectPropertiesViewModel: shapePropertiesViewModel)
110 |
111 |
112 | }
113 | .navigationTitle("Shape")
114 | //.navigationBarTitleDisplayMode(.inline)
115 | .toolbar {
116 |
117 | }
118 | }
119 | .navigationViewStyle(.stack)
120 | .frame(height:horizontalSizeClass == .regular && verticalSizeClass == .regular ? 400 : 290)
121 | .onAppear(perform: setupViewModel)
122 | .padding(.bottom, horizontalSizeClass == .regular && verticalSizeClass == .regular ? 70 : 0)
123 | }
124 |
125 | func setupViewModel()
126 | {
127 | shapePropertiesViewModel.setupSelectedProperties()
128 |
129 | }
130 | }
131 |
132 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/TemplateLabelViewX.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | import SwiftUI
12 |
13 | struct TemplateLabelViewX: View {
14 |
15 |
16 | var body: some View {
17 |
18 | ZStack {
19 |
20 |
21 | }
22 | .background(Color.white)
23 | .onTapGesture {
24 |
25 | }
26 |
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabel/Views/TextPropertiesViewX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextPropertiesView.swift
3 | // (iOS)
4 | //
5 | // Created by on 23/4/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct TextPropertiesViewX: View {
11 |
12 | @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
13 | @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
14 | @EnvironmentObject var optionSettings: OptionSettings
15 | @EnvironmentObject var shapes: ShapesX
16 | @StateObject var textPropertiesViewModel: TextPropertiesViewModel
17 | @State private var letter = ""
18 | private let letters = ["Alpha", "Bravo", "Charlie"]
19 |
20 | var body: some View {
21 |
22 | NavigationView {
23 | Form {
24 | Section(header: Text("Text")){
25 |
26 | HStack{
27 |
28 |
29 | TextField("Text", text: $textPropertiesViewModel.text)
30 | .onChange(of: textPropertiesViewModel.text) { newValue in
31 |
32 | self.shapes.shapeList.forEach
33 | {
34 | if $0.isSelected == true {
35 | let selectedText = $0 as! TextX
36 |
37 | if newValue.count > 200
38 | {
39 | selectedText.text = String(newValue.prefix(200))
40 | }
41 | else{
42 | selectedText.text = newValue
43 | }
44 |
45 | }
46 | }
47 | }
48 | //.padding(5).textFieldStyle(RoundedBorderTextFieldStyle())
49 | }
50 | }
51 |
52 | Section(header: Text("Font")){
53 |
54 | Picker("Name", selection: $textPropertiesViewModel.fontName) {
55 | ForEach(fontNames, id: \.self) {
56 | Text($0)
57 | }
58 | }
59 | .onChange(of: textPropertiesViewModel.fontName) { newValue in
60 | self.shapes.shapeList.forEach
61 | {
62 | if $0.isSelected == true {
63 | let selectedText = $0 as! TextX
64 | selectedText.fontName = newValue
65 | }
66 | }
67 | }
68 | HStack{
69 | Text("Color")
70 | Spacer()
71 | ColorPicker("", selection: $textPropertiesViewModel.textColor, supportsOpacity: false)
72 | .onChange(of: textPropertiesViewModel.textColor) { newValue in
73 |
74 | self.shapes.shapeList.forEach
75 | {
76 | if $0.isSelected == true {
77 | let selectedText = $0 as! TextX
78 | selectedText.textColor = newValue
79 | }
80 | }
81 | }.frame(width:100, height:30, alignment: .trailing)
82 | }
83 | HStack{
84 | Text("Size")
85 | Spacer()
86 |
87 |
88 | Text("\(Int(textPropertiesViewModel.fontSize * 72.0/300.0))")
89 |
90 | }
91 | Slider(value: $textPropertiesViewModel.fontSize, in: 10...600 )
92 | .onChange(of: textPropertiesViewModel.fontSize) { newValue in
93 | self.shapes.shapeList.forEach
94 | {
95 | if $0.isSelected == true {
96 | let selectedText = $0 as! TextX
97 | selectedText.fontSize = newValue
98 |
99 | }
100 | }
101 | }
102 | //Spacer()
103 | }
104 | Section(header: Text("Horizontal Text Alignment")){
105 | Picker("Text Alignment", selection: $textPropertiesViewModel.alignment) {
106 | Label("Left", systemImage: "align.horizontal.left")
107 | .labelStyle(.iconOnly)
108 | .tag("Left")
109 | Label("Center", systemImage: "align.horizontal.center")
110 | .labelStyle(.iconOnly)
111 | .tag("Center")
112 | Label("Right", systemImage: "align.horizontal.right")
113 | .labelStyle(.iconOnly)
114 | .tag("Right")
115 | }
116 | .pickerStyle(.segmented)
117 | .onChange(of: textPropertiesViewModel.alignment) { newValue in
118 | self.shapes.shapeList.forEach
119 | {
120 | if $0.isSelected == true {
121 | let selectedText = $0 as! TextX
122 | selectedText.horizontalTextAlignment = newValue
123 | }
124 | }
125 | }
126 | }
127 |
128 |
129 | DimensionsPropertiesViewX(objectPropertiesViewModel: textPropertiesViewModel)
130 |
131 |
132 | }
133 | .navigationTitle("Text")
134 | //.navigationBarTitleDisplayMode(.inline)
135 | .toolbar {
136 |
137 | }
138 | }
139 | .navigationViewStyle(.stack)
140 | .frame(height:horizontalSizeClass == .regular && verticalSizeClass == .regular ? 400 : 290)
141 | .onAppear(perform: setupViewModel)
142 | .padding(.bottom, horizontalSizeClass == .regular && verticalSizeClass == .regular ? 70 : 0)
143 |
144 | }
145 |
146 | func setupViewModel()
147 | {
148 | textPropertiesViewModel.setupSelectedProperties()
149 |
150 | }
151 |
152 | }
153 |
154 |
--------------------------------------------------------------------------------
/Shared/BarcodeLabelApp.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2022 barcoderesource.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | /*
12 | https://www.barcoderesource.com/barcodelabelappleapp.shtml
13 |
14 | https://www.barcoderesource.com/swiftui_view_vector_draw_wysiwyg.shtml
15 | */
16 |
17 | import SwiftUI
18 |
19 | @main
20 | @available(iOS 15.0, *)
21 | struct BarcodeLabelApp: App {
22 | var body: some Scene {
23 | WindowGroup {
24 | LabelMainViewX()
25 | .environmentObject(ShapesX())
26 | .environmentObject(AppSettings(300.0,0.28))
27 | .environmentObject(OptionSettings("Design"))
28 | .environmentObject(PageSettings())
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Shared/IMG_20200419_102525.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/IMG_20200419_102525.jpg
--------------------------------------------------------------------------------
/Shared/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Misfits-Rebels-Outcasts/SwiftUI-WYSIWYG-Draw/66d7dec9463e0fc8f74f59ed7dc950df30a9623c/Shared/test.jpg
--------------------------------------------------------------------------------
/Tests iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests iOS/Tests_iOS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Tests_iOS.swift
3 | // Tests iOS
4 | //
5 | // Created by on 27/01/2021.
6 | //
7 |
8 | import XCTest
9 |
10 | class Tests_iOS: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use recording to get started writing UI tests.
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Tests macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests macOS/Tests_macOS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Tests_macOS.swift
3 | // Tests macOS
4 | //
5 | // Created by on 27/01/2021.
6 | //
7 |
8 | import XCTest
9 |
10 | class Tests_macOS: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use recording to get started writing UI tests.
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Barcode & Label
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSApplicationCategoryType
24 | public.app-category.graphics-design
25 | LSRequiresIPhoneOS
26 |
27 | NSCameraUsageDescription
28 | This app will acquire images from camera to apply sketch or cartoon filter effects.
29 | NSPhotoLibraryAddUsageDescription
30 | This app will access your photo library to save the images with sketch or cartoon filter effects.
31 | NSPhotoLibraryUsageDescription
32 | This app will acquire images from photo library to apply sketch or cartoon filter effects.
33 | UIAppFonts
34 |
35 | ConnectCodeIND2of5_S3.otf
36 | ConnectCodeIPostnet.otf
37 | ConnectCode39_S3.otf
38 |
39 | UIApplicationSceneManifest
40 |
41 | UIApplicationSupportsMultipleScenes
42 |
43 |
44 | UIApplicationSupportsIndirectInputEvents
45 |
46 | UIFileSharingEnabled
47 |
48 | UILaunchScreen
49 |
50 | UILaunchStoryboardName
51 | BLLaunch Screen
52 | UIRequiredDeviceCapabilities
53 |
54 | still-camera
55 | armv7
56 |
57 | UISupportedInterfaceOrientations
58 |
59 | UIInterfaceOrientationPortrait
60 |
61 | UISupportedInterfaceOrientations~ipad
62 |
63 | UIInterfaceOrientationPortrait
64 | UIInterfaceOrientationPortraitUpsideDown
65 | UIInterfaceOrientationLandscapeLeft
66 | UIInterfaceOrientationLandscapeRight
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSApplicationCategoryType
24 | public.app-category.graphics-design
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 |
28 |
29 |
--------------------------------------------------------------------------------
/macOS/macOS.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 | com.apple.security.device.camera
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------