# XcodeGen spec for the native SwiftUI VniDrop app (iOS/iPadOS/macOS).
# Regenerate the project with:  xcodegen generate  (run from apple/)
# Requires three generated inputs first (all gitignored), before xcodegen:
#   - Rust core:      apple/scripts/build-core.sh debug
#   - Localization:   (cd localization && bun run src/cli.ts generate)
#                     -> VniDrop/Resources/Localizable.xcstrings, VniDrop/Generated/L10n.swift
#   - Versions:       packaging/version/generate-apple-xcconfig.sh all
#                     -> Generated/StoreVersion.xcconfig, Generated/DirectVersion.xcconfig
name: VniDrop
options:
  bundleIdPrefix: com.vnidrop
  deploymentTarget:
    iOS: "18.2"
    macOS: "15.0"
  createIntermediateGroups: true

# Build configurations. Declaring `configs` replaces XcodeGen's Debug/Release
# defaults, so both are re-listed here. `Release-Direct` is a release-type config
# used only by the VniDropDirect (notarized DMG + Sparkle) target; the App Store
# `VniDrop` target ships under plain `Release`.
configs:
  Debug: debug
  Release: release
  Release-Direct: release

# Project-wide build settings (applied to every target/config).
settings:
  base:
    # Apple Silicon only. Intel Macs are unsupported (going EOL with macOS 28), and
    # the Rust core's macOS slice (vnidrop.xcframework) is built arm64-only, so a
    # universal link would fail looking for x86_64 symbols anyway.
    ARCHS: arm64
    # Strip unreachable code from release binaries.
    DEAD_CODE_STRIPPING: YES
    # Flag user-facing strings that aren't localized (the app ships 9 languages).
    CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED: YES

packages:
  VnidropCore:
    path: VnidropCore
  SFSafeSymbols:
    url: https://github.com/SFSafeSymbols/SFSafeSymbols
    from: "5.3.0"
  # Sparkle powers in-app auto-updates for the direct-download (.dmg) build only.
  # It is linked exclusively by the VniDropDirect target — SwiftPM links products
  # per target, not per config, so keeping it off the App Store target is what
  # guarantees the store binary never bundles a self-updater (App Store forbids it).
  Sparkle:
    url: https://github.com/sparkle-project/Sparkle
    from: "2.9.4"

# Shared definition for the two shipping app targets. `VniDrop` (App Store /
# TestFlight) and `VniDropDirect` (notarized DMG + Sparkle) build the exact same
# sources; only their destinations, extra dependencies, and the DIRECT_DISTRIBUTION
# compile flag differ (set per target below).
targetTemplates:
  AppBase:
    type: application
    sources:
      - path: VniDrop
        excludes:
          - "Resources/Info.plist"
          - "Resources/VniDrop.entitlements"
          - "Resources/VniDropDirect.entitlements"
          - "Resources/**/.DS_Store"
    settings:
      base:
        PRODUCT_NAME: VniDrop
        PRODUCT_BUNDLE_IDENTIFIER: com.vnidrop.app
        MARKETING_VERSION: "$(PRODUCT_VERSION)"
        GENERATE_INFOPLIST_FILE: NO
        INFOPLIST_FILE: VniDrop/Resources/Info.plist
        CODE_SIGN_ENTITLEMENTS: VniDrop/Resources/VniDrop.entitlements
        # Mirror the Info.plist identity so Xcode's Identity editor shows it too
        # (the editor reads these build settings, not the manual plist).
        INFOPLIST_KEY_CFBundleDisplayName: VniDrop
        INFOPLIST_KEY_LSApplicationCategoryType: public.app-category.utilities
        SWIFT_VERSION: "6.0"
        SWIFT_STRICT_CONCURRENCY: complete
        ENABLE_USER_SCRIPT_SANDBOXING: NO
        ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
        # App-wide accent (macOS sidebar selection, default control tints). The
        # AccentColor asset mirrors VniDropColors.brandPurple — keep them in sync.
        ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
      configs:
        release:
          # Produce a dSYM in the archive so symbol upload succeeds.
          DEBUG_INFORMATION_FORMAT: dwarf-with-dsym
        release-direct:
          DEBUG_INFORMATION_FORMAT: dwarf-with-dsym
    dependencies:
      - package: VnidropCore
      - package: SFSafeSymbols
      - sdk: SystemConfiguration.framework
      - sdk: Security.framework
      - sdk: libresolv.tbd
    preBuildScripts:
      # Enforce the typed-resources convention (see .swiftlint.yml). Required: fails
      # the build if SwiftLint is missing so the rules can't be silently bypassed.
      - name: SwiftLint (typed resources)
        basedOnDependencyAnalysis: false
        script: |
          # Xcode runs build phases with a minimal PATH that omits Homebrew, so add
          # the common Homebrew bin dirs (Apple Silicon + Intel) before resolving it.
          export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
          if which swiftlint >/dev/null; then
            swiftlint lint --config "${SRCROOT}/.swiftlint.yml"
          else
            echo "error: SwiftLint not installed — run 'brew install swiftlint'"
            exit 1
          fi

targets:
  # App Store / TestFlight target. iOS + macOS, sandboxed, no self-updater.
  VniDrop:
    templates: [AppBase]
    supportedDestinations: [iOS, macOS]
    configFiles:
      Debug: Generated/StoreVersion.xcconfig
      Release: Generated/StoreVersion.xcconfig
      Release-Direct: Generated/StoreVersion.xcconfig

  # Direct-download macOS target: Developer ID signed, notarized, ships in a .dmg
  # and self-updates via Sparkle. DIRECT_DISTRIBUTION gates all Sparkle code so the
  # App Store target above never compiles or links it.
  VniDropDirect:
    templates: [AppBase]
    supportedDestinations: [macOS]
    configFiles:
      Debug: Generated/DirectVersion.xcconfig
      Release: Generated/DirectVersion.xcconfig
      Release-Direct: Generated/DirectVersion.xcconfig
    settings:
      base:
        SWIFT_ACTIVE_COMPILATION_CONDITIONS: "$(inherited) DIRECT_DISTRIBUTION"
        # Notarization requires the hardened runtime.
        ENABLE_HARDENED_RUNTIME: YES
        # Non-sandboxed entitlements: a sandboxed Developer ID app needs a
        # provisioning profile, which direct distribution avoids. (App Store target
        # keeps VniDrop.entitlements with the sandbox.)
        CODE_SIGN_ENTITLEMENTS: VniDrop/Resources/VniDropDirect.entitlements
    dependencies:
      - package: Sparkle

  VniDropTests:
    type: bundle.unit-test
    supportedDestinations: [iOS, macOS]
    configFiles:
      Debug: Signing.xcconfig
      Release: Signing.xcconfig
      Release-Direct: Signing.xcconfig
    sources:
      - path: Tests
    settings:
      base:
        GENERATE_INFOPLIST_FILE: YES
        SWIFT_VERSION: "6.0"
        SWIFT_STRICT_CONCURRENCY: complete
    dependencies:
      - target: VniDrop

schemes:
  VniDrop:
    build:
      targets:
        VniDrop: all
    run:
      config: Debug
    test:
      config: Debug
      targets:
        - VniDropTests
    # TestFlight ships the Release build; make the Archive/Profile actions explicit
    # so Product → Archive can never pick up a Debug configuration.
    profile:
      config: Release
    archive:
      config: Release

  # Direct-download build: always the Release-Direct config (Sparkle + notarization).
  VniDropDirect:
    build:
      targets:
        VniDropDirect: all
    run:
      config: Release-Direct
    profile:
      config: Release-Direct
    archive:
      config: Release-Direct
