Documentation Index
Fetch the complete documentation index at: https://mintlify.com/japsinghx/breeze-ios/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The PollenView component displays pollen and allergen information in a visually appealing grid format. It shows pollen levels for different types (grass, tree, weed) and specific plants, with detailed sheets featuring plant images, health recommendations, and seasonal information.
Visual Display
The component presents:
- Header with “Allergy Tracker” title and Google attribution
- 2-column grid of pollen item cards
- Each card shows pollen name, level value, progress bar, and status
- Tappable cards that open detailed information sheets
- Empty state when no pollen data is available
Component Definition
struct PollenView: View {
let items: [PollenItem]
@State private var selectedPollen: PollenItem?
@State private var detentSelection: PresentationDetent = .large
private let columns = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
VStack(alignment: .leading, spacing: 12) {
HStack {
Image(systemName: "leaf.fill")
.foregroundColor(.green)
Text("Allergy Tracker")
.font(.headline)
Spacer()
Text("Powered by Google")
.font(.caption2)
.foregroundColor(.secondary)
}
.padding(.horizontal, 4)
LazyVGrid(columns: columns, spacing: 8) {
ForEach(items) { item in
PollenItemCard(item: item)
.onTapGesture {
selectedPollen = item
detentSelection = .large
}
}
}
}
.sheet(item: $selectedPollen) { pollen in
PollenDetailSheet(pollen: pollen)
.presentationDetents([.large, .medium], selection: $detentSelection)
.presentationDragIndicator(.visible)
}
}
}
Props / Parameters
Array of pollen items to display. Each PollenItem contains:
id: Unique identifier
name: Display name (e.g., “Grass”, “Ragweed”)
value: Pollen level (0-5 scale)
category: Status category (None, Low, Moderate, High, Very High)
isPlant: Whether this is a specific plant or general category
imageUrl: Optional plant image URL
family: Plant family information
season: Peak pollen season
appearance: Plant appearance description
healthRecommendations: Array of health tips
Pollen Item Card
Each card in the grid displays:
struct PollenItemCard: View {
let item: PollenItem
var body: some View {
VStack(alignment: .leading, spacing: 6) {
HStack {
Text(item.name)
.font(.subheadline)
.fontWeight(.medium)
.lineLimit(1)
Spacer()
HStack(spacing: 4) {
Text("\(item.value)")
.font(.title3)
.fontWeight(.bold)
.foregroundColor(item.level.color)
Image(systemName: "info.circle")
.font(.caption)
.foregroundColor(.accentColor)
}
}
// Progress bar
GeometryReader { geometry in
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 4)
.fill(Color.secondary.opacity(0.2))
.frame(height: 6)
RoundedRectangle(cornerRadius: 4)
.fill(item.level.color)
.frame(width: geometry.size.width * CGFloat(item.value) / 5.0, height: 6)
}
}
.frame(height: 6)
Text(item.level.rawValue)
.font(.caption)
.foregroundColor(.secondary)
}
.padding(10)
.background(Color.cardBackground)
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}
Detail Sheet Features
The pollen detail sheet provides comprehensive information:
Hero Section
VStack(spacing: 12) {
// Icon
ZStack {
Circle()
.fill(pollen.level.color.opacity(0.15))
.frame(width: 70, height: 70)
Image(systemName: "leaf.fill")
.font(.system(size: 28, weight: .medium))
.foregroundColor(pollen.level.color)
}
// Name
VStack(spacing: 4) {
Text(pollen.name)
.font(.title2)
.fontWeight(.bold)
Text(pollen.isPlant ? "Plant Pollen" : "Pollen Type")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
Current Level Display
VStack(spacing: 8) {
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text("\(pollen.value)")
.font(.system(size: 44, weight: .bold, design: .rounded))
.foregroundColor(pollen.level.color)
Text("/ 5")
.font(.title3)
.foregroundColor(.secondary)
}
// Status badge
Text(pollen.level.rawValue)
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.white)
.padding(.horizontal, 14)
.padding(.vertical, 6)
.background(pollen.level.color)
.clipShape(Capsule())
}
Plant Image
For plant-specific entries, displays AsyncImage:
if let imageUrl = pollen.imageUrl, let url = URL(string: imageUrl) {
AsyncImage(url: url) { phase in
switch phase {
case .empty:
ProgressView()
.frame(maxWidth: .infinity)
.frame(height: 260)
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: .infinity)
.frame(height: 260)
.clipShape(RoundedRectangle(cornerRadius: 16))
case .failure:
EmptyView()
@unknown default:
EmptyView()
}
}
}
Displays botanical details when available:
if pollen.family != nil || pollen.season != nil || pollen.appearance != nil {
VStack(alignment: .leading, spacing: 12) {
Text("About this Plant")
.font(.headline)
VStack(alignment: .leading, spacing: 12) {
if let family = pollen.family {
VStack(alignment: .leading, spacing: 4) {
Text("Family")
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.secondary)
Text(family)
.font(.subheadline)
}
}
if let season = pollen.season {
VStack(alignment: .leading, spacing: 4) {
Text("Season")
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.secondary)
Text(season)
.font(.subheadline)
}
}
}
}
}
Pollen Index Scale
The detail sheet includes a comprehensive scale:
- None: 0
- Low: 1
- Moderate: 2-3
- High: 4
- Very High: 5
struct PollenScaleRow: View {
let level: String
let range: String
let color: Color
let isActive: Bool
var body: some View {
HStack {
Circle()
.fill(color)
.frame(width: 10, height: 10)
Text(level)
.font(.subheadline)
Spacer()
Text(range)
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(.vertical, 8)
.padding(.horizontal, 12)
.background(isActive ? color.opacity(0.1) : Color.clear)
.clipShape(RoundedRectangle(cornerRadius: 8))
}
}
Empty State
When no pollen data is available:
if items.isEmpty {
HStack {
Spacer()
VStack(spacing: 8) {
Image(systemName: "leaf.circle")
.font(.largeTitle)
.foregroundColor(.secondary)
Text("No pollen data available")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(.vertical, 24)
Spacer()
}
.background(Color.cardBackground)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
Usage in App
PollenView(items: [
PollenItem(id: "GRASS", name: "Grass", value: 3, category: "Moderate", isPlant: false),
PollenItem(id: "TREE", name: "Tree", value: 2, category: "Low", isPlant: false),
PollenItem(id: "RAGWEED", name: "Ragweed", value: 4, category: "High", isPlant: true)
])
Data Source
Pollen data is powered by Google’s Pollen API, as indicated in the header attribution.
Source Location
BreezeApp/Views/Environmental/PollenView.swift:3