@@ -17,6 +17,8 @@ class AccessoryController: ObservableObject {
1717 var selfObserver : AnyCancellable ?
1818 var listElementsObserver = [ AnyCancellable] ( )
1919 let findMyController : FindMyController
20+
21+ weak var savePanel : NSSavePanel ?
2022
2123 init ( accessories: [ Accessory ] , findMyController: FindMyController ) {
2224 self . accessories = accessories
@@ -99,28 +101,65 @@ class AccessoryController: ObservableObject {
99101 let savePanel = NSSavePanel ( )
100102// savePanel.allowedFileTypes = ["plist", "json"]
101103 if #available( macOS 12 . 0 , * ) {
102- savePanel. allowedContentTypes = [ . propertyList, . json]
104+ savePanel. allowedContentTypes = [ . propertyList]
105+ } else {
106+ savePanel. allowedFileTypes = [ " plist " ]
103107 }
104- savePanel . allowedFileTypes = [ " plist " , " json " ]
108+
105109 savePanel. canCreateDirectories = true
106110 savePanel. directoryURL = try FileManager . default. url ( for: . documentDirectory, in: . userDomainMask, appropriateFor: nil , create: false )
107111 savePanel. message = " This export contains all private keys! Keep the file save to protect your location data "
108112 savePanel. nameFieldLabel = " Filename "
109- savePanel. nameFieldStringValue = " openhaystack_accessories.plist "
113+ savePanel. nameFieldStringValue = " openhaystack_accessories "
110114 savePanel. prompt = " Export "
111115 savePanel. title = " Export accessories & keys "
112116 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
113144
114145 let result = savePanel. runModal ( )
115146
116147 if result == . OK,
117- let url = savePanel. url
148+ var url = savePanel. url
118149 {
150+ let selectedItemIndex = popUpButton. indexOfSelectedItem
151+
119152 // Store the accessory file
120- if url. pathExtension == " plist " {
153+ if selectedItemIndex == 0 {
154+ if url. pathExtension != " plist " {
155+ url = url. appendingPathExtension ( " plist " )
156+ }
121157 let propertyList = try PropertyListEncoder ( ) . encode ( accessories)
122158 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+ }
124163 let jsonObject = try JSONEncoder ( ) . encode ( accessories)
125164 try jsonObject. write ( to: url)
126165 }
@@ -129,11 +168,32 @@ class AccessoryController: ObservableObject {
129168 }
130169 throw ImportError . cancelled
131170 }
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+ }
132187
133188 /// Let the user select a file to import the accessories exported by another OpenHaystack instance.
134189 func importAccessories( ) throws {
135190 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+
137197 openPanel. canCreateDirectories = true
138198 openPanel. directoryURL = try FileManager . default. url ( for: . documentDirectory, in: . userDomainMask, appropriateFor: nil , create: false )
139199 openPanel. message = " Import an accessories file that includes the private keys "
@@ -144,9 +204,14 @@ class AccessoryController: ObservableObject {
144204 if result == . OK,
145205 let url = openPanel. url
146206 {
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+
150215 var updatedAccessories = self . accessories
151216 // Filter out accessories with the same id (no duplicates)
152217 importedAccessories = importedAccessories. filter ( { acc in !self . accessories. contains ( where: { acc. id == $0. id } ) } )
0 commit comments