KMBackgroundManager.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  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. // 移除旧数据
  244. _ = self.deleteTemplate(model: model)
  245. // 新增新数据
  246. model.isUpdated = true
  247. model.modificationDate = Date().timeIntervalSince1970
  248. return self.addTemplate(model: model)
  249. }
  250. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  251. let create = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  252. if (create == nil) {
  253. return false
  254. }
  255. }
  256. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  257. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  258. if (create == nil) {
  259. return false
  260. }
  261. }
  262. var flagModel: KMBackgroundModel!
  263. for model_ in self.datas {
  264. if (model_.backgroundID == model.backgroundID) {
  265. flagModel = model_
  266. break
  267. }
  268. }
  269. if (flagModel == nil) {
  270. return false
  271. }
  272. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  273. var newDict:NSMutableDictionary!
  274. if (dict != nil) {
  275. newDict = NSMutableDictionary(dictionary: dict!)
  276. } else {
  277. newDict = NSMutableDictionary()
  278. }
  279. model.isUpdated = true
  280. model.modificationDate = Date().timeIntervalSince1970
  281. let modelDict = self.parseModel(model: model)
  282. if (modelDict.isEmpty) {
  283. let alert = NSAlert()
  284. alert.alertStyle = .critical
  285. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  286. alert.runModal()
  287. return false
  288. }
  289. newDict.setObject(modelDict, forKey: flagModel.backgroundID as NSCopying)
  290. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  291. if (result) {
  292. let index = self.datas.index(of: flagModel)
  293. self.datas[index!] = model
  294. }
  295. return result
  296. }
  297. /**
  298. `Private Methods`
  299. */
  300. private func _addRemovedTemplate(model: KMBackgroundModel) -> Bool {
  301. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  302. let create: ()? = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  303. if (create == nil) {
  304. return false
  305. }
  306. }
  307. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  308. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  309. if (create == nil) {
  310. return false
  311. }
  312. }
  313. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  314. var newDict:NSMutableDictionary!
  315. if (dict != nil) {
  316. newDict = NSMutableDictionary(dictionary: dict!)
  317. } else {
  318. newDict = NSMutableDictionary()
  319. }
  320. model.isRemoved = true
  321. model.modificationDate = Date().timeIntervalSince1970
  322. let backgroundDict = self.parseModel(model: model)
  323. if (backgroundDict.isEmpty) {
  324. let alert = NSAlert()
  325. alert.alertStyle = .critical
  326. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  327. alert.runModal()
  328. return false
  329. }
  330. let tag = model.backgroundID
  331. newDict.addEntries(from: [tag : backgroundDict])
  332. model.backgroundID = tag
  333. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  334. return result
  335. }
  336. private func parseModel(model: KMBackgroundModel) -> Dictionary<String, Any> {
  337. let tag = tagString()
  338. var dict: [String : Any] = [:]
  339. if (model.type == .color) {
  340. var red: CGFloat = 0.0
  341. var green: CGFloat = 0.0
  342. var blue: CGFloat = 0.0
  343. model.color!.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil)
  344. dict["red"] = red
  345. dict["green"] = green
  346. dict["blue"] = blue
  347. } else {
  348. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  349. try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  350. }
  351. let path = kBackgroundFolderPath?.stringByAppendingPathComponent("\(tag).png")
  352. let image = model.image
  353. let data = image?.tiffRepresentation
  354. let imageRep = NSBitmapImageRep(data: data!)
  355. imageRep?.size = image!.size
  356. var imageData: Data!
  357. let pathExtension = model.imagePath.components(separatedBy: ".").last
  358. if (pathExtension?.lowercased() == "png") {
  359. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:])
  360. } else {
  361. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])
  362. }
  363. do {
  364. try imageData.write(to: URL(fileURLWithPath: path!))
  365. dict["imagePath"] = path?.lastPathComponent
  366. }
  367. catch {
  368. KMPrint("Failed to write to disk.")
  369. return [:]
  370. }
  371. }
  372. dict["type"] = model.type.rawValue
  373. dict["scale"] = model.scale
  374. dict["opacity"] = model.opacity
  375. dict["rotation"] = model.rotation
  376. dict["horizontalMode"] = model.horizontalMode
  377. dict["horizontalSpace"] = model.horizontalSpace
  378. dict["verticalMode"] = model.verticalMode
  379. dict["verticalSpace"] = model.verticalSpace
  380. dict["pageRangeType"] = model.pageRangeType.rawValue
  381. dict["pagesString"] = model.pagesString
  382. dict["isMigrate"] = model.isMigrate
  383. dict["isUpdated"] = model.isUpdated
  384. if let data = model.modificationDate {
  385. dict["modificationDate"] = data
  386. }
  387. dict["isRemoved"] = model.isRemoved
  388. return dict
  389. }
  390. private func parseDictionary(dict: NSDictionary) -> KMBackgroundModel {
  391. let model = KMBackgroundModel()
  392. model.type = KMBackgroundType(rawValue: dict.object(forKey: "type") as! Int)!
  393. if (model.type == .file) {
  394. let path = kBackgroundFolderPath?.stringByAppendingPathComponent(dict.object(forKey: "imagePath") as! String)
  395. if (FileManager.default.fileExists(atPath: path!)) {
  396. model.image = NSImage(contentsOfFile: path!)
  397. model.imagePath = path!
  398. } else {
  399. model.image = nil
  400. }
  401. } else {
  402. let red: CGFloat = dict.object(forKey: "red") as! CGFloat
  403. let green: CGFloat = dict.object(forKey: "green") as! CGFloat
  404. let blue: CGFloat = dict.object(forKey: "blue") as! CGFloat
  405. model.color = NSColor(red: red, green: green, blue: blue, alpha: 1.0)
  406. }
  407. model.scale = dict.object(forKey: "scale") as! CGFloat
  408. model.rotation = CGFloat(Int(dict.object(forKey: "rotation") as! CGFloat))
  409. model.opacity = (dict.object(forKey: "opacity") as! CGFloat)
  410. model.verticalMode = (dict.object(forKey: "verticalMode") as! Int)
  411. model.verticalSpace = (dict.object(forKey: "verticalSpace") as! CGFloat)
  412. model.horizontalMode = (dict.object(forKey: "horizontalMode") as! Int)
  413. model.horizontalSpace = (dict.object(forKey: "horizontalSpace") as! CGFloat)
  414. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: (dict.object(forKey: "pageRangeType") as! Int))!
  415. model.pagesString = (dict.object(forKey: "pagesString") as! String)
  416. model.isMigrate = (dict.object(forKey: "isMigrate") as? Bool) ?? false
  417. model.isUpdated = (dict.object(forKey: "isUpdated") as? Bool) ?? false
  418. model.modificationDate = (dict.object(forKey: "modificationDate") as? TimeInterval)
  419. model.isRemoved = (dict.object(forKey: "isRemoved") as? Bool) ?? false
  420. return model
  421. }
  422. private func parseObject(object: KMBackgroundObject) -> KMBackgroundModel {
  423. let model = KMBackgroundModel()
  424. model.type = object.type
  425. if (model.type == .file) {
  426. model.image = object.image
  427. model.imagePath = object.imagePath ?? ""
  428. } else {
  429. model.color = object.color
  430. }
  431. model.scale = object.scale
  432. model.rotation = object.rotation.cgFloat
  433. model.opacity = object.opacity
  434. model.verticalMode = object.verticalMode
  435. model.verticalSpace = object.verticalSpace.cgFloat
  436. model.horizontalMode = object.horizontalMode
  437. model.horizontalSpace = object.horizontalSpace.cgFloat
  438. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: object.pageRangeType.rawValue) ?? .all
  439. model.pagesString = object.pagesString
  440. model.backgroundID = object.backgroundID ?? "background0"
  441. model.isMigrate = true
  442. return model
  443. }
  444. private func parseModeForObject(_ mode: KMBackgroundModel) -> KMBackgroundObject {
  445. let obj = KMBackgroundObject()
  446. obj.type = mode.type
  447. if (obj.type == .file) {
  448. obj.image = mode.image
  449. obj.imagePath = mode.imagePath
  450. } else {
  451. obj.color = mode.color ?? .red
  452. }
  453. obj.scale = mode.scale
  454. obj.rotation = Int(mode.rotation)
  455. obj.opacity = mode.opacity
  456. obj.verticalMode = mode.verticalMode
  457. obj.verticalSpace = Int(mode.verticalSpace)
  458. obj.horizontalMode = mode.horizontalMode
  459. obj.horizontalSpace = Int(mode.horizontalSpace)
  460. obj.pageRangeType = KMBatchOperatePageChoice.init(rawValue: mode.pageRangeType.rawValue) ?? .All
  461. obj.pagesString = mode.pagesString
  462. obj.backgroundID = mode.backgroundID
  463. return obj
  464. }
  465. private func _addBackground(_ obj: KMBackgroundObject) {
  466. // self.backgroundObjects.insert(obj, at: 0)
  467. // self._store()
  468. }
  469. private func _removeBackground(_ obj: KMBackgroundObject) {
  470. // self.backgroundObjects.removeObject(obj)
  471. // self._store()
  472. }
  473. private func _store() {
  474. // let encodedObject = NSKeyedArchiver.archivedData(withRootObject: self)
  475. // let defaults = UserDefaults.standard
  476. // defaults.set(encodedObject, forKey: "kBackgroundInfoSaveKey")
  477. // defaults.synchronize()
  478. }
  479. private func _clearStored() {
  480. let defaults = UserDefaults.standard
  481. defaults.set(nil, forKey: "kBackgroundInfoSaveKey")
  482. defaults.synchronize()
  483. }
  484. private func tagString() -> String {
  485. var result: String = ""
  486. let dateFormatter = DateFormatter()
  487. dateFormatter.dateFormat = "yyMMddHHmmss"
  488. result.append(dateFormatter.string(from: Date()))
  489. result = result.appendingFormat("%04d", arc4random()%10000)
  490. return result
  491. }
  492. func fetchAvailableName() -> String {
  493. var availableIndex = 0
  494. for item in datas {
  495. if item.backgroundID.hasPrefix("Background") {
  496. if let index = Int(item.backgroundID.dropFirst("Background".count)), index >= availableIndex {
  497. availableIndex = index + 1
  498. }
  499. }
  500. }
  501. return "Background\(availableIndex)"
  502. }
  503. }