Caps-iOS/CapCollector/Presentation/SettingsController.swift
2019-04-12 13:45:31 +02:00

252 lines
7.7 KiB
Swift

//
// SettingsController.swift
// CapCollector
//
// Created by Christoph on 15.10.18.
// Copyright © 2018 CH. All rights reserved.
//
import UIKit
class SettingsController: UITableViewController {
@IBOutlet weak var totalCapsLabel: UILabel!
@IBOutlet weak var totalImagesLabel: UILabel!
@IBOutlet weak var recognizedCapsLabel: UILabel!
@IBOutlet weak var imagesStatsLabel: UILabel!
@IBOutlet weak var databaseUpdatesLabel: UILabel!
@IBOutlet weak var dropboxAccountLabel: UILabel!
@IBOutlet weak var countsLabel: UILabel!
private var nameFileChanges = false
private var isUpdatingCounts = false
private var isUpdatingThumbnails = false
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
updateDropboxStatus()
updateNameFileStats()
updateDatabaseStats()
(navigationController as! NavigationController).allowLandscape = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setAccessories()
}
private func updateThumbnails() {
isUpdatingThumbnails = true
for cap in Cap.all.values {
cap.makeThumbnail()
}
isUpdatingThumbnails = false
}
private func updateDatabaseStats() {
let totalCaps = Cap.totalCapCount
totalCapsLabel.text = "\(totalCaps) caps"
totalImagesLabel.text = "\(Cap.imageCount) images"
let recognizedCaps = Persistence.recognizedCapCount
let newCapCount = totalCaps - recognizedCaps
recognizedCapsLabel.text = "\(newCapCount) new caps"
let ratio = Float(Cap.imageCount)/Float(Cap.totalCapCount)
let (images, count) = Cap.getCapStatistics().enumerated().first(where: { $0.element != 0 })!
imagesStatsLabel.text = String(format: "%.2f images per cap, lowest count: %d (%dx)", ratio, images, count)
}
private func updateNameFileStats() {
let capCount = Cap.totalCapCount - Persistence.lastUploadedCapCount
let imageCount = Cap.imageCount - Persistence.lastUploadedImageCount
nameFileChanges = capCount > 0 || imageCount > 0
databaseUpdatesLabel.text = "\(capCount) new caps and \(imageCount) new images"
}
private func updateDropboxStatus() {
dropboxAccountLabel.text = DropboxController.shared.isEnabled ? "Sign out" : "Sign in"
}
private func setAccessories() {
tableView.cellForRow(at: IndexPath(row: 0, section: 2))?.accessoryType = Persistence.squeezenet ? .checkmark : .none
tableView.cellForRow(at: IndexPath(row: 1, section: 2))?.accessoryType = Persistence.resnet ? .checkmark : .none
tableView.cellForRow(at: IndexPath(row: 2, section: 2))?.accessoryType = Persistence.xcode ? .checkmark : .none
}
private func toggleClassifier(index: Int) {
switch index {
case 0: Persistence.squeezenet = !Persistence.squeezenet
case 1: Persistence.resnet = !Persistence.resnet
case 2: Persistence.xcode = !Persistence.xcode
default:
return
}
setAccessories()
}
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
switch indexPath.section {
case 0: // Mosaic
return true
case 1: // Database
return indexPath.row == 2 && nameFileChanges
case 2: // Choose models
return true
case 3: // Refresh
if indexPath.row == 0 {
return !isUpdatingCounts
} else {
return !isUpdatingThumbnails
}
case 4: // Dropbox account
return true
case 5: // Log file
return true
default: return false
}
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
switch indexPath.section {
case 0: // Mosaic
return indexPath
case 1: // Database
return (indexPath.row == 2 && nameFileChanges) ? indexPath : nil
case 2: // Choose models
return indexPath
case 3: // Refresh count
if indexPath.row == 0 {
return isUpdatingCounts ? nil : indexPath
} else {
return isUpdatingThumbnails ? nil : indexPath
}
case 4: // Dropbox account
return indexPath
case 5: // Log file
return indexPath
default: return nil
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch indexPath.section {
case 1: // Upload
if indexPath.row == 2 && nameFileChanges {
uploadNameFile()
}
case 2: // Choose models
toggleClassifier(index: indexPath.row)
case 3: // Refresh count
if indexPath.row == 0 {
updateCounts()
} else {
updateThumbnails()
}
default:
break
}
}
private func updateCounts() {
isUpdatingCounts = true
Cap.shouldSave = false
// TODO: Don't make all requests at the same time
DispatchQueue.global(qos: .userInitiated).async {
let list = Cap.all.keys.sorted()
let total = list.count
var finished = 0
let chunks = list.chunked(into: 10)
for chunk in chunks {
self.updateCounts(ids: chunk)
finished += 10
DispatchQueue.main.async {
self.countsLabel.text = "\(finished) / \(total) finished"
}
}
self.isUpdatingCounts = false
Cap.shouldSave = true
DispatchQueue.main.async {
self.countsLabel.text = "Refresh image counts"
self.updateDatabaseStats()
}
}
}
private func updateCounts(ids: [Int]) {
var count = ids.count
let s = DispatchSemaphore(value: 0)
for cap in ids {
Cap.all[cap]!.updateCount { _ in
count -= 1
if count == 0 {
s.signal()
}
}
}
_ = s.wait(timeout: .now() + .seconds(30))
event("Finished updating ids \(ids.first!) to \(ids.last!)")
}
private func uploadNameFile() {
Cap.saveAndUpload() { _ in
self.updateNameFileStats()
}
}
private func toggleDropbox() {
guard !DropboxController.shared.isEnabled else {
DropboxController.shared.signOut()
updateDropboxStatus()
return
}
DropboxController.shared.setup(in: self)
updateDropboxStatus()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let id = segue.identifier else {
return
}
switch id {
case "showMosaic":
(navigationController as! NavigationController).allowLandscape = true
case "showLog":
return
default:
return
}
}
}
extension SettingsController: Logger {
static let logToken = "[Settings]"
}
private extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}