# Sparkle Auto-Update Setup Guide

This guide will help you set up automatic updates for LangToLang using Sparkle and GitHub Releases.

---

## 📋 Prerequisites

1. GitHub account
2. GitHub repository for LangToLang
3. Xcode with your project

---

## 🔧 Step 1: Add Sparkle Framework

### Option A: Swift Package Manager (Recommended)

1. In Xcode: **File → Add Package Dependencies...**
2. Enter URL: `https://github.com/sparkle-project/Sparkle`
3. Select version: **2.x** (latest)
4. Click **Add Package**
5. Select **Sparkle** library
6. Click **Add Package**

### Option B: Manual (if SPM fails)

1. Download Sparkle from: https://sparkle-project.org
2. Drag `Sparkle.framework` into your project
3. Embed & Sign in General → Frameworks

---

## 📝 Step 2: Add Sparkle to Info.plist

Add these keys to your `Info.plist`:

```xml
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/YOUR_USERNAME/LangToLang/main/appcast.xml</string>

<key>SUPublicEDKey</key>
<string>YOUR_PUBLIC_KEY_HERE</string>

<key>SUEnableAutomaticChecks</key>
<true/>

<key>SUScheduledCheckInterval</key>
<integer>86400</integer>  <!-- Check daily -->
```

Replace `YOUR_USERNAME` with your GitHub username.

---

## 🔑 Step 3: Generate Signing Keys

Sparkle uses EdDSA signatures to verify updates.

### In Terminal:

```bash
# Navigate to Sparkle tools (if installed via package)
cd ~/Library/Developer/Xcode/DerivedData/YOUR_PROJECT/SourcePackages/checkouts/Sparkle

# Or download generate_keys tool from Sparkle releases

# Generate keys
./bin/generate_keys

# Output:
# Private key: SAVE THIS SECURELY, NEVER COMMIT IT!
# Public key: ADD THIS TO Info.plist
```

**Important:**
- ✅ Add **public key** to `Info.plist` → `SUPublicEDKey`
- ❌ **NEVER** commit private key to GitHub
- 💾 Save private key somewhere safe (you'll need it for each release)

---

## 📦 Step 4: Create GitHub Release

### When ready to release a new version:

1. **Archive the app**:
   ```
   Xcode → Product → Archive
   ```

2. **Export**:
   - Distribute App → Copy App
   - Save somewhere accessible

3. **Create ZIP**:
   ```bash
   cd /path/to/exported/app
   zip -r LangToLang-1.5.0.zip LangToLang.app
   ```

4. **Sign the ZIP**:
   ```bash
   # Use your private key from Step 3
   /path/to/sparkle/bin/sign_update LangToLang-1.5.0.zip
   
   # Output: 
   # edSignature: COPY_THIS_SIGNATURE
   # length: COPY_THIS_LENGTH
   ```

5. **Create GitHub Release**:
   - Go to your repo → Releases → New Release
   - Tag: `v1.5.0`
   - Title: `LangToLang 1.5.0`
   - Description: Changelog
   - Attach: `LangToLang-1.5.0.zip`
   - Publish release

6. **Get download URL**:
   ```
   Right-click ZIP → Copy Link
   Should be: https://github.com/YOUR_USERNAME/LangToLang/releases/download/v1.5.0/LangToLang-1.5.0.zip
   ```

---

## 📰 Step 5: Create/Update appcast.xml

Create `appcast.xml` in your repo root:

```xml
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>LangToLang Updates</title>
    <description>Most recent updates to LangToLang</description>
    <language>en</language>
    
    <item>
      <title>LangToLang 1.5.0</title>
      <description><![CDATA[
        <h2>What's New in 1.5.0</h2>
        <ul>
          <li>NEW: Conversion statistics</li>
          <li>NEW: App blacklist</li>
          <li>NEW: Visual feedback when disabled</li>
          <li>IMPROVED: Better multi-line handling</li>
          <li>FIX: Capital letter conversion</li>
        </ul>
      ]]></description>
      <pubDate>Mon, 03 Feb 2026 12:00:00 +0000</pubDate>
      <sparkle:version>1.5.0</sparkle:version>
      <sparkle:shortVersionString>1.5.0</sparkle:shortVersionString>
      <sparkle:minimumSystemVersion>13.0</sparkle:minimumSystemVersion>
      <enclosure 
        url="https://github.com/YOUR_USERNAME/LangToLang/releases/download/v1.5.0/LangToLang-1.5.0.zip"
        sparkle:edSignature="YOUR_SIGNATURE_FROM_STEP_4"
        length="YOUR_LENGTH_FROM_STEP_4"
        type="application/octet-stream" />
    </item>
    
    <!-- Add previous versions below -->
    
  </channel>
</rss>
```

Replace:
- `YOUR_USERNAME`
- `YOUR_SIGNATURE_FROM_STEP_4`
- `YOUR_LENGTH_FROM_STEP_4`

---

## 💻 Step 6: Add Update Check to App

Add this to `AppDelegate.swift`:

```swift
import Sparkle

class AppDelegate: NSObject, NSApplicationDelegate {
    // ... existing code ...
    
    private var updater: SPUStandardUpdaterController?
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        // ... existing code ...
        
        // Initialize Sparkle
        updater = SPUStandardUpdaterController(
            startingUpdater: true,
            updaterDelegate: nil,
            userDriverDelegate: nil
        )
    }
}
```

Add menu item:

```swift
// In updateMenu()
let updateItem = NSMenuItem(title: "Check for Updates...", action: #selector(checkForUpdates), keyEquivalent: "")
updateItem.target = self
menu.addItem(updateItem)

@objc private func checkForUpdates() {
    updater?.checkForUpdates(nil)
}
```

---

## ✅ Step 7: Test

1. **Lower version number** in your local build (e.g., 1.4.0)
2. **Run app**
3. **Click "Check for Updates"**
4. Should detect v1.5.0 and offer to update!

---

## 🔄 For Each New Release:

1. Update version in `Settings.swift`:
   ```swift
   struct AppVersion {
       static let version = "1.6.0"  // ← Change this
       static let build = "1"
   }
   ```

2. Archive → Export → Zip → Sign

3. Create GitHub Release with ZIP

4. Add new `<item>` to `appcast.xml` (at the top)

5. Commit and push `appcast.xml`

6. Done! Users will auto-update

---

## 🔒 Security Notes

- **Private key**: Store securely, NEVER commit to Git
- **Add to `.gitignore`**:
  ```
  *_key.pem
  *_priv.pem
  *.private
  ```

- **Use GitHub Secrets** for CI/CD automation

---

## 📚 Resources

- [Sparkle Documentation](https://sparkle-project.org/documentation/)
- [GitHub Releases Guide](https://docs.github.com/en/repositories/releasing-projects-on-github)
- [EdDSA Signing](https://sparkle-project.org/documentation/security/)

---

## ❓ Troubleshooting

### "Could not find Feed URL"
- Check `SUFeedURL` in Info.plist
- Make sure `appcast.xml` is accessible at that URL

### "Update signature invalid"
- Verify public key in Info.plist matches private key
- Re-sign the update with correct private key

### "No updates found"
- Check appcast.xml is valid XML
- Verify version number is higher than current
- Check GitHub Release is published (not draft)

---

**You're all set!** 🚀

Users will now receive automatic update notifications when you release new versions.
