2019-03-15 13:19:19 +01:00
|
|
|
//
|
|
|
|
// Cap.swift
|
|
|
|
// CapCollector
|
|
|
|
//
|
|
|
|
// Created by Christoph on 19.11.18.
|
|
|
|
// Copyright © 2018 CH. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import UIKit
|
2019-07-17 11:10:07 +02:00
|
|
|
import CoreImage
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
import SQLite
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
struct Cap {
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
// MARK: - Static constants
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
static let sufficientImageCount = 10
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
static let imageWidth = 299 // New for XCode models, 227/229 for turicreate
|
|
|
|
|
|
|
|
static let imageSize = CGSize(width: imageWidth, height: imageWidth)
|
2019-03-15 13:19:19 +01:00
|
|
|
|
|
|
|
static let jpgQuality: CGFloat = 0.3
|
|
|
|
|
|
|
|
private static let mosaicColumns = 40
|
|
|
|
|
|
|
|
static let mosaicCellSize: CGFloat = 60
|
|
|
|
|
|
|
|
private static let mosaicRowHeight = mosaicCellSize * 0.866
|
|
|
|
|
|
|
|
private static let mosaicMargin = mosaicCellSize - mosaicRowHeight
|
|
|
|
|
|
|
|
// MARK: - Variables
|
|
|
|
|
|
|
|
/// The unique number of the cap
|
|
|
|
let id: Int
|
|
|
|
|
|
|
|
/// The name of the cap
|
2020-05-16 11:21:55 +02:00
|
|
|
let name: String
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
/// The name of the cap without special characters
|
|
|
|
let cleanName: String
|
2019-03-15 13:19:19 +01:00
|
|
|
|
|
|
|
/// The number of images existing for the cap
|
2020-05-16 11:21:55 +02:00
|
|
|
let count: Int
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
/// Indicate if the cap can be found by the recognition model
|
|
|
|
let matched: Bool
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
/// Indicate if the cap is present on the server
|
|
|
|
let uploaded: Bool
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
// MARK: Init
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
init(name: String, id: Int) {
|
2020-05-16 11:21:55 +02:00
|
|
|
self.id = id
|
|
|
|
self.count = 1
|
|
|
|
self.name = name
|
|
|
|
self.cleanName = ""
|
|
|
|
self.matched = false
|
|
|
|
self.uploaded = false
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
init(id: Int, name: String, count: Int) {
|
|
|
|
self.id = id
|
|
|
|
self.name = name
|
|
|
|
self.count = count
|
|
|
|
self.cleanName = name.clean
|
|
|
|
self.matched = false
|
|
|
|
self.uploaded = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func renamed(to name: String) -> Cap {
|
|
|
|
Cap(from: self, renamed: name)
|
|
|
|
}
|
|
|
|
|
|
|
|
init(from cap: Cap, renamed newName: String) {
|
|
|
|
self.id = cap.id
|
|
|
|
self.count = cap.count
|
|
|
|
self.name = newName
|
|
|
|
self.cleanName = newName.clean
|
|
|
|
self.matched = cap.matched
|
|
|
|
self.uploaded = cap.uploaded
|
|
|
|
}
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
// MARK: SQLite
|
2019-07-17 11:10:07 +02:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
init(row: Row) {
|
|
|
|
self.id = row[Cap.columnId]
|
|
|
|
self.name = row[Cap.columnName]
|
|
|
|
self.count = row[Cap.columnCount]
|
|
|
|
self.cleanName = name.clean
|
|
|
|
self.matched = row[Cap.columnMatched]
|
|
|
|
self.uploaded = row[Cap.columnUploaded]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
static let table = Table("data")
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
static var createQuery: String {
|
2020-05-16 11:21:55 +02:00
|
|
|
table.create(ifNotExists: true) { t in
|
2020-06-18 22:55:51 +02:00
|
|
|
t.column(columnId, primaryKey: true)
|
|
|
|
t.column(columnName)
|
|
|
|
t.column(columnCount)
|
|
|
|
t.column(columnMatched)
|
|
|
|
t.column(columnUploaded)
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
2020-06-18 22:55:51 +02:00
|
|
|
}
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
static let columnId = Expression<Int>("id")
|
2019-07-17 11:10:07 +02:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
static let columnName = Expression<String>("name")
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
static let columnCount = Expression<Int>("count")
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
static let columnMatched = Expression<Bool>("matched")
|
2019-03-15 13:19:19 +01:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
static let columnUploaded = Expression<Bool>("uploaded")
|
2019-07-17 11:10:07 +02:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
var insertQuery: Insert {
|
|
|
|
return Cap.table.insert(
|
2020-06-18 22:55:51 +02:00
|
|
|
Cap.columnId <- id,
|
|
|
|
Cap.columnName <- name,
|
|
|
|
Cap.columnCount <- count,
|
|
|
|
Cap.columnMatched <- matched,
|
|
|
|
Cap.columnUploaded <- uploaded)
|
2019-07-17 11:10:07 +02:00
|
|
|
}
|
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
// MARK: Display
|
2019-07-17 11:10:07 +02:00
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
func matchLabelText(match: Float?, appIsUnlocked: Bool) -> String {
|
|
|
|
if let match = match {
|
|
|
|
let percent = Int((match * 100).rounded())
|
|
|
|
return String(format: "%d %%", arguments: [percent])
|
|
|
|
}
|
|
|
|
|
|
|
|
guard matched else {
|
|
|
|
return "📵"
|
|
|
|
}
|
|
|
|
guard appIsUnlocked, !hasSufficientImages else {
|
|
|
|
return ""
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
2020-06-18 22:55:51 +02:00
|
|
|
return "⚠️"
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
func countLabelText(appIsUnlocked: Bool) -> String {
|
|
|
|
guard appIsUnlocked else {
|
|
|
|
return "\(id)"
|
|
|
|
}
|
2020-05-16 11:21:55 +02:00
|
|
|
guard count != 1 else {
|
|
|
|
return "\(id) (1 image)"
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
2020-05-16 11:21:55 +02:00
|
|
|
return "\(id) (\(count) images)"
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
|
2020-06-18 22:55:51 +02:00
|
|
|
// MARK: Images
|
2020-05-16 11:21:55 +02:00
|
|
|
|
|
|
|
var hasSufficientImages: Bool {
|
2020-06-18 22:55:51 +02:00
|
|
|
count >= Cap.sufficientImageCount
|
2019-04-12 13:46:18 +02:00
|
|
|
}
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
static func thumbnail(for image: UIImage) -> UIImage {
|
|
|
|
let len = GridViewController.len * 2
|
|
|
|
return image.resize(to: CGSize.init(width: len, height: len))
|
2019-03-15 13:19:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Protocol Hashable
|
|
|
|
|
|
|
|
extension Cap: Hashable {
|
|
|
|
|
|
|
|
static func == (lhs: Cap, rhs: Cap) -> Bool {
|
|
|
|
return lhs.id == rhs.id
|
|
|
|
}
|
|
|
|
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
|
|
hasher.combine(id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Protocol Logger
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
extension Cap: Logger { }
|
2019-03-15 13:19:19 +01:00
|
|
|
|
|
|
|
// MARK: - String extension
|
|
|
|
|
|
|
|
extension String {
|
2020-06-18 22:55:51 +02:00
|
|
|
|
2019-03-15 13:19:19 +01:00
|
|
|
var clean: String {
|
|
|
|
return lowercased().replacingOccurrences(of: "[^a-z0-9 ]", with: "", options: .regularExpression)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Int extension
|
|
|
|
|
|
|
|
private extension Int {
|
|
|
|
|
|
|
|
var isEven: Bool {
|
|
|
|
return self % 2 == 0
|
|
|
|
}
|
|
|
|
}
|