KMBackgroundManager.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. //
  2. // KMBackgroundManager.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by tangchao on 2022/12/23.
  6. //
  7. import Cocoa
  8. /*
  9. Pro Mac -> New
  10. New !-> Pro Mac
  11. 1.Pro Mac New 更新 Pro Mac 的模板,会新建新的 New 模板(原数据保存不变) 会出现两个
  12. 2.Pro Mac 删除
  13. */
  14. class KMBackgroundManager: NSObject, NSCoding {
  15. let kBackgroundFolderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("background")
  16. let kBackgroundPlistPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("background").stringByAppendingPathComponent("background.plist")
  17. var datas: Array<KMBackgroundModel> = []
  18. var backgroundObjects: [KMBackgroundObject] = []
  19. static let defaultManager = KMBackgroundManager()
  20. static let kRemovedKey = "KMBackgroundRemovedKey"
  21. override init() {
  22. super.init()
  23. // 查找原数据
  24. if let storedData = UserDefaults.standard.value(forKey: "kBackgroundInfoSaveKey") as? Data {
  25. NSKeyedUnarchiver.setClass(KMBackgroundObject.self, forClassName: "KMBackgroundObject")
  26. NSKeyedUnarchiver.setClass(KMBackgroundManager.self, forClassName: "KMBackgroundManager")
  27. if let man = NSKeyedUnarchiver.unarchiveObject(with: storedData) as? KMBackgroundManager {
  28. for object in man.backgroundObjects {
  29. self.backgroundObjects.append(object)
  30. }
  31. }
  32. }
  33. // 原数据转换
  34. let removedKeys = KMDataManager.ud_array(forKey: Self.kRemovedKey) as? [String] ?? []
  35. for obj in self.backgroundObjects {
  36. let id = obj.backgroundID ?? ""
  37. if removedKeys.contains(id) {
  38. continue
  39. }
  40. let model = self.parseObject(object: obj)
  41. self.datas.append(model)
  42. }
  43. if (FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  44. let dataDict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  45. if (dataDict == nil) {
  46. return
  47. }
  48. var deleteKeys: Array<String> = []
  49. for keyIndex in 0 ..< (dataDict?.allKeys.count)! {
  50. let key: String = dataDict?.allKeys[keyIndex] as! String
  51. let backgroundDict: NSDictionary = dataDict?.object(forKey: key) as! NSDictionary
  52. let model = parseDictionary(dict: backgroundDict)
  53. /// 赋值id
  54. model.backgroundID = key
  55. if (model.type == .file) {
  56. if (model.image == nil) {
  57. deleteKeys.append(key)
  58. } else {
  59. self.datas.append(model)
  60. }
  61. } else {
  62. self.datas.append(model)
  63. }
  64. }
  65. if (deleteKeys.count > 0) {
  66. let newDict: NSMutableDictionary = NSMutableDictionary(dictionary: dataDict!)
  67. for key in deleteKeys {
  68. newDict.removeObject(forKey: key)
  69. }
  70. newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  71. }
  72. }
  73. }
  74. required init?(coder: NSCoder) {
  75. if let data = coder.decodeObject(forKey: "backgroundObjects") {
  76. self.backgroundObjects = data as? [KMBackgroundObject] ?? []
  77. }
  78. }
  79. func encode(with coder: NSCoder) {
  80. // coder.encode(self.backgroundObjects, forKey: "backgroundObjects")
  81. }
  82. func addTemplate(model: KMBackgroundModel) -> Bool {
  83. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  84. let create: ()? = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  85. if (create == nil) {
  86. return false
  87. }
  88. }
  89. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  90. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  91. if (create == nil) {
  92. return false
  93. }
  94. }
  95. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  96. var newDict:NSMutableDictionary!
  97. if (dict != nil) {
  98. newDict = NSMutableDictionary(dictionary: dict!)
  99. } else {
  100. newDict = NSMutableDictionary()
  101. }
  102. model.modificationDate = Date().timeIntervalSince1970
  103. let backgroundDict = self.parseModel(model: model)
  104. if (backgroundDict.isEmpty) {
  105. let alert = NSAlert()
  106. alert.alertStyle = .critical
  107. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  108. alert.runModal()
  109. return false
  110. }
  111. let tag = fetchAvailableName()//tagString()
  112. newDict.addEntries(from: [tag : backgroundDict])
  113. if model.backgroundID.count == 0 {
  114. model.backgroundID = tag
  115. }
  116. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  117. if (result) {
  118. if (self.datas.count < 1) {
  119. self.datas.append(model)
  120. } else {
  121. self.datas.insert(model, at: 0)
  122. }
  123. }
  124. return result
  125. }
  126. func deleteTemplate(model: KMBackgroundModel) -> Bool {
  127. if model.isMigrate && model.isUpdated == false { // 原数据删除
  128. // if (self._addRemovedTemplate(model: model)) {
  129. var removedKeys = KMDataManager.ud_array(forKey: Self.kRemovedKey) ?? []
  130. removedKeys.append(model.backgroundID)
  131. KMDataManager.ud_set(removedKeys, forKey: Self.kRemovedKey)
  132. if (self.datas.contains(model)) { // 数据源删除
  133. self.datas.removeObject(model)
  134. }
  135. // }
  136. return true
  137. }
  138. if (model.backgroundID.isEmpty) {
  139. return false
  140. }
  141. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  142. return false
  143. }
  144. let key: String = model.backgroundID
  145. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  146. var newDictionary: NSMutableDictionary!
  147. if (dictionary != nil) {
  148. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  149. } else {
  150. newDictionary = NSMutableDictionary()
  151. }
  152. newDictionary.removeObject(forKey: key)
  153. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  154. if (result) {
  155. if (model.type == .file) {
  156. let filePath: String = model.imagePath
  157. try?FileManager.default.removeItem(atPath: filePath)
  158. }
  159. if (self.datas.contains(model)) {
  160. self.datas.removeObject(model)
  161. }
  162. }
  163. return result
  164. }
  165. func deleteAllTemplates() -> Bool {
  166. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  167. return false
  168. }
  169. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  170. var newDictionary: NSMutableDictionary!
  171. if (dictionary != nil) {
  172. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  173. } else {
  174. newDictionary = NSMutableDictionary()
  175. }
  176. newDictionary.removeAllObjects()
  177. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  178. if (result) {
  179. self.datas.removeAll()
  180. }
  181. KMDataManager.ud_set(nil, forKey: Self.kRemovedKey)
  182. self._clearStored()
  183. return result
  184. }
  185. func deleteAllColorTemplates() -> Bool {
  186. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  187. return false
  188. }
  189. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  190. var newDictionary: NSMutableDictionary!
  191. if (dictionary != nil) {
  192. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  193. } else {
  194. newDictionary = NSMutableDictionary()
  195. }
  196. let count = self.datas.count-1
  197. var deleteArray: Array<KMBackgroundModel> = []
  198. for i in 0 ... count {
  199. let model = self.datas[i]
  200. if (model.type == .color) {
  201. newDictionary.removeObject(forKey: model.backgroundID as Any)
  202. deleteArray.append(model)
  203. }
  204. }
  205. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  206. if (result) {
  207. for model in deleteArray {
  208. self.datas.removeObject(model)
  209. }
  210. }
  211. self._clearStored()
  212. return result
  213. }
  214. func deleteAllFileTemplates() -> Bool {
  215. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  216. return false
  217. }
  218. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  219. var newDictionary: NSMutableDictionary!
  220. if (dictionary != nil) {
  221. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  222. } else {
  223. newDictionary = NSMutableDictionary()
  224. }
  225. let count = self.datas.count-1
  226. var deleteArray: Array<KMBackgroundModel> = []
  227. for i in 0 ... count {
  228. let model = self.datas[i]
  229. if (model.type == .file) {
  230. newDictionary.removeObject(forKey: model.backgroundID as Any)
  231. deleteArray.append(model)
  232. }
  233. }
  234. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  235. if (result) {
  236. for model in deleteArray {
  237. self.datas.removeObject(model)
  238. }
  239. }
  240. self._clearStored()
  241. return result
  242. }
  243. func updateTemplate(model: KMBackgroundModel) -> Bool {
  244. if model.isMigrate && model.isUpdated == false { // 原数据
  245. // 移除旧数据
  246. _ = self.deleteTemplate(model: model)
  247. // 新增新数据
  248. model.isUpdated = true
  249. model.modificationDate = Date().timeIntervalSince1970
  250. return self.addTemplate(model: model)
  251. }
  252. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  253. let create = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  254. if (create == nil) {
  255. return false
  256. }
  257. }
  258. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  259. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  260. if (create == nil) {
  261. return false
  262. }
  263. }
  264. var flagModel: KMBackgroundModel!
  265. for model_ in self.datas {
  266. if (model_.backgroundID == model.backgroundID) {
  267. flagModel = model_
  268. break
  269. }
  270. }
  271. if (flagModel == nil) {
  272. return false
  273. }
  274. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  275. var newDict:NSMutableDictionary!
  276. if (dict != nil) {
  277. newDict = NSMutableDictionary(dictionary: dict!)
  278. } else {
  279. newDict = NSMutableDictionary()
  280. }
  281. model.isUpdated = true
  282. model.modificationDate = Date().timeIntervalSince1970
  283. let modelDict = self.parseModel(model: model)
  284. if (modelDict.isEmpty) {
  285. let alert = NSAlert()
  286. alert.alertStyle = .critical
  287. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  288. alert.runModal()
  289. return false
  290. }
  291. newDict.setObject(modelDict, forKey: flagModel.backgroundID as NSCopying)
  292. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  293. if (result) {
  294. let index = self.datas.index(of: flagModel)
  295. self.datas[index!] = model
  296. }
  297. return result
  298. }
  299. /**
  300. `Private Methods`
  301. */
  302. private func _addRemovedTemplate(model: KMBackgroundModel) -> Bool {
  303. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  304. let create: ()? = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  305. if (create == nil) {
  306. return false
  307. }
  308. }
  309. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  310. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  311. if (create == nil) {
  312. return false
  313. }
  314. }
  315. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  316. var newDict:NSMutableDictionary!
  317. if (dict != nil) {
  318. newDict = NSMutableDictionary(dictionary: dict!)
  319. } else {
  320. newDict = NSMutableDictionary()
  321. }
  322. model.isRemoved = true
  323. model.modificationDate = Date().timeIntervalSince1970
  324. let backgroundDict = self.parseModel(model: model)
  325. if (backgroundDict.isEmpty) {
  326. let alert = NSAlert()
  327. alert.alertStyle = .critical
  328. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  329. alert.runModal()
  330. return false
  331. }
  332. let tag = model.backgroundID
  333. newDict.addEntries(from: [tag : backgroundDict])
  334. model.backgroundID = tag
  335. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  336. return result
  337. }
  338. private func parseModel(model: KMBackgroundModel) -> Dictionary<String, Any> {
  339. let tag = tagString()
  340. var dict: [String : Any] = [:]
  341. if (model.type == .color) {
  342. var red: CGFloat = 0.0
  343. var green: CGFloat = 0.0
  344. var blue: CGFloat = 0.0
  345. model.color!.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil)
  346. dict["red"] = red
  347. dict["green"] = green
  348. dict["blue"] = blue
  349. } else {
  350. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  351. try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  352. }
  353. let path = kBackgroundFolderPath?.stringByAppendingPathComponent("\(tag).png")
  354. let image = model.image
  355. let data = image?.tiffRepresentation
  356. let imageRep = NSBitmapImageRep(data: data!)
  357. imageRep?.size = image!.size
  358. var imageData: Data!
  359. let pathExtension = model.imagePath.components(separatedBy: ".").last
  360. if (pathExtension?.lowercased() == "png") {
  361. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:])
  362. } else {
  363. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])
  364. }
  365. do {
  366. try imageData.write(to: URL(fileURLWithPath: path!))
  367. dict["imagePath"] = path?.lastPathComponent
  368. }
  369. catch {
  370. KMPrint("Failed to write to disk.")
  371. return [:]
  372. }
  373. }
  374. dict["type"] = model.type.rawValue
  375. dict["scale"] = model.scale
  376. dict["opacity"] = model.opacity
  377. dict["rotation"] = model.rotation
  378. dict["horizontalMode"] = model.horizontalMode
  379. dict["horizontalSpace"] = model.horizontalSpace
  380. dict["verticalMode"] = model.verticalMode
  381. dict["verticalSpace"] = model.verticalSpace
  382. dict["pageRangeType"] = model.pageRangeType.rawValue
  383. dict["pagesString"] = model.pagesString
  384. dict["isMigrate"] = model.isMigrate
  385. dict["isUpdated"] = model.isUpdated
  386. if let data = model.modificationDate {
  387. dict["modificationDate"] = data
  388. }
  389. dict["isRemoved"] = model.isRemoved
  390. return dict
  391. }
  392. private func parseDictionary(dict: NSDictionary) -> KMBackgroundModel {
  393. let model = KMBackgroundModel()
  394. model.type = KMBackgroundType(rawValue: dict.object(forKey: "type") as! Int)!
  395. if (model.type == .file) {
  396. let path = kBackgroundFolderPath?.stringByAppendingPathComponent(dict.object(forKey: "imagePath") as! String)
  397. if (FileManager.default.fileExists(atPath: path!)) {
  398. model.image = NSImage(contentsOfFile: path!)
  399. model.imagePath = path!
  400. } else {
  401. model.image = nil
  402. }
  403. } else {
  404. let red: CGFloat = dict.object(forKey: "red") as! CGFloat
  405. let green: CGFloat = dict.object(forKey: "green") as! CGFloat
  406. let blue: CGFloat = dict.object(forKey: "blue") as! CGFloat
  407. model.color = NSColor(red: red, green: green, blue: blue, alpha: 1.0)
  408. }
  409. model.scale = dict.object(forKey: "scale") as! CGFloat
  410. model.rotation = CGFloat(Int(dict.object(forKey: "rotation") as! CGFloat))
  411. model.opacity = (dict.object(forKey: "opacity") as! CGFloat)
  412. model.verticalMode = (dict.object(forKey: "verticalMode") as! Int)
  413. model.verticalSpace = (dict.object(forKey: "verticalSpace") as! CGFloat)
  414. model.horizontalMode = (dict.object(forKey: "horizontalMode") as! Int)
  415. model.horizontalSpace = (dict.object(forKey: "horizontalSpace") as! CGFloat)
  416. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: (dict.object(forKey: "pageRangeType") as! Int))!
  417. model.pagesString = (dict.object(forKey: "pagesString") as! String)
  418. model.isMigrate = (dict.object(forKey: "isMigrate") as? Bool) ?? false
  419. model.isUpdated = (dict.object(forKey: "isUpdated") as? Bool) ?? false
  420. model.modificationDate = (dict.object(forKey: "modificationDate") as? TimeInterval)
  421. model.isRemoved = (dict.object(forKey: "isRemoved") as? Bool) ?? false
  422. return model
  423. }
  424. private func parseObject(object: KMBackgroundObject) -> KMBackgroundModel {
  425. let model = KMBackgroundModel()
  426. model.type = object.type
  427. if (model.type == .file) {
  428. model.image = object.image
  429. model.imagePath = object.imagePath ?? ""
  430. } else {
  431. model.color = object.color
  432. }
  433. model.scale = object.scale
  434. model.rotation = object.rotation.cgFloat
  435. model.opacity = object.opacity
  436. model.verticalMode = object.verticalMode
  437. model.verticalSpace = object.verticalSpace.cgFloat
  438. model.horizontalMode = object.horizontalMode
  439. model.horizontalSpace = object.horizontalSpace.cgFloat
  440. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: object.pageRangeType.rawValue) ?? .all
  441. model.pagesString = object.pagesString
  442. model.backgroundID = object.backgroundID ?? "background0"
  443. model.isMigrate = true
  444. return model
  445. }
  446. private func parseModeForObject(_ mode: KMBackgroundModel) -> KMBackgroundObject {
  447. let obj = KMBackgroundObject()
  448. obj.type = mode.type
  449. if (obj.type == .file) {
  450. obj.image = mode.image
  451. obj.imagePath = mode.imagePath
  452. } else {
  453. obj.color = mode.color ?? .red
  454. }
  455. obj.scale = mode.scale
  456. obj.rotation = Int(mode.rotation)
  457. obj.opacity = mode.opacity
  458. obj.verticalMode = mode.verticalMode
  459. obj.verticalSpace = Int(mode.verticalSpace)
  460. obj.horizontalMode = mode.horizontalMode
  461. obj.horizontalSpace = Int(mode.horizontalSpace)
  462. obj.pageRangeType = KMBatchOperatePageChoice.init(rawValue: mode.pageRangeType.rawValue) ?? .All
  463. obj.pagesString = mode.pagesString
  464. obj.backgroundID = mode.backgroundID
  465. return obj
  466. }
  467. private func _addBackground(_ obj: KMBackgroundObject) {
  468. // self.backgroundObjects.insert(obj, at: 0)
  469. // self._store()
  470. }
  471. private func _removeBackground(_ obj: KMBackgroundObject) {
  472. // self.backgroundObjects.removeObject(obj)
  473. // self._store()
  474. }
  475. private func _store() {
  476. // let encodedObject = NSKeyedArchiver.archivedData(withRootObject: self)
  477. // let defaults = UserDefaults.standard
  478. // defaults.set(encodedObject, forKey: "kBackgroundInfoSaveKey")
  479. // defaults.synchronize()
  480. }
  481. private func _clearStored() {
  482. let defaults = UserDefaults.standard
  483. defaults.set(nil, forKey: "kBackgroundInfoSaveKey")
  484. defaults.synchronize()
  485. }
  486. private func tagString() -> String {
  487. var result: String = ""
  488. let dateFormatter = DateFormatter()
  489. dateFormatter.dateFormat = "yyMMddHHmmss"
  490. result.append(dateFormatter.string(from: Date()))
  491. result = result.appendingFormat("%04d", arc4random()%10000)
  492. return result
  493. }
  494. func fetchAvailableName() -> String {
  495. var availableIndex = 0
  496. for item in datas {
  497. if item.backgroundID.hasPrefix("Background") {
  498. if let index = Int(item.backgroundID.dropFirst("Background".count)), index >= availableIndex {
  499. availableIndex = index + 1
  500. }
  501. }
  502. }
  503. return "Background\(availableIndex)"
  504. }
  505. }