@@ -17,6 +17,8 @@ class AccessoryController: ObservableObject {
17
17
var selfObserver : AnyCancellable ?
18
18
var listElementsObserver = [ AnyCancellable] ( )
19
19
let findMyController : FindMyController
20
+
21
+ weak var savePanel : NSSavePanel ?
20
22
21
23
init ( accessories: [ Accessory ] , findMyController: FindMyController ) {
22
24
self . accessories = accessories
@@ -99,28 +101,65 @@ class AccessoryController: ObservableObject {
99
101
let savePanel = NSSavePanel ( )
100
102
// savePanel.allowedFileTypes = ["plist", "json"]
101
103
if #available( macOS 12 . 0 , * ) {
102
- savePanel. allowedContentTypes = [ . propertyList, . json]
104
+ savePanel. allowedContentTypes = [ . propertyList]
105
+ } else {
106
+ savePanel. allowedFileTypes = [ " plist " ]
103
107
}
104
- savePanel . allowedFileTypes = [ " plist " , " json " ]
108
+
105
109
savePanel. canCreateDirectories = true
106
110
savePanel. directoryURL = try FileManager . default. url ( for: . documentDirectory, in: . userDomainMask, appropriateFor: nil , create: false )
107
111
savePanel. message = " This export contains all private keys! Keep the file save to protect your location data "
108
112
savePanel. nameFieldLabel = " Filename "
109
- savePanel. nameFieldStringValue = " openhaystack_accessories.plist "
113
+ savePanel. nameFieldStringValue = " openhaystack_accessories "
110
114
savePanel. prompt = " Export "
111
115
savePanel. title = " Export accessories & keys "
112
116
savePanel. isExtensionHidden = false
117
+
118
+ let accessoryView = NSView ( )
119
+ let popUpButton = NSPopUpButton ( title: " File type " , target: self , action: #selector( exportFileTypeChanged ( button: ) ) )
120
+ popUpButton. addItems ( withTitles: [ " Property List " , " JSON " ] )
121
+ popUpButton. selectItem ( at: 0 )
122
+ popUpButton. stringValue = " File type "
123
+ popUpButton. translatesAutoresizingMaskIntoConstraints = false
124
+ accessoryView. addSubview ( popUpButton)
125
+
126
+ let popUpButtonLabel = NSTextField ( labelWithString: " File type " )
127
+ popUpButtonLabel. translatesAutoresizingMaskIntoConstraints = false
128
+ accessoryView. addSubview ( popUpButtonLabel)
129
+ accessoryView. translatesAutoresizingMaskIntoConstraints = false
130
+
131
+ // popUpButtonLabel.leadingAnchor.constraint(greaterThanOrEqualTo: accessoryView.leadingAnchor, constant: 20.0).isActive = true
132
+ popUpButtonLabel. trailingAnchor. constraint ( equalTo: popUpButton. leadingAnchor, constant: - 8.0 ) . isActive = true
133
+ popUpButtonLabel. trailingAnchor. constraint ( lessThanOrEqualTo: accessoryView. centerXAnchor, constant: 0 ) . isActive = true
134
+ popUpButtonLabel. centerYAnchor. constraint ( equalTo: popUpButton. centerYAnchor, constant: 0 ) . isActive = true
135
+ // popUpButton.trailingAnchor.constraint(lessThanOrEqualTo: accessoryView.trailingAnchor, constant: -20.0).isActive = true
136
+ popUpButton. leadingAnchor. constraint ( lessThanOrEqualTo: accessoryView. centerXAnchor, constant: 0 ) . isActive = true
137
+ popUpButton. topAnchor. constraint ( equalTo: accessoryView. topAnchor, constant: 8.0 ) . isActive = true
138
+ popUpButton. bottomAnchor. constraint ( equalTo: accessoryView. bottomAnchor, constant: - 8.0 ) . isActive = true
139
+ popUpButton. heightAnchor. constraint ( greaterThanOrEqualToConstant: 20.0 ) . isActive = true
140
+ popUpButton. widthAnchor. constraint ( lessThanOrEqualToConstant: 200.0 ) . isActive = true
141
+
142
+ savePanel. accessoryView = accessoryView
143
+ self . savePanel = savePanel
113
144
114
145
let result = savePanel. runModal ( )
115
146
116
147
if result == . OK,
117
- let url = savePanel. url
148
+ var url = savePanel. url
118
149
{
150
+ let selectedItemIndex = popUpButton. indexOfSelectedItem
151
+
119
152
// Store the accessory file
120
- if url. pathExtension == " plist " {
153
+ if selectedItemIndex == 0 {
154
+ if url. pathExtension != " plist " {
155
+ url = url. appendingPathExtension ( " plist " )
156
+ }
121
157
let propertyList = try PropertyListEncoder ( ) . encode ( accessories)
122
158
try propertyList. write ( to: url)
123
- } else if url. pathExtension == " json " {
159
+ } else if selectedItemIndex == 1 {
160
+ if url. pathExtension != " json " {
161
+ url = url. appendingPathExtension ( " json " )
162
+ }
124
163
let jsonObject = try JSONEncoder ( ) . encode ( accessories)
125
164
try jsonObject. write ( to: url)
126
165
}
@@ -129,11 +168,32 @@ class AccessoryController: ObservableObject {
129
168
}
130
169
throw ImportError . cancelled
131
170
}
171
+
172
+ @objc func exportFileTypeChanged( button: NSPopUpButton ) {
173
+ if button. indexOfSelectedItem == 0 {
174
+ if #available( macOS 12 . 0 , * ) {
175
+ self . savePanel? . allowedContentTypes = [ . propertyList]
176
+ } else {
177
+ self . savePanel? . allowedFileTypes = [ " plist " ]
178
+ }
179
+ } else {
180
+ if #available( macOS 12 . 0 , * ) {
181
+ self . savePanel? . allowedContentTypes = [ . json]
182
+ } else {
183
+ self . savePanel? . allowedFileTypes = [ " json " ]
184
+ }
185
+ }
186
+ }
132
187
133
188
/// Let the user select a file to import the accessories exported by another OpenHaystack instance.
134
189
func importAccessories( ) throws {
135
190
let openPanel = NSOpenPanel ( )
136
- openPanel. allowedFileTypes = [ " plist " ]
191
+ if #available( macOS 12 . 0 , * ) {
192
+ openPanel. allowedContentTypes = [ . json, . propertyList]
193
+ } else {
194
+ openPanel. allowedFileTypes = [ " json " , " plist " ]
195
+ }
196
+
137
197
openPanel. canCreateDirectories = true
138
198
openPanel. directoryURL = try FileManager . default. url ( for: . documentDirectory, in: . userDomainMask, appropriateFor: nil , create: false )
139
199
openPanel. message = " Import an accessories file that includes the private keys "
@@ -144,9 +204,14 @@ class AccessoryController: ObservableObject {
144
204
if result == . OK,
145
205
let url = openPanel. url
146
206
{
147
- let propertyList = try Data ( contentsOf: url)
148
- var importedAccessories = try PropertyListDecoder ( ) . decode ( [ Accessory ] . self, from: propertyList)
149
-
207
+ let accessoryData = try Data ( contentsOf: url)
208
+ var importedAccessories : [ Accessory ]
209
+ if url. pathExtension == " plist " {
210
+ importedAccessories = try PropertyListDecoder ( ) . decode ( [ Accessory ] . self, from: accessoryData)
211
+ } else {
212
+ importedAccessories = try JSONDecoder ( ) . decode ( [ Accessory ] . self, from: accessoryData)
213
+ }
214
+
150
215
var updatedAccessories = self . accessories
151
216
// Filter out accessories with the same id (no duplicates)
152
217
importedAccessories = importedAccessories. filter ( { acc in !self . accessories. contains ( where: { acc. id == $0. id } ) } )
0 commit comments