275 lines
15 KiB
Swift
275 lines
15 KiB
Swift
import UIKit
|
|
import Kingfisher
|
|
import AutoCatCore
|
|
|
|
extension Vehicle {
|
|
func drawLine(y: CGFloat, width: CGFloat, margin: CGFloat = 15,context: CGContext) {
|
|
let lineWidth = 1/UIScreen.main.scale
|
|
context.move(to: CGPoint(x: margin, y: y + lineWidth/2))
|
|
context.addLine(to: CGPoint(x: width, y: y + lineWidth/2))
|
|
context.closePath()
|
|
context.setLineWidth(lineWidth)
|
|
context.setStrokeColor(UIColor.opaqueSeparator.cgColor)
|
|
context.strokePath()
|
|
}
|
|
|
|
func drawCell(y: CGFloat, width: CGFloat, height: CGFloat, title: String, value: String, lineMargin: CGFloat = 15, context: CGContext) {
|
|
let fontSize: CGFloat = 17
|
|
let font = UIFont.systemFont(ofSize: fontSize)
|
|
let offest = (height - fontSize)/2
|
|
let pStyle = NSMutableParagraphStyle()
|
|
pStyle.alignment = .right
|
|
let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.label]
|
|
let valueAttributs: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: UIColor.secondaryLabel, .paragraphStyle: pStyle]
|
|
let rect = CGRect(x: 15, y: y + offest, width: width - 30, height: height)
|
|
UIColor.secondarySystemGroupedBackground.setFill()
|
|
UIRectFill(CGRect(x: 0, y: y, width: width, height: height))
|
|
title.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
|
|
value.draw(with: rect, options: .usesLineFragmentOrigin, attributes: valueAttributs, context: nil)
|
|
self.drawLine(y: y + height - 1/UIScreen.main.scale, width: width, margin: lineMargin, context: context)
|
|
}
|
|
|
|
func drawBigTextCell(y: CGFloat, width: CGFloat, title: String, value: String, lineMargin: CGFloat = 15, context: CGContext) -> CGFloat {
|
|
let pStyle = NSMutableParagraphStyle()
|
|
pStyle.alignment = .right
|
|
let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 17), .foregroundColor: UIColor.label]
|
|
let valueAttributs: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 15), .foregroundColor: UIColor.secondaryLabel, .paragraphStyle: pStyle]
|
|
UIColor.secondarySystemGroupedBackground.setFill()
|
|
|
|
let text = NSMutableAttributedString(string: title + " - " + value)
|
|
text.setAttributes(attributes, range: NSRange(location: 0, length: title.count))
|
|
text.setAttributes(valueAttributs, range: NSRange(location: title.count, length: value.count + 3))
|
|
let textRect = text.boundingRect(with: CGSize(width: width - 30, height: 1000), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
|
|
let height = textRect.size.height > 28 ? textRect.size.height + 16 : 44
|
|
let offset = (height - textRect.size.height)/2
|
|
let rect = CGRect(x: 15, y: y + offset, width: width - 30, height: height)
|
|
UIRectFill(CGRect(x: 0, y: y, width: width, height: height))
|
|
text.draw(with: rect, options: .usesLineFragmentOrigin, context: nil)
|
|
self.drawLine(y: y + height - 1/UIScreen.main.scale, width: width, margin: lineMargin, context: context)
|
|
|
|
return height
|
|
}
|
|
|
|
func reportImage(width: CGFloat) -> UIImage {
|
|
var realHeight: CGFloat = 0
|
|
let rect = CGRect(origin: .zero, size: CGSize(width: width, height: CGFloat(10000)))
|
|
let renderer = UIGraphicsImageRenderer(bounds: rect)
|
|
let image = renderer.image { rendererContext in
|
|
let cellHeight: CGFloat = 44
|
|
let ctx = rendererContext.cgContext
|
|
let centeredStyle = NSMutableParagraphStyle()
|
|
centeredStyle.alignment = .center
|
|
let titleAttributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 20), .paragraphStyle: centeredStyle, .foregroundColor: UIColor.label]
|
|
let headerAttributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 13), .foregroundColor: UIColor.secondaryLabel]
|
|
|
|
let w: CGFloat = width
|
|
var y: CGFloat = 0
|
|
|
|
UIColor.systemGroupedBackground.setFill()
|
|
UIRectFill(rect)
|
|
|
|
y += 12
|
|
"\(self.brand?.name?.original ?? "Unknown model") (\(self.getNumber()))".draw(with: CGRect(x: 0, y: y, width: w, height: 30), options: .usesLineFragmentOrigin, attributes: titleAttributes, context: nil)
|
|
y += 50
|
|
"GENERAL".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
|
y += 24
|
|
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
|
y += 1/UIScreen.main.scale
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Year", value: String(self.year), context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Color", value: self.color ?? "<unknown>", context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Category", value: self.category ?? "<unknown>", context: ctx)
|
|
y += cellHeight
|
|
var position = "Unknown"
|
|
if let rightWheel = self.isRightWheel {
|
|
position = rightWheel ? "Right" : "Left"
|
|
}
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Steering wheel position", value: position, context: ctx)
|
|
y += cellHeight
|
|
var japanese = "<Unknown>"
|
|
if let isJapanese = self.isJapanese {
|
|
japanese = isJapanese ? "Yes" : "No"
|
|
}
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Japanese", value: japanese, lineMargin: 0, context: ctx)
|
|
y += cellHeight + 32
|
|
|
|
"IDENTIFIERS".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
|
y += 24
|
|
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
|
y += 1/UIScreen.main.scale
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Plate number", value: self.getNumber(), context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "VIN", value: self.vin1 ?? "<unknown>", context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "STS", value: self.sts ?? "<unknown>", context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "PTS", value: self.pts ?? "<unknown>", context: ctx)
|
|
y += cellHeight + 32
|
|
|
|
"ENGINE".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
|
y += 24
|
|
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
|
y += 1/UIScreen.main.scale
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Number", value: self.engine?.number ?? "<unknown>", context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Fuel type", value: self.engine?.fuelType ?? "<unknown>", context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Volume (cm³)", value: String(self.engine?.volume ?? 0), context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (HP)", value: String(self.engine?.powerHp ?? 0), context: ctx)
|
|
y += cellHeight
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (kw)", value: String(self.engine?.powerKw ?? 0), context: ctx)
|
|
y += cellHeight + 32
|
|
|
|
"OWNERSHIP PERIODS (\(self.ownershipPeriods.count))".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
|
y += 24
|
|
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
|
y += 1/UIScreen.main.scale
|
|
|
|
let formatter = DateFormatter()
|
|
formatter.dateStyle = .long
|
|
formatter.timeStyle = .none
|
|
for period in self.ownershipPeriods {
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Owner type", value: period.ownerType, context: ctx)
|
|
y += cellHeight
|
|
|
|
let fromDate = Date(timeIntervalSince1970: TimeInterval(period.from/1000))
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "From", value: formatter.string(from: fromDate), context: ctx)
|
|
y += cellHeight
|
|
|
|
let toDate = Date(timeIntervalSince1970: TimeInterval(period.to/1000))
|
|
let toString = period.to == 0 ? "now" : formatter.string(from: toDate)
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "To", value: toString, context: ctx)
|
|
y += cellHeight
|
|
|
|
let height = self.drawBigTextCell(y: y, width: w, title: "Last operation", value: period.lastOperation, lineMargin: 0, context: ctx)
|
|
y += height + 8
|
|
}
|
|
|
|
y += 24
|
|
|
|
if !self.events.isEmpty {
|
|
"LOCATIONS".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
|
y += 24
|
|
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
|
y += 1/UIScreen.main.scale
|
|
|
|
for event in self.events {
|
|
let date = Date(timeIntervalSince1970: event.date)
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Date", value: formatter.string(from: date), context: ctx)
|
|
y += cellHeight
|
|
|
|
if let address = event.address {
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Address", value: address, context: ctx)
|
|
y += cellHeight
|
|
}
|
|
|
|
let location = String(format: "%.05f, %.05f", event.latitude, event.longitude)
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Location", value: location, context: ctx)
|
|
y += cellHeight + 8
|
|
}
|
|
}
|
|
|
|
y += 24
|
|
|
|
"PHOTOS (\(self.photos.count))".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
|
y += 24
|
|
self.drawLine(y: y, width: w, margin: 0, context: ctx)
|
|
y += 1/UIScreen.main.scale
|
|
|
|
for photo in self.photos {
|
|
let date = Date(timeIntervalSince1970: TimeInterval(photo.date/1000))
|
|
var name = "<Unknown model>"
|
|
if let brand = photo.brand, let model = photo.model {
|
|
name = "\(brand) \(model)"
|
|
}
|
|
|
|
if let url = URL(string: photo.url) {
|
|
if let image = ImageCache.default.retrieveImageInDiskCache(forKey: url.cacheKey) {
|
|
let imgHeight = image.size.height*w/image.size.width
|
|
let rect = CGRect(x: 0, y: y, width: w, height: imgHeight)
|
|
image.draw(in: rect)
|
|
y += imgHeight
|
|
}
|
|
}
|
|
|
|
self.drawCell(y: y, width: w, height: cellHeight, title: name, value: formatter.string(from: date), lineMargin: 0, context: ctx)
|
|
y += cellHeight
|
|
|
|
y += 16
|
|
}
|
|
|
|
realHeight = y
|
|
}
|
|
|
|
return image.cutHeight(to: realHeight)
|
|
}
|
|
|
|
func reportText() -> String {
|
|
let formatter = DateFormatter()
|
|
formatter.dateStyle = .long
|
|
formatter.timeStyle = .none
|
|
|
|
var text = (self.brand?.name?.original ?? "<unknown model>") + "\n"
|
|
text += "Year: \(self.year)\n"
|
|
if let color = self.color { text += "Color: \(color)\n" }
|
|
if let category = self.category { text += "Category: \(category)\n" }
|
|
var position = "Unknown"
|
|
if let rightWheel = self.isRightWheel {
|
|
position = rightWheel ? "Right" : "Left"
|
|
}
|
|
var japanese = "<Unknown>"
|
|
if let isJapanese = self.isJapanese {
|
|
japanese = isJapanese ? "Yes" : "No"
|
|
}
|
|
text += "Steering wheel position: \(position)\n"
|
|
text += "Japanese: \(japanese)\n"
|
|
text += "Plate number: \(self.getNumber())\n"
|
|
if let vin = self.vin1 { text += "VIN: \(vin)\n" }
|
|
if let sts = self.sts { text += "STS: \(sts)\n" }
|
|
if let pts = self.pts { text += "PTS: \(pts)\n" }
|
|
if let engineNumber = self.engine?.number { text += "Engine number: \(engineNumber)\n" }
|
|
if let fuel = self.engine?.fuelType { text += "Fuel type: \(fuel)\n" }
|
|
if let volume = self.engine?.volume { text += "Volume (cm³): \(volume)\n" }
|
|
if let powerHp = self.engine?.powerHp { text += "Power (HP): \(powerHp)\n" }
|
|
if let powerHp = self.engine?.powerHp { text += "Power (HP): \(powerHp)\n" }
|
|
|
|
if self.ownershipPeriods.count > 0 {
|
|
text += "\n"
|
|
text += "Ownership periods: \(self.ownershipPeriods.count)\n"
|
|
text += "\n"
|
|
for period in self.ownershipPeriods {
|
|
text += "Owner type: \(period.ownerType)\n"
|
|
let fromDate = Date(timeIntervalSince1970: TimeInterval(period.from/1000))
|
|
text += "From: \(formatter.string(from: fromDate))\n"
|
|
let toDate = Date(timeIntervalSince1970: TimeInterval(period.to/1000))
|
|
let toString = period.to == 0 ? "now" : formatter.string(from: toDate)
|
|
text += "To: \(toString)\n"
|
|
text += "Last operation: \(period.lastOperation)\n"
|
|
text += "\n"
|
|
}
|
|
}
|
|
|
|
if !self.events.isEmpty {
|
|
text += "\n"
|
|
text += "Locations\n"
|
|
text += "\n"
|
|
for event in self.events {
|
|
let date = Date(timeIntervalSince1970: event.date)
|
|
text += "Date: \(formatter.string(from: date))\n"
|
|
|
|
if let address = event.address {
|
|
text += "Address: \(address)\n"
|
|
}
|
|
|
|
let location = String(format: "%.05f, %.05f", event.latitude, event.longitude)
|
|
text += "Location: \(location)\n"
|
|
text += "\n"
|
|
}
|
|
}
|
|
|
|
return text
|
|
}
|
|
}
|