Fix: Add new cap without internet access
This commit is contained in:
parent
c13dd8b080
commit
02e8e9a585
@ -154,18 +154,21 @@ final class Cap {
|
||||
self.id = Cap.nextUnusedId
|
||||
self.tile = id - 1
|
||||
self.name = name
|
||||
self.count = 1
|
||||
self.count = 0
|
||||
self.cleanName = name.clean
|
||||
guard save(mainImage: image) else {
|
||||
return nil
|
||||
}
|
||||
upload(mainImage: image) { success in
|
||||
guard success else { return }
|
||||
Cap.all[self.id] = self
|
||||
Cap.tiles[self.id] = self
|
||||
Cap.save()
|
||||
Cap.updateMosaicWithNewCap(id: self.id, image)
|
||||
Cap.delegate?.capHasUpdates(self)
|
||||
Cap.all[self.id] = self
|
||||
Cap.tiles[self.id] = self
|
||||
Cap.shouldCreateFolderForCap(self.id)
|
||||
Cap.save()
|
||||
Cap.delegate?.capHasUpdates(self)
|
||||
//Cap.updateMosaicWithNewCap(id: self.id, image)
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
self.add(image: image) { _ in
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,7 +302,7 @@ final class Cap {
|
||||
}
|
||||
|
||||
func add(image: UIImage, completion: @escaping (Bool) -> Void) {
|
||||
upload(image: image) { saved in
|
||||
self.upload(image: image) { saved in
|
||||
guard saved else {
|
||||
completion(false)
|
||||
return
|
||||
@ -311,14 +314,7 @@ final class Cap {
|
||||
}
|
||||
|
||||
// MARK: - Image upload
|
||||
|
||||
private func upload(mainImage: UIImage, completion: @escaping (_ success: Bool) -> Void) {
|
||||
self.createFolder { created in
|
||||
guard created else { return }
|
||||
self.upload(image: mainImage, number: 0, savedCallback: completion)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func folderExists(completion: @escaping (_ exists: Bool?) -> Void) {
|
||||
let path = "/Images"
|
||||
DropboxController.client.files.listFolder(path: path).response { response, error in
|
||||
@ -338,15 +334,20 @@ final class Cap {
|
||||
}
|
||||
}
|
||||
|
||||
private func createFolder(completion: @escaping (_ success: Bool) -> Void) {
|
||||
private static func createFolder(forCap cap: Int, completion: @escaping (_ success: Bool) -> Void) {
|
||||
guard shouldCreateFolder(forCap: cap) else {
|
||||
completion(true)
|
||||
return
|
||||
}
|
||||
// Create folder for cap
|
||||
let path = "/Images/\(id)"
|
||||
let path = "/Images/\(cap)"
|
||||
DropboxController.client.files.createFolderV2(path: path).response { _, error in
|
||||
if let err = error {
|
||||
self.event("Could not create folder for new cap \(self.id): \(err)")
|
||||
self.event("Could not create folder for cap \(cap): \(err)")
|
||||
completion(false)
|
||||
} else {
|
||||
self.event("Created folder for new cap \(self.id)")
|
||||
self.event("Created folder for cap \(cap)")
|
||||
didCreateFolder(forCap: cap)
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
@ -372,13 +373,19 @@ final class Cap {
|
||||
event("Saved image \(number) for cap \(id) for upload")
|
||||
savedCallback(true)
|
||||
|
||||
Cap.upload(url: url) { success in
|
||||
Cap.uploadCapImage(at: url, forCap: id) { success in
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static func upload(url: URL, completion: @escaping (Bool) -> Void) {
|
||||
let cap = Int(url.lastPathComponent.components(separatedBy: "-").first!)!
|
||||
private static func uploadCapImage(at url: URL, forCap cap: Int, completion: @escaping (Bool) -> Void) {
|
||||
createFolder(forCap: cap) { created in
|
||||
guard created else { return }
|
||||
uploadCapImage(at: url, forCapWithExistingFolder: cap, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
private static func uploadCapImage(at url: URL, forCapWithExistingFolder cap: Int, completion: @escaping (Bool) -> Void) {
|
||||
let path = "/Images/\(cap)/" + url.lastPathComponent
|
||||
|
||||
let data: Data
|
||||
@ -417,7 +424,8 @@ final class Cap {
|
||||
event("\(list.count) image uploads pending")
|
||||
|
||||
for url in list {
|
||||
upload(url: url) { didUpload in
|
||||
let cap = Int(url.lastPathComponent.components(separatedBy: "-").first!)!
|
||||
uploadCapImage(at: url, forCap: cap) { didUpload in
|
||||
// Delete image from disk if uploaded
|
||||
guard didUpload else {
|
||||
self.error("Could not upload image at url \(url)")
|
||||
@ -505,9 +513,6 @@ final class Cap {
|
||||
return
|
||||
}
|
||||
self.readNames(from: lines)
|
||||
DispatchQueue.main.async {
|
||||
createAndSaveMosaic()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,150 +556,27 @@ final class Cap {
|
||||
return capList(sortedBy: .id, ascending: true).reduce("") { $0 + $1.description }
|
||||
}
|
||||
|
||||
// MARK: - GridView
|
||||
// MARK: - Folders to upload
|
||||
|
||||
private static func size(for tiles: Int) -> CGSize {
|
||||
let columns = CGFloat(mosaicColumns)
|
||||
// Add half of a cell due to row shift
|
||||
let width = (columns + 0.5) * mosaicCellSize
|
||||
let rows = (CGFloat(tiles) / columns).rounded(.up)
|
||||
// Add margin because the last row does not overlap
|
||||
let height = rows * mosaicRowHeight + mosaicMargin
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
static func origin(for tile: Int) -> CGPoint {
|
||||
let row = tile / mosaicColumns
|
||||
let column = tile - row * mosaicColumns
|
||||
let x = ( CGFloat(column) + (row.isEven ? 0 : 0.5) ) * mosaicCellSize
|
||||
let y = CGFloat(row) * mosaicRowHeight
|
||||
return CGPoint(x: x, y: y)
|
||||
}
|
||||
|
||||
private static func makeTile(_ tile: Int, image: UIImage) -> RoundedImageView {
|
||||
let point = origin(for: tile)
|
||||
let frame = CGRect(origin: point, size: CGSize(width: mosaicCellSize, height: mosaicCellSize))
|
||||
let view = RoundedImageView(frame: frame)
|
||||
view.image = image
|
||||
return view
|
||||
}
|
||||
|
||||
private static func makeMosaicCanvas() -> UIView {
|
||||
let view = UIView(frame: CGRect(origin: .zero, size: size(for: Cap.totalCapCount)))
|
||||
view.backgroundColor = UIColor(red: 36/255, green: 36/255, blue: 36/255, alpha: 1)
|
||||
return view
|
||||
}
|
||||
|
||||
private static func makeMosaic() -> UIImage? {
|
||||
let canvas = makeMosaicCanvas()
|
||||
|
||||
for cap in Cap.all.values {
|
||||
if let img = cap.image {
|
||||
let view = makeTile(cap.id - 1, image: img)
|
||||
canvas.addSubview(view)
|
||||
} else {
|
||||
error("No image for cap \(cap.id)")
|
||||
}
|
||||
}
|
||||
return render(view: canvas)
|
||||
}
|
||||
|
||||
private static func render(view: UIView) -> UIImage? {
|
||||
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0)
|
||||
defer { UIGraphicsEndImageContext() }
|
||||
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
|
||||
return UIGraphicsGetImageFromCurrentImageContext()
|
||||
}
|
||||
|
||||
private static func createAndSaveMosaic() {
|
||||
guard !DiskManager.mosaicExists else {
|
||||
event("Mosaic already created")
|
||||
static func shouldCreateFolderForCap(_ cap: Int) {
|
||||
let oldCaps = Persistence.folderNotCreated
|
||||
guard !oldCaps.contains(cap) else {
|
||||
return
|
||||
}
|
||||
updateMosaic()
|
||||
let newCaps = oldCaps + [cap]
|
||||
Persistence.folderNotCreated = newCaps
|
||||
}
|
||||
|
||||
static var mosaic: UIImage? {
|
||||
guard let data = DiskManager.mosaicData else {
|
||||
error("No mosaic data on disk")
|
||||
return nil
|
||||
}
|
||||
guard let image = UIImage(data: data, scale: UIScreen.main.scale) else {
|
||||
error("Failed to create image from mosaic data")
|
||||
return nil
|
||||
}
|
||||
return image
|
||||
static func shouldCreateFolder(forCap cap: Int) -> Bool {
|
||||
return Persistence.folderNotCreated.contains(cap)
|
||||
}
|
||||
|
||||
private static func updateMosaicWithNewCap(id: Int, _ image: UIImage) {
|
||||
guard let old = mosaic else { return }
|
||||
|
||||
let view = UIImageView(image: old)
|
||||
let canvas = makeMosaicCanvas()
|
||||
let tile = makeTile(id - 1, image: image)
|
||||
canvas.addSubview(view)
|
||||
canvas.addSubview(tile)
|
||||
guard let img = render(view: canvas) else {
|
||||
error("Failed to update mosaic for cap \(id)")
|
||||
static func didCreateFolder(forCap cap: Int) {
|
||||
let oldCaps = Persistence.folderNotCreated
|
||||
guard oldCaps.contains(cap) else {
|
||||
return
|
||||
}
|
||||
saveMosaic(img)
|
||||
}
|
||||
|
||||
static func tile(for point: CGPoint) -> Int? {
|
||||
let s = point.y.truncatingRemainder(dividingBy: mosaicRowHeight)
|
||||
let row = Int(point.y / mosaicRowHeight)
|
||||
guard s > mosaicMargin else {
|
||||
return nil
|
||||
}
|
||||
let column: CGFloat
|
||||
if row.isEven {
|
||||
column = point.x / mosaicCellSize
|
||||
} else {
|
||||
column = (point.x - mosaicCellSize / 2) / mosaicCellSize
|
||||
}
|
||||
return row * mosaicColumns + Int(column)
|
||||
}
|
||||
|
||||
static func switchTilesInMosaic(_ mosaic: UIImageView, tile1: Int, tile2: Int) {
|
||||
let tileView1 = makeTile(tile1, image: Cap.tileImage(tile: tile1)!)
|
||||
let tileView2 = makeTile(tile2, image: Cap.tileImage(tile: tile2)!)
|
||||
|
||||
|
||||
mosaic.addSubview(tileView1)
|
||||
mosaic.addSubview(tileView2)
|
||||
defer {
|
||||
tileView1.removeFromSuperview()
|
||||
tileView2.removeFromSuperview()
|
||||
}
|
||||
|
||||
guard let img = render(view: mosaic) else {
|
||||
error("Failed to switch \(tile1) and \(tile2) in mosaic")
|
||||
return
|
||||
}
|
||||
|
||||
mosaic.image = img
|
||||
saveMosaic(img)
|
||||
}
|
||||
|
||||
static func updateMosaic() {
|
||||
guard let image = makeMosaic() else {
|
||||
error("No mosaik image created")
|
||||
return
|
||||
}
|
||||
saveMosaic(image)
|
||||
}
|
||||
|
||||
static func saveMosaic(_ image: UIImage) {
|
||||
guard let data = image.pngData() else {
|
||||
error("Failed to convert mosaic to data")
|
||||
return
|
||||
}
|
||||
guard DiskManager.saveMosaicData(data) else {
|
||||
error("Failed to write mosaic to disk")
|
||||
return
|
||||
}
|
||||
event("Mosaic saved")
|
||||
Persistence.folderNotCreated = oldCaps.filter { $0 != cap }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,4 +75,13 @@ final class Persistence {
|
||||
UserDefaults.standard.set(newValue, forKey: "xcode")
|
||||
}
|
||||
}
|
||||
|
||||
static var folderNotCreated: [Int] {
|
||||
get {
|
||||
return UserDefaults.standard.array(forKey: "folders") as? [Int] ?? []
|
||||
}
|
||||
set {
|
||||
UserDefaults.standard.set(newValue, forKey: "folders")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user