2019-03-15 13:19:19 +01:00
|
|
|
//
|
|
|
|
// 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 isUpdatingCounts = false
|
|
|
|
|
2019-07-17 11:10:07 +02:00
|
|
|
private var isUploadingNameFile = false
|
|
|
|
|
2019-03-15 13:19:19 +01:00
|
|
|
private var isUpdatingThumbnails = false
|
|
|
|
|
2019-07-17 11:10:07 +02:00
|
|
|
private var isUpdatingColors = false
|
|
|
|
|
2019-03-15 13:19:19 +01:00
|
|
|
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
|
|
|
return .portrait
|
|
|
|
}
|
|
|
|
|
|
|
|
override func viewDidLoad() {
|
|
|
|
super.viewDidLoad()
|
|
|
|
}
|
2019-07-17 11:10:07 +02:00
|
|
|
|
2019-03-15 13:19:19 +01:00
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
|
|
updateDropboxStatus()
|
|
|
|
updateNameFileStats()
|
|
|
|
updateDatabaseStats()
|
|
|
|
|
|
|
|
(navigationController as! NavigationController).allowLandscape = false
|
|
|
|
}
|
|
|
|
|
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
|
|
super.viewDidAppear(animated)
|
2019-07-17 11:10:07 +02:00
|
|
|
setClassifierChoice(Persistence.useMobileNet)
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private func updateThumbnails() {
|
|
|
|
isUpdatingThumbnails = true
|
|
|
|
for cap in Cap.all.values {
|
|
|
|
cap.makeThumbnail()
|
|
|
|
}
|
|
|
|
isUpdatingThumbnails = false
|
|
|
|
}
|
|
|
|
|
2019-07-17 11:10:07 +02:00
|
|
|
private func updateColors() {
|
|
|
|
isUpdatingColors = true
|
|
|
|
Cap.shouldSave = false
|
|
|
|
for cap in Cap.all.values {
|
|
|
|
cap.makeAverageColor()
|
|
|
|
}
|
|
|
|
Cap.shouldSave = true
|
|
|
|
isUpdatingColors = false
|
|
|
|
}
|
|
|
|
|
2019-03-15 13:19:19 +01:00
|
|
|
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
|
|
|
|
databaseUpdatesLabel.text = "\(capCount) new caps and \(imageCount) new images"
|
|
|
|
}
|
|
|
|
|
|
|
|
private func updateDropboxStatus() {
|
|
|
|
dropboxAccountLabel.text = DropboxController.shared.isEnabled ? "Sign out" : "Sign in"
|
|
|
|
}
|
|
|
|
|
2019-07-17 11:10:07 +02:00
|
|
|
private func setClassifierChoice(_ useMobileNet: Bool) {
|
|
|
|
tableView.cellForRow(at: IndexPath(row: 0, section: 0))?.accessoryType = useMobileNet ? .checkmark : .none
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
|
2019-07-17 11:10:07 +02:00
|
|
|
private func toggleClassifier() {
|
|
|
|
let newValue = !Persistence.useMobileNet
|
|
|
|
Persistence.useMobileNet = newValue
|
|
|
|
setClassifierChoice(newValue)
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
|
|
|
|
switch indexPath.section {
|
2019-07-17 11:10:07 +02:00
|
|
|
case 0: // Choose models
|
2019-03-15 13:19:19 +01:00
|
|
|
return true
|
2019-07-17 11:10:07 +02:00
|
|
|
case 1: // Mosaic
|
2019-03-15 13:19:19 +01:00
|
|
|
return true
|
2019-07-17 11:10:07 +02:00
|
|
|
case 2: // Database
|
|
|
|
return indexPath.row == 2 && !isUploadingNameFile
|
2019-03-15 13:19:19 +01:00
|
|
|
case 3: // Refresh
|
2019-07-17 11:10:07 +02:00
|
|
|
switch indexPath.row {
|
|
|
|
case 0:
|
2019-03-15 13:19:19 +01:00
|
|
|
return !isUpdatingCounts
|
2019-07-17 11:10:07 +02:00
|
|
|
case 1:
|
2019-03-15 13:19:19 +01:00
|
|
|
return !isUpdatingThumbnails
|
2019-07-17 11:10:07 +02:00
|
|
|
case 2:
|
|
|
|
return !isUpdatingColors
|
|
|
|
default:
|
|
|
|
return false
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
case 4: // Dropbox account
|
|
|
|
return true
|
2019-04-12 13:45:31 +02:00
|
|
|
case 5: // Log file
|
|
|
|
return true
|
2019-03-15 13:19:19 +01:00
|
|
|
default: return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
|
|
|
switch indexPath.section {
|
2019-07-17 11:10:07 +02:00
|
|
|
case 0: // Choose models
|
2019-03-15 13:19:19 +01:00
|
|
|
return indexPath
|
2019-07-17 11:10:07 +02:00
|
|
|
case 1: // Mosaic
|
2019-03-15 13:19:19 +01:00
|
|
|
return indexPath
|
2019-07-17 11:10:07 +02:00
|
|
|
case 2: // Database
|
|
|
|
return (indexPath.row == 2 && !isUploadingNameFile) ? indexPath : nil
|
2019-03-15 13:19:19 +01:00
|
|
|
case 3: // Refresh count
|
2019-07-17 11:10:07 +02:00
|
|
|
switch indexPath.row {
|
|
|
|
case 0:
|
|
|
|
return isUpdatingCounts ? nil : indexPath
|
|
|
|
case 1:
|
2019-03-15 13:19:19 +01:00
|
|
|
return isUpdatingThumbnails ? nil : indexPath
|
2019-07-17 11:10:07 +02:00
|
|
|
case 2:
|
|
|
|
return isUpdatingColors ? nil : indexPath
|
|
|
|
default:
|
|
|
|
return nil
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
case 4: // Dropbox account
|
|
|
|
return indexPath
|
2019-04-12 13:45:31 +02:00
|
|
|
case 5: // Log file
|
|
|
|
return indexPath
|
2019-03-15 13:19:19 +01:00
|
|
|
default: return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
|
|
tableView.deselectRow(at: indexPath, animated: true)
|
|
|
|
switch indexPath.section {
|
2019-07-17 11:10:07 +02:00
|
|
|
case 0: // Choose models
|
|
|
|
toggleClassifier()
|
|
|
|
case 2: // Upload
|
|
|
|
if indexPath.row == 2 && !isUploadingNameFile {
|
2019-03-15 13:19:19 +01:00
|
|
|
uploadNameFile()
|
|
|
|
}
|
|
|
|
case 3: // Refresh count
|
2019-07-17 11:10:07 +02:00
|
|
|
switch indexPath.row {
|
|
|
|
case 0:
|
2019-03-15 13:19:19 +01:00
|
|
|
updateCounts()
|
2019-07-17 11:10:07 +02:00
|
|
|
case 1:
|
2019-03-15 13:19:19 +01:00
|
|
|
updateThumbnails()
|
2019-07-17 11:10:07 +02:00
|
|
|
case 2:
|
|
|
|
updateColors()
|
|
|
|
default:
|
|
|
|
break
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
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() {
|
2019-07-17 11:10:07 +02:00
|
|
|
event("Uploading name file")
|
|
|
|
isUploadingNameFile = true
|
2019-03-15 13:19:19 +01:00
|
|
|
Cap.saveAndUpload() { _ in
|
2019-07-17 11:10:07 +02:00
|
|
|
self.isUploadingNameFile = false
|
2019-03-15 13:19:19 +01:00
|
|
|
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?) {
|
2019-04-12 13:45:31 +02:00
|
|
|
guard let id = segue.identifier else {
|
2019-03-15 13:19:19 +01:00
|
|
|
return
|
|
|
|
}
|
2019-04-12 13:45:31 +02:00
|
|
|
switch id {
|
|
|
|
case "showMosaic":
|
|
|
|
(navigationController as! NavigationController).allowLandscape = true
|
|
|
|
case "showLog":
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|