/
History.swift
123 lines (93 loc) · 2.85 KB
/
History.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import UIKit
struct History {
private let oneMegaByte = 1000000
private let sizeLimitInMegaBytes = 50
private var sizeLimit: Int {
return oneMegaByte * sizeLimitInMegaBytes
}
private var undoList = [CGImage]()
private var redoList = [CGImage]()
private var approximateFileSizeRaw: Int64 {
let undoSize = undoList.reduce(0) { total, image in
return total + image.approximateFileSize
}
let redoSize = redoList.reduce(0) { total, image in
return total + image.approximateFileSize
}
return undoSize + redoSize
}
var approximateFileSize: String {
let formatter = ByteCountFormatter()
formatter.countStyle = .file
return formatter.string(fromByteCount: approximateFileSizeRaw)
}
var lastImage: CGImage? {
return undoList.last
}
var canUndo: Bool {
return !undoList.isEmpty
}
var canRedo: Bool {
return !redoList.isEmpty
}
var canReset: Bool {
return canUndo || canRedo
}
// MARK: - Private
private mutating func appendUndo(image: CGImage?) {
guard let image = image else { return }
if approximateFileSizeRaw >= sizeLimit {
undoList.removeFirst()
}
undoList.append(image)
}
private mutating func appendRedo(image: CGImage?) {
guard let image = image else { return }
redoList.append(image)
}
private mutating func resetUndo() {
undoList.removeAll()
}
private mutating func resetRedo() {
redoList.removeAll()
}
// MARK: - Public
mutating func append(image: CGImage?) {
appendUndo(image: image)
resetRedo()
}
mutating func undo() {
guard canUndo else {
return
}
let last = undoList.removeLast()
appendRedo(image: last)
}
mutating func redo() {
guard canRedo else {
return
}
let last = redoList.removeLast()
appendUndo(image: last)
}
mutating func clear() {
resetUndo()
resetRedo()
}
}
extension History: Serializable {
var serializedDictionary: [String: Any] {
return [
"undoList": undoList.map { UIImage(cgImage: $0) },
"redoList": redoList.map { UIImage(cgImage: $0) }
]
}
init?(serializedDictionary: [String: Any]) {
guard let undoList = serializedDictionary["undoList"] as? [UIImage],
let redoList = serializedDictionary["redoList"] as? [UIImage] else {
return nil
}
self.undoList = undoList.compactMap { $0.cgImage }
self.redoList = redoList.compactMap { $0.cgImage }
}
}