Skip to content

File-Specific Implementation Notes

This document contains detailed implementation notes for specific files in the Nutri-E codebase. These notes highlight critical patterns, line-specific logic, and gotchas that developers should be aware of.


Table of Contents


Views

TodayView.swift

  • StarredNutrientsSection: Displays pinned nutrients with dual progress bars (RDA + Max Intake)
  • Default tab logic: Opens Today tab if user has supplements, Supplements tab if empty
  • Streak counter: Shows consecutive days streak (fixed to count days, not individual doses)

ScheduleProfileView.swift

  • Color/Icon pickers: Must use .buttonStyle(BorderlessButtonStyle()) for buttons in Form LazyVGrid
  • Color extension: Color(colorName:) converts string color names to SwiftUI Color values

AddScheduleView.swift

  • Auto-populate dose: .onChange(of: selectedSupplement) sets doseAmount from supplement.doseAmount

SupplementSearchView.swift

  • Line 602-610: Form classification logic - DosageFormService lookup BEFORE unit-based override
  • Line 675-686: Fractional serving size parsing with regex pattern
  • Line 723: Unit normalization mapping
  • @FocusState: Auto-focus search field when view appears

NutrientDetailView.swift

  • getRelevantUnits(): Must include .kcal for calories editing
  • refreshTrigger pattern: Use @State + .id() for immediate view updates

DataManagementView.swift

  • Export options:
  • Export to file: Creates .json file with date-stamped filename
  • Share sheet for AirDrop, Files, email
  • Import options:
  • Import from file: Standard file picker
  • Paste JSON: Direct JSON paste from clipboard (added Oct 2024)
  • Auto-pastes clipboard content when opened
  • Import confirmation: Shows destructive alert before replacing all data
  • Data statistics: Shows supplement count, dose count, and days of data tracked
  • Error handling: Validates JSON before import, shows user-friendly error messages

MoreView.swift

  • Device ID display: Shows first 12 characters in About section (lines 108-123)
  • Long-press context menu to copy full Device ID
  • Used for customer support and debugging
  • Format: ABC123XYZ... with monospaced font
  • Developer Tools: Wrapped in #if DEBUG flag (lines 85-96)
  • Only visible in debug builds
  • Hidden in production/TestFlight/App Store builds

Services

ScheduleService.swift

  • Time-based sorting: Sorts schedules by hour/minute components (lines 176-188)
  • In-memory sort: Extracts Calendar components to ensure proper chronological order

StreakTrackingService.swift

  • Consecutive days logic: Counts unique days with doses, not individual dose count (fixed Oct 2024)
  • De-duplication: Skips doses on same day using lastCountedDay tracking

DataExportService.swift

  • Complete data export/import: Exports supplements, doses, schedules, profiles, and user profile to JSON
  • CRITICAL FIELDS: Must include servingSize and servingUnit for Individual Dose data integrity
  • servingSize: Individual Dose amount (stored as String, e.g., "0.5")
  • servingUnit: Individual Dose unit (stored as String, e.g., "mL")
  • Without these fields, Individual Dose defaults to "1" after import (data corruption)
  • Export format: Pretty-printed JSON with ISO8601 dates
  • Import process: Batch deletes all existing data, calls viewContext.reset(), then imports fresh data
  • Version: Currently "1.0" format

DosageFormService.swift

  • 31 supported forms: Capsule, Tablet, Lozenge, Powder, Liquid, etc.
  • Synonyms support: "gummi bear" → "Gummy", "ampoule" → "Lozenge"
  • Category mapping: Each form maps to .solid, .liquid, .powder, .topical, .other

Utils

SupplementDisplayFormatter.swift

  • formatDoseDisplay(): Handles individual vs serving size display
  • pluralizeUnit(): Count-based units get pluralized, weight/volume don't
  • formatStockCount(): Decimals for powder/liquid, integers for solids

Models

UnitType.swift

  • Categories: .weight, .volume, .energy, .count, .internationalUnits
  • Conversions: Built-in conversion logic between related units
  • Display: Always use .displayName for UI, never raw values

Notes

When to update this file: - Adding new critical patterns or gotchas - Fixing bugs that require line-specific explanations - Documenting non-obvious implementation details

When NOT to use this file: - General architectural patterns (put in CLAUDE.md) - API documentation (put in API_REFERENCE.md) - User-facing documentation (put in README.md)

Better alternatives: - Add inline code comments for complex logic - Use descriptive function/variable names - Write unit tests that document expected behavior