diff --git a/CapCollector/Data/Cap.swift b/CapCollector/Data/Cap.swift index 007efcc..a61492c 100644 --- a/CapCollector/Data/Cap.swift +++ b/CapCollector/Data/Cap.swift @@ -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 } } } diff --git a/CapCollector/Data/UserDefaults.swift b/CapCollector/Data/UserDefaults.swift index a265d14..5964271 100644 --- a/CapCollector/Data/UserDefaults.swift +++ b/CapCollector/Data/UserDefaults.swift @@ -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") + } + } }