- Implement camera capture and plant identification workflow - Add Core Data persistence for plants, care schedules, and cached API data - Create collection view with grid/list layouts and filtering - Build plant detail views with care information display - Integrate Trefle botanical API for plant care data - Add local image storage for captured plant photos - Implement dependency injection container for testability - Include accessibility support throughout the app Bug fixes in this commit: - Fix Trefle API decoding by removing duplicate CodingKeys - Fix LocalCachedImage to load from correct PlantImages directory - Set dateAdded when saving plants for proper collection sorting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
336 lines
11 KiB
Swift
336 lines
11 KiB
Swift
//
|
|
// TrefleDTOs.swift
|
|
// PlantGuide
|
|
//
|
|
// Created on 2026-01-21.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
// MARK: - TrefleSearchResponseDTO
|
|
|
|
/// The root response object from the Trefle plant search API.
|
|
///
|
|
/// This DTO represents the complete response from the `/api/v1/plants/search` endpoint,
|
|
/// including search results, pagination links, and metadata.
|
|
struct TrefleSearchResponseDTO: Decodable, Sendable {
|
|
/// The list of plant summaries matching the search query.
|
|
let data: [TreflePlantSummaryDTO]
|
|
|
|
/// Pagination links for navigating through search results.
|
|
let links: TrefleLinksDTO
|
|
|
|
/// Metadata about the search results, including total count.
|
|
let meta: TrefleMetaDTO
|
|
}
|
|
|
|
// MARK: - TrefleSpeciesResponseDTO
|
|
|
|
/// The root response object for a single species from the Trefle API.
|
|
///
|
|
/// This DTO represents the complete response from the `/api/v1/species/{id}` endpoint,
|
|
/// containing detailed species information and metadata.
|
|
struct TrefleSpeciesResponseDTO: Decodable, Sendable {
|
|
/// The detailed species information.
|
|
let data: TrefleSpeciesDTO
|
|
|
|
/// Metadata about the response.
|
|
let meta: TrefleMetaDTO
|
|
}
|
|
|
|
// MARK: - TreflePlantSummaryDTO
|
|
|
|
/// Represents basic plant information returned from a Trefle search query.
|
|
///
|
|
/// This DTO contains summarized plant data suitable for displaying in search results
|
|
/// or lists, with links to more detailed species information.
|
|
struct TreflePlantSummaryDTO: Decodable, Sendable {
|
|
/// The unique identifier for this plant in the Trefle database.
|
|
let id: Int
|
|
|
|
/// The common name for this plant (e.g., "European Oak").
|
|
/// May be nil if no common name is available.
|
|
let commonName: String?
|
|
|
|
/// The URL-friendly slug for this plant (e.g., "quercus-robur").
|
|
let slug: String
|
|
|
|
/// The scientific name for this plant (e.g., "Quercus robur").
|
|
let scientificName: String
|
|
|
|
/// The family name for this plant (e.g., "Fagaceae").
|
|
/// May be nil if family information is not available.
|
|
let family: String?
|
|
|
|
/// The genus name for this plant (e.g., "Quercus").
|
|
/// May be nil if genus information is not available.
|
|
let genus: String?
|
|
|
|
/// The URL to the primary image for this plant.
|
|
/// May be nil if no image is available.
|
|
let imageUrl: String?
|
|
}
|
|
|
|
// MARK: - TrefleSpeciesDTO
|
|
|
|
/// Represents detailed species information from the Trefle API.
|
|
///
|
|
/// This DTO contains comprehensive plant data including taxonomic details,
|
|
/// images, growth requirements, and physical specifications.
|
|
struct TrefleSpeciesDTO: Decodable, Sendable {
|
|
/// The unique identifier for this species in the Trefle database.
|
|
let id: Int
|
|
|
|
/// The common name for this species (e.g., "European Oak").
|
|
/// May be nil if no common name is available.
|
|
let commonName: String?
|
|
|
|
/// The URL-friendly slug for this species (e.g., "quercus-robur").
|
|
let slug: String
|
|
|
|
/// The scientific name for this species (e.g., "Quercus robur").
|
|
let scientificName: String
|
|
|
|
/// The year this species was first formally described.
|
|
/// May be nil if the year is not known.
|
|
let year: Int?
|
|
|
|
/// The bibliographic reference for the original species description.
|
|
/// May be nil if not available.
|
|
let bibliography: String?
|
|
|
|
/// The author who first described this species (e.g., "L." for Linnaeus).
|
|
/// May be nil if not available.
|
|
let author: String?
|
|
|
|
/// The common name of the plant family (e.g., "Beech family").
|
|
/// May be nil if not available.
|
|
let familyCommonName: String?
|
|
|
|
/// The scientific family name (e.g., "Fagaceae").
|
|
/// May be nil if not available.
|
|
let family: String?
|
|
|
|
/// The genus name (e.g., "Quercus").
|
|
/// May be nil if not available.
|
|
let genus: String?
|
|
|
|
/// The unique identifier for the genus in the Trefle database.
|
|
/// May be nil if not available.
|
|
let genusId: Int?
|
|
|
|
/// The URL to the primary image for this species.
|
|
/// May be nil if no image is available.
|
|
let imageUrl: String?
|
|
|
|
/// Categorized images of different plant parts.
|
|
/// May be nil if no images are available.
|
|
let images: TrefleImagesDTO?
|
|
|
|
/// Physical specifications and characteristics of this species.
|
|
/// May be nil if specifications are not available.
|
|
let specifications: TrefleSpecificationsDTO?
|
|
|
|
/// Growth requirements and seasonal information for this species.
|
|
/// May be nil if growth data is not available.
|
|
let growth: TrefleGrowthDTO?
|
|
}
|
|
|
|
// MARK: - TrefleGrowthDTO
|
|
|
|
/// Represents growth requirements and seasonal information for a plant species.
|
|
///
|
|
/// This DTO contains detailed environmental preferences and growing conditions,
|
|
/// including light, humidity, temperature ranges, and seasonal activity.
|
|
struct TrefleGrowthDTO: Decodable, Sendable {
|
|
/// Light requirement on a scale of 0-10 (0 = full shade, 10 = full sun).
|
|
/// May be nil if not available.
|
|
let light: Int?
|
|
|
|
/// Atmospheric humidity requirement on a scale of 0-10.
|
|
/// May be nil if not available.
|
|
let atmosphericHumidity: Int?
|
|
|
|
/// Months during which the plant actively grows (e.g., ["mar", "apr", "may"]).
|
|
/// May be nil if not available.
|
|
let growthMonths: [String]?
|
|
|
|
/// Months during which the plant blooms (e.g., ["apr", "may"]).
|
|
/// May be nil if not available.
|
|
let bloomMonths: [String]?
|
|
|
|
/// Months during which the plant produces fruit (e.g., ["sep", "oct"]).
|
|
/// May be nil if not available.
|
|
let fruitMonths: [String]?
|
|
|
|
/// The minimum precipitation requirement for this species.
|
|
/// May be nil if not available.
|
|
let minimumPrecipitation: TrefleMeasurementDTO?
|
|
|
|
/// The maximum precipitation tolerance for this species.
|
|
/// May be nil if not available.
|
|
let maximumPrecipitation: TrefleMeasurementDTO?
|
|
|
|
/// The minimum temperature tolerance for this species.
|
|
/// May be nil if not available.
|
|
let minimumTemperature: TrefleMeasurementDTO?
|
|
|
|
/// The maximum temperature tolerance for this species.
|
|
/// May be nil if not available.
|
|
let maximumTemperature: TrefleMeasurementDTO?
|
|
|
|
/// Soil nutrient requirement on a scale of 0-10 (0 = low, 10 = high).
|
|
/// May be nil if not available.
|
|
let soilNutriments: Int?
|
|
|
|
/// Soil humidity requirement on a scale of 0-10 (0 = dry, 10 = wet).
|
|
/// May be nil if not available.
|
|
let soilHumidity: Int?
|
|
|
|
/// The minimum soil pH tolerance for this species.
|
|
/// May be nil if not available.
|
|
let phMinimum: Double?
|
|
|
|
/// The maximum soil pH tolerance for this species.
|
|
/// May be nil if not available.
|
|
let phMaximum: Double?
|
|
}
|
|
|
|
// MARK: - TrefleSpecificationsDTO
|
|
|
|
/// Represents physical specifications and characteristics of a plant species.
|
|
///
|
|
/// This DTO contains information about growth rate, toxicity, and size dimensions.
|
|
struct TrefleSpecificationsDTO: Decodable, Sendable {
|
|
/// The growth rate classification (e.g., "slow", "moderate", "rapid").
|
|
/// May be nil if not available.
|
|
let growthRate: String?
|
|
|
|
/// Toxicity information (e.g., "none", "low", "medium", "high").
|
|
/// May be nil if not available.
|
|
let toxicity: String?
|
|
|
|
/// The average height of mature plants.
|
|
/// May be nil if not available.
|
|
let averageHeight: TrefleMeasurementDTO?
|
|
|
|
/// The maximum height of mature plants.
|
|
/// May be nil if not available.
|
|
let maximumHeight: TrefleMeasurementDTO?
|
|
}
|
|
|
|
// MARK: - TrefleMeasurementDTO
|
|
|
|
/// Represents a measurement value with various unit representations.
|
|
///
|
|
/// This DTO contains the same measurement expressed in different units,
|
|
/// supporting heights (cm), precipitation (mm), and temperatures (Celsius/Fahrenheit).
|
|
struct TrefleMeasurementDTO: Decodable, Sendable {
|
|
/// The measurement in centimeters (used for heights).
|
|
/// May be nil if not applicable.
|
|
let cm: Double?
|
|
|
|
/// The measurement in millimeters (used for precipitation).
|
|
/// May be nil if not applicable.
|
|
let mm: Double?
|
|
|
|
/// The measurement in degrees Celsius (used for temperatures).
|
|
/// May be nil if not applicable.
|
|
let degC: Double?
|
|
|
|
/// The measurement in degrees Fahrenheit (used for temperatures).
|
|
/// May be nil if not applicable.
|
|
let degF: Double?
|
|
}
|
|
|
|
// MARK: - TrefleImagesDTO
|
|
|
|
/// Represents categorized images of different plant parts.
|
|
///
|
|
/// This DTO organizes plant images by the part of the plant they depict,
|
|
/// making it easy to find specific types of reference images.
|
|
struct TrefleImagesDTO: Decodable, Sendable {
|
|
/// Images of the plant's flowers.
|
|
/// May be nil or empty if no flower images are available.
|
|
let flower: [TrefleImageDTO]?
|
|
|
|
/// Images of the plant's leaves.
|
|
/// May be nil or empty if no leaf images are available.
|
|
let leaf: [TrefleImageDTO]?
|
|
|
|
/// Images of the plant's bark.
|
|
/// May be nil or empty if no bark images are available.
|
|
let bark: [TrefleImageDTO]?
|
|
|
|
/// Images of the plant's fruit.
|
|
/// May be nil or empty if no fruit images are available.
|
|
let fruit: [TrefleImageDTO]?
|
|
|
|
/// Images of the plant's overall habit/form.
|
|
/// May be nil or empty if no habit images are available.
|
|
let habit: [TrefleImageDTO]?
|
|
}
|
|
|
|
// MARK: - TrefleImageDTO
|
|
|
|
/// Represents a single plant image from the Trefle database.
|
|
struct TrefleImageDTO: Decodable, Sendable {
|
|
/// The unique identifier for this image in the Trefle database.
|
|
let id: Int
|
|
|
|
/// The URL to access this image.
|
|
let imageUrl: String
|
|
}
|
|
|
|
// MARK: - TrefleLinksDTO
|
|
|
|
/// Represents pagination links for navigating through Trefle API results.
|
|
///
|
|
/// This DTO contains URLs for traversing paginated search results,
|
|
/// following the HATEOAS pattern for RESTful APIs.
|
|
struct TrefleLinksDTO: Decodable, Sendable {
|
|
/// The URL for the current page of results.
|
|
/// Note: Maps from "self" in JSON (reserved keyword in Swift).
|
|
let selfLink: String
|
|
|
|
/// The URL for the first page of results.
|
|
let first: String
|
|
|
|
/// The URL for the last page of results.
|
|
/// May be nil if not available.
|
|
let last: String?
|
|
|
|
/// The URL for the next page of results.
|
|
/// May be nil if this is the last page.
|
|
let next: String?
|
|
|
|
/// The URL for the previous page of results.
|
|
/// May be nil if this is the first page.
|
|
let prev: String?
|
|
|
|
// CodingKeys required because "self" is a reserved keyword
|
|
private enum CodingKeys: String, CodingKey {
|
|
case selfLink = "self"
|
|
case first
|
|
case last
|
|
case next
|
|
case prev
|
|
}
|
|
}
|
|
|
|
// MARK: - TrefleMetaDTO
|
|
|
|
/// Represents metadata about a Trefle API response.
|
|
///
|
|
/// This DTO contains supplementary information about the response,
|
|
/// such as the total number of results or when the data was last updated.
|
|
struct TrefleMetaDTO: Decodable, Sendable {
|
|
/// The total number of results matching the query.
|
|
/// May be nil for single-resource responses.
|
|
let total: Int?
|
|
|
|
/// The timestamp when the data was last modified.
|
|
/// May be nil if not available.
|
|
let lastModified: String?
|
|
}
|