KMBackgroundManager.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  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. model.backgroundID = tag
  114. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  115. if (result) {
  116. if (self.datas.count < 1) {
  117. self.datas.append(model)
  118. } else {
  119. self.datas.insert(model, at: 0)
  120. }
  121. }
  122. return result
  123. }
  124. func deleteTemplate(model: KMBackgroundModel) -> Bool {
  125. if model.isMigrate && model.isUpdated == false { // 原数据删除
  126. // if (self._addRemovedTemplate(model: model)) {
  127. var removedKeys = KMDataManager.ud_array(forKey: Self.kRemovedKey) ?? []
  128. removedKeys.append(model.backgroundID)
  129. KMDataManager.ud_set(removedKeys, forKey: Self.kRemovedKey)
  130. if (self.datas.contains(model)) { // 数据源删除
  131. self.datas.removeObject(model)
  132. }
  133. // }
  134. return true
  135. }
  136. if (model.backgroundID.isEmpty) {
  137. return false
  138. }
  139. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  140. return false
  141. }
  142. let key: String = model.backgroundID
  143. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  144. var newDictionary: NSMutableDictionary!
  145. if (dictionary != nil) {
  146. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  147. } else {
  148. newDictionary = NSMutableDictionary()
  149. }
  150. newDictionary.removeObject(forKey: key)
  151. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  152. if (result) {
  153. if (model.type == .file) {
  154. let filePath: String = model.imagePath
  155. try?FileManager.default.removeItem(atPath: filePath)
  156. }
  157. if (self.datas.contains(model)) {
  158. self.datas.removeObject(model)
  159. }
  160. }
  161. return result
  162. }
  163. func deleteAllTemplates() -> Bool {
  164. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  165. return false
  166. }
  167. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  168. var newDictionary: NSMutableDictionary!
  169. if (dictionary != nil) {
  170. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  171. } else {
  172. newDictionary = NSMutableDictionary()
  173. }
  174. newDictionary.removeAllObjects()
  175. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  176. if (result) {
  177. self.datas.removeAll()
  178. }
  179. KMDataManager.ud_set(nil, forKey: Self.kRemovedKey)
  180. self._clearStored()
  181. return result
  182. }
  183. func deleteAllColorTemplates() -> Bool {
  184. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  185. return false
  186. }
  187. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  188. var newDictionary: NSMutableDictionary!
  189. if (dictionary != nil) {
  190. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  191. } else {
  192. newDictionary = NSMutableDictionary()
  193. }
  194. let count = self.datas.count-1
  195. var deleteArray: Array<KMBackgroundModel> = []
  196. for i in 0 ... count {
  197. let model = self.datas[i]
  198. if (model.type == .color) {
  199. newDictionary.removeObject(forKey: model.backgroundID as Any)
  200. deleteArray.append(model)
  201. }
  202. }
  203. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  204. if (result) {
  205. for model in deleteArray {
  206. self.datas.removeObject(model)
  207. }
  208. }
  209. self._clearStored()
  210. return result
  211. }
  212. func deleteAllFileTemplates() -> Bool {
  213. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  214. return false
  215. }
  216. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  217. var newDictionary: NSMutableDictionary!
  218. if (dictionary != nil) {
  219. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  220. } else {
  221. newDictionary = NSMutableDictionary()
  222. }
  223. let count = self.datas.count-1
  224. var deleteArray: Array<KMBackgroundModel> = []
  225. for i in 0 ... count {
  226. let model = self.datas[i]
  227. if (model.type == .file) {
  228. newDictionary.removeObject(forKey: model.backgroundID as Any)
  229. deleteArray.append(model)
  230. }
  231. }
  232. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  233. if (result) {
  234. for model in deleteArray {
  235. self.datas.removeObject(model)
  236. }
  237. }
  238. self._clearStored()
  239. return result
  240. }
  241. func updateTemplate(model: KMBackgroundModel) -> Bool {
  242. if model.isMigrate && model.isUpdated == false { // 原数据
  243. model.isUpdated = true
  244. model.modificationDate = Date().timeIntervalSince1970
  245. return self.addTemplate(model: model)
  246. }
  247. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  248. let create = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  249. if (create == nil) {
  250. return false
  251. }
  252. }
  253. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  254. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  255. if (create == nil) {
  256. return false
  257. }
  258. }
  259. var flagModel: KMBackgroundModel!
  260. for model_ in self.datas {
  261. if (model_.backgroundID == model.backgroundID) {
  262. flagModel = model_
  263. break
  264. }
  265. }
  266. if (flagModel == nil) {
  267. return false
  268. }
  269. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  270. var newDict:NSMutableDictionary!
  271. if (dict != nil) {
  272. newDict = NSMutableDictionary(dictionary: dict!)
  273. } else {
  274. newDict = NSMutableDictionary()
  275. }
  276. model.isUpdated = true
  277. model.modificationDate = Date().timeIntervalSince1970
  278. let modelDict = self.parseModel(model: model)
  279. if (modelDict.isEmpty) {
  280. let alert = NSAlert()
  281. alert.alertStyle = .critical
  282. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  283. alert.runModal()
  284. return false
  285. }
  286. newDict.setObject(modelDict, forKey: flagModel.backgroundID as NSCopying)
  287. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  288. if (result) {
  289. let index = self.datas.index(of: flagModel)
  290. self.datas[index!] = model
  291. }
  292. return result
  293. }
  294. /**
  295. `Private Methods`
  296. */
  297. private func _addRemovedTemplate(model: KMBackgroundModel) -> Bool {
  298. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  299. let create: ()? = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  300. if (create == nil) {
  301. return false
  302. }
  303. }
  304. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  305. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  306. if (create == nil) {
  307. return false
  308. }
  309. }
  310. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  311. var newDict:NSMutableDictionary!
  312. if (dict != nil) {
  313. newDict = NSMutableDictionary(dictionary: dict!)
  314. } else {
  315. newDict = NSMutableDictionary()
  316. }
  317. model.isRemoved = true
  318. model.modificationDate = Date().timeIntervalSince1970
  319. let backgroundDict = self.parseModel(model: model)
  320. if (backgroundDict.isEmpty) {
  321. let alert = NSAlert()
  322. alert.alertStyle = .critical
  323. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  324. alert.runModal()
  325. return false
  326. }
  327. let tag = model.backgroundID
  328. newDict.addEntries(from: [tag : backgroundDict])
  329. model.backgroundID = tag
  330. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  331. return result
  332. }
  333. private func parseModel(model: KMBackgroundModel) -> Dictionary<String, Any> {
  334. let tag = tagString()
  335. var dict: [String : Any] = [:]
  336. if (model.type == .color) {
  337. var red: CGFloat = 0.0
  338. var green: CGFloat = 0.0
  339. var blue: CGFloat = 0.0
  340. model.color!.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil)
  341. dict["red"] = red
  342. dict["green"] = green
  343. dict["blue"] = blue
  344. } else {
  345. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  346. try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  347. }
  348. let path = kBackgroundFolderPath?.stringByAppendingPathComponent("\(tag).png")
  349. let image = model.image
  350. let data = image?.tiffRepresentation
  351. let imageRep = NSBitmapImageRep(data: data!)
  352. imageRep?.size = image!.size
  353. var imageData: Data!
  354. let pathExtension = model.imagePath.components(separatedBy: ".").last
  355. if (pathExtension?.lowercased() == "png") {
  356. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:])
  357. } else {
  358. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])
  359. }
  360. do {
  361. try imageData.write(to: URL(fileURLWithPath: path!))
  362. dict["imagePath"] = path?.lastPathComponent
  363. }
  364. catch {
  365. KMPrint("Failed to write to disk.")
  366. return [:]
  367. }
  368. }
  369. dict["type"] = model.type.rawValue
  370. dict["scale"] = model.scale
  371. dict["opacity"] = model.opacity
  372. dict["rotation"] = model.rotation
  373. dict["horizontalMode"] = model.horizontalMode
  374. dict["horizontalSpace"] = model.horizontalSpace
  375. dict["verticalMode"] = model.verticalMode
  376. dict["verticalSpace"] = model.verticalSpace
  377. dict["pageRangeType"] = model.pageRangeType.rawValue
  378. dict["pagesString"] = model.pagesString
  379. dict["isMigrate"] = model.isMigrate
  380. dict["isUpdated"] = model.isUpdated
  381. if let data = model.modificationDate {
  382. dict["modificationDate"] = data
  383. }
  384. dict["isRemoved"] = model.isRemoved
  385. return dict
  386. }
  387. private func parseDictionary(dict: NSDictionary) -> KMBackgroundModel {
  388. let model = KMBackgroundModel()
  389. model.type = KMBackgroundType(rawValue: dict.object(forKey: "type") as! Int)!
  390. if (model.type == .file) {
  391. let path = kBackgroundFolderPath?.stringByAppendingPathComponent(dict.object(forKey: "imagePath") as! String)
  392. if (FileManager.default.fileExists(atPath: path!)) {
  393. model.image = NSImage(contentsOfFile: path!)
  394. model.imagePath = path!
  395. } else {
  396. model.image = nil
  397. }
  398. } else {
  399. let red: CGFloat = dict.object(forKey: "red") as! CGFloat
  400. let green: CGFloat = dict.object(forKey: "green") as! CGFloat
  401. let blue: CGFloat = dict.object(forKey: "blue") as! CGFloat
  402. model.color = NSColor(red: red, green: green, blue: blue, alpha: 1.0)
  403. }
  404. model.scale = dict.object(forKey: "scale") as! CGFloat
  405. model.rotation = CGFloat(Int(dict.object(forKey: "rotation") as! CGFloat))
  406. model.opacity = (dict.object(forKey: "opacity") as! CGFloat)
  407. model.verticalMode = (dict.object(forKey: "verticalMode") as! Int)
  408. model.verticalSpace = (dict.object(forKey: "verticalSpace") as! CGFloat)
  409. model.horizontalMode = (dict.object(forKey: "horizontalMode") as! Int)
  410. model.horizontalSpace = (dict.object(forKey: "horizontalSpace") as! CGFloat)
  411. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: (dict.object(forKey: "pageRangeType") as! Int))!
  412. model.pagesString = (dict.object(forKey: "pagesString") as! String)
  413. model.isMigrate = (dict.object(forKey: "isMigrate") as? Bool) ?? false
  414. model.isUpdated = (dict.object(forKey: "isUpdated") as? Bool) ?? false
  415. model.modificationDate = (dict.object(forKey: "modificationDate") as? TimeInterval)
  416. model.isRemoved = (dict.object(forKey: "isRemoved") as? Bool) ?? false
  417. return model
  418. }
  419. private func parseObject(object: KMBackgroundObject) -> KMBackgroundModel {
  420. let model = KMBackgroundModel()
  421. model.type = object.type
  422. if (model.type == .file) {
  423. model.image = object.image
  424. model.imagePath = object.imagePath ?? ""
  425. } else {
  426. model.color = object.color
  427. }
  428. model.scale = object.scale
  429. model.rotation = object.rotation.cgFloat
  430. model.opacity = object.opacity
  431. model.verticalMode = object.verticalMode
  432. model.verticalSpace = object.verticalSpace.cgFloat
  433. model.horizontalMode = object.horizontalMode
  434. model.horizontalSpace = object.horizontalSpace.cgFloat
  435. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: object.pageRangeType.rawValue) ?? .all
  436. model.pagesString = object.pagesString
  437. model.backgroundID = object.backgroundID ?? "background0"
  438. model.isMigrate = true
  439. return model
  440. }
  441. private func parseModeForObject(_ mode: KMBackgroundModel) -> KMBackgroundObject {
  442. let obj = KMBackgroundObject()
  443. obj.type = mode.type
  444. if (obj.type == .file) {
  445. obj.image = mode.image
  446. obj.imagePath = mode.imagePath
  447. } else {
  448. obj.color = mode.color ?? .red
  449. }
  450. obj.scale = mode.scale
  451. obj.rotation = Int(mode.rotation)
  452. obj.opacity = mode.opacity
  453. obj.verticalMode = mode.verticalMode
  454. obj.verticalSpace = Int(mode.verticalSpace)
  455. obj.horizontalMode = mode.horizontalMode
  456. obj.horizontalSpace = Int(mode.horizontalSpace)
  457. obj.pageRangeType = KMBatchOperatePageChoice.init(rawValue: mode.pageRangeType.rawValue) ?? .All
  458. obj.pagesString = mode.pagesString
  459. obj.backgroundID = mode.backgroundID
  460. return obj
  461. }
  462. private func _addBackground(_ obj: KMBackgroundObject) {
  463. // self.backgroundObjects.insert(obj, at: 0)
  464. // self._store()
  465. }
  466. private func _removeBackground(_ obj: KMBackgroundObject) {
  467. // self.backgroundObjects.removeObject(obj)
  468. // self._store()
  469. }
  470. private func _store() {
  471. // let encodedObject = NSKeyedArchiver.archivedData(withRootObject: self)
  472. // let defaults = UserDefaults.standard
  473. // defaults.set(encodedObject, forKey: "kBackgroundInfoSaveKey")
  474. // defaults.synchronize()
  475. }
  476. private func _clearStored() {
  477. let defaults = UserDefaults.standard
  478. defaults.set(nil, forKey: "kBackgroundInfoSaveKey")
  479. defaults.synchronize()
  480. }
  481. private func tagString() -> String {
  482. var result: String = ""
  483. let dateFormatter = DateFormatter()
  484. dateFormatter.dateFormat = "yyMMddHHmmss"
  485. result.append(dateFormatter.string(from: Date()))
  486. result = result.appendingFormat("%04d", arc4random()%10000)
  487. return result
  488. }
  489. func fetchAvailableName() -> String {
  490. var availableIndex = 0
  491. for item in datas {
  492. if item.backgroundID.hasPrefix("Background") {
  493. if let index = Int(item.backgroundID.dropFirst("Background".count)), index >= availableIndex {
  494. availableIndex = index + 1
  495. }
  496. }
  497. }
  498. return "Background\(availableIndex)"
  499. }
  500. }