Files
Gas-Tank-AR-App/GasTankAR/Data/Leads/StubLeadDetailRemoteService.swift

112 lines
5.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
import UIKit
@MainActor
final class StubLeadDetailRemoteService: LeadDetailRemoteService {
enum Scenario { case success, offline, timeout, http(Int), invalidFile }
var detailScenario: Scenario = .success
var fileScenario: Scenario = .success
var delay: Duration
private(set) var downloadCount = 0
private let leads: any LeadRemoteService
init(leads: (any LeadRemoteService)? = nil,
delay: Duration = .milliseconds(400)) {
self.leads = leads ?? StubLeadRemoteService(delay: .zero)
self.delay = delay
}
func fetchDetail(id: String, salesCode: String) async throws -> LeadDetailDTO {
try await simulate(detailScenario)
let lead = try await leads.fetchLead(id: id, salesCode: salesCode).toDomain()
return LeadDetailDTO(detail: LeadDetailSampleData.make(for: lead))
}
func download(_ reference: LeadFileReference, leadID: String, salesCode: String) async throws -> Data {
downloadCount += 1
try await simulate(fileScenario)
if case .invalidFile = fileScenario { return Data("not a valid file".utf8) }
let lead = try await leads.fetchLead(id: leadID, salesCode: salesCode).toDomain()
let detail = LeadDetailSampleData.make(for: lead)
switch reference.kind {
case .pdf:
guard let document = detail.offers.flatMap(\.documents).first(where: { $0.file == reference }) else {
throw LeadRemoteError.http(statusCode: 404)
}
return makePDF(document: document, customer: lead.displayName)
case .image:
guard let photo = detail.photos.first(where: { $0.thumbnail == reference || $0.original == reference }) else {
throw LeadRemoteError.http(statusCode: 404)
}
return makeImage(photo: photo, thumbnail: reference == photo.thumbnail)
}
}
private func simulate(_ scenario: Scenario) async throws {
try await Task.sleep(for: delay)
try Task.checkCancellation()
switch scenario {
case .success, .invalidFile: break
case .offline: throw URLError(.notConnectedToInternet)
case .timeout: throw URLError(.timedOut)
case .http(let code): throw LeadRemoteError.http(statusCode: code)
}
}
private func makePDF(document: LeadDocument, customer: String) -> Data {
let renderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: 595, height: 842))
return renderer.pdfData { context in
for page in 1...document.pageCount {
context.beginPage()
let title = document.title.replacingOccurrences(of: ".pdf", with: "")
(title as NSString).draw(in: CGRect(x: 48, y: 56, width: 499, height: 100),
withAttributes: [.font: UIFont.boldSystemFont(ofSize: 24)])
let body = """
DrachenGas – Beispieldokument
\(customer)
Seite \(page) von \(document.pageCount)
Diese Datei dient ausschließlich zur Vorschau der Download- und PDF-Anzeige.
Sie enthält keine verbindlichen Vertragsbedingungen.
Bitte prüfen Sie alle Seiten vor der Unterschrift.
"""
(body as NSString).draw(in: CGRect(x: 48, y: 180, width: 499, height: 540),
withAttributes: [.font: UIFont.systemFont(ofSize: 15),
.foregroundColor: UIColor.darkGray])
if let placement = document.signaturePlacement, placement.pageIndex == page - 1 {
let bounds = placement.bounds
let field = CGRect(x: bounds.minX, y: 842 - bounds.maxY,
width: bounds.width, height: bounds.height)
UIColor.lightGray.setStroke()
UIBezierPath(rect: field).stroke()
("Unterschrift Kunde" as NSString).draw(
at: CGPoint(x: field.minX, y: field.maxY + 8),
withAttributes: [.font: UIFont.systemFont(ofSize: 11),
.foregroundColor: UIColor.darkGray]
)
}
}
}
}
private func makeImage(photo: LeadPhoto, thumbnail: Bool) -> Data {
let size = thumbnail ? CGSize(width: 360, height: 220) : CGSize(width: 1200, height: 800)
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.pngData { context in
UIColor.systemTeal.withAlphaComponent(0.14).setFill()
context.fill(CGRect(origin: .zero, size: size))
let symbol = UIImage(systemName: photo.isAR ? "arkit" : "photo")?
.withTintColor(.systemBlue, renderingMode: .alwaysOriginal)
symbol?.draw(in: CGRect(x: size.width * 0.4, y: size.height * 0.2,
width: size.width * 0.2, height: size.height * 0.35))
("Beispiel · \(photo.title)" as NSString).draw(
in: CGRect(x: 20, y: size.height * 0.72, width: size.width - 40, height: 60),
withAttributes: [.font: UIFont.systemFont(ofSize: thumbnail ? 16 : 32),
.foregroundColor: UIColor.darkGray]
)
}
}
}