Caps-iOS/CapCollector/Data/Cap.swift

204 lines
4.7 KiB
Swift
Raw Normal View History

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
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
// 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
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
}
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
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
static var createQuery: String {
2020-05-16 11:21:55 +02:00
table.create(ifNotExists: true) { t in
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
}
}
2019-03-15 13:19:19 +01:00
static let columnId = Expression<Int>("id")
static let columnName = Expression<String>("name")
2019-03-15 13:19:19 +01:00
static let columnCount = Expression<Int>("count")
2019-03-15 13:19:19 +01:00
static let columnMatched = Expression<Bool>("matched")
2019-03-15 13:19:19 +01:00
static let columnUploaded = Expression<Bool>("uploaded")
2020-05-16 11:21:55 +02:00
var insertQuery: Insert {
return Cap.table.insert(
Cap.columnId <- id,
Cap.columnName <- name,
Cap.columnCount <- count,
Cap.columnMatched <- matched,
Cap.columnUploaded <- uploaded)
}
// MARK: Display
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
}
return "⚠️"
2019-03-15 13:19:19 +01: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
}
// MARK: Images
2020-05-16 11:21:55 +02:00
var hasSufficientImages: Bool {
count >= Cap.sufficientImageCount
}
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 {
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
}
}