Full Code of nuance-dev/achico for AI

master 85a726791483 cached
35 files
119.2 KB
27.5k tokens
1 requests
Download .txt
Repository: nuance-dev/achico
Branch: master
Commit: 85a726791483
Files: 35
Total size: 119.2 KB

Directory structure:
gitextract_q763oxjx/

├── Achico/
│   ├── Achico.entitlements
│   ├── App/
│   │   ├── AchicoApp.swift
│   │   └── AppDelegate.swift
│   ├── Info.plist
│   ├── Preview Content/
│   │   └── Preview Assets.xcassets/
│   │       ├── AppIcon-1024.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-128.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-16.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-256.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-32.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-512.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-64.imageset/
│   │       │   └── Contents.json
│   │       └── Contents.json
│   ├── Processor/
│   │   ├── CacheManager.swift
│   │   ├── FileProcessor.swift
│   │   └── VideoProcessor.swift
│   ├── Resources/
│   │   ├── Assets.xcassets/
│   │   │   ├── AccentColor.colorset/
│   │   │   │   └── Contents.json
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── Contents.json
│   │   ├── CompressionSettings.swift
│   │   ├── FileDropDelegate.swift
│   │   ├── MenuBarController.swift
│   │   └── UpdateChecker.swift
│   ├── UI Components/
│   │   ├── ButtonGroup.swift
│   │   ├── GlassButtonStyle.swift
│   │   ├── TitleBarAccessory.swift
│   │   ├── VisualEffectBlur.swift
│   │   └── WindowAccessor.swift
│   └── Views/
│       ├── ContentView.swift
│       ├── DropZoneView.swift
│       ├── MenuBarView.swift
│       ├── MultiFileProcessingView.swift
│       └── ResultView.swift
├── Achico.xcodeproj/
│   └── project.pbxproj
├── LICENSE
└── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: Achico/Achico.entitlements
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-only</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
</dict>
</plist>


================================================
FILE: Achico/App/AchicoApp.swift
================================================
import SwiftUI
import AppKit

@main
struct AchicoApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @AppStorage("isDarkMode") private var isDarkMode = false
    @StateObject private var menuBarController = MenuBarController()
    @State private var showingUpdateSheet = false
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(minWidth: 400, minHeight: 500)
                .preferredColorScheme(isDarkMode ? .dark : .light)
                .background(WindowAccessor())
                .environmentObject(menuBarController)
                .sheet(isPresented: $showingUpdateSheet) {
                    MenuBarView(updater: menuBarController.updater)
                        .environmentObject(menuBarController)
                }
                .onAppear {
                    // Check for updates when app launches
                    menuBarController.updater.checkForUpdates()
                    
                    // Set up observer for update availability
                    menuBarController.updater.onUpdateAvailable = {
                        showingUpdateSheet = true
                    }
                }
        }
        .windowStyle(.hiddenTitleBar)
        .commands {
            CommandGroup(after: .appInfo) {
                Button("Check for Updates...") {
                    showingUpdateSheet = true
                    menuBarController.updater.checkForUpdates()
                }
                .keyboardShortcut("U", modifiers: [.command])
                
                if menuBarController.updater.updateAvailable {
                    Button("Download Update") {
                        if let url = menuBarController.updater.downloadURL {
                            NSWorkspace.shared.open(url)
                        }
                    }
                }
                
                Divider()
            }
        }
    }
}


================================================
FILE: Achico/App/AppDelegate.swift
================================================
import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationWillTerminate(_ notification: Notification) {
        CacheManager.shared.cleanupOldFiles()
    }
}


================================================
FILE: Achico/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-1024.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-1024.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-128.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-128.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-16.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-16.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-256.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-256.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-32.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-32.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-512.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-512.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/AppIcon-64.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-64.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Preview Content/Preview Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Processor/CacheManager.swift
================================================
// CacheManager.swift
import Foundation
import AppKit

class CacheManager {
    static let shared = CacheManager()
    
    private let cacheDirectory: URL
    private let maxCacheAge: TimeInterval = 24 * 60 * 60 // 24 hours
    
    private init() {
        let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        cacheDirectory = cacheDir.appendingPathComponent("com.achico.filecache", isDirectory: true)
        
        do {
            try FileManager.default.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
        } catch {
            print("Failed to create cache directory: \(error)")
        }
        
        // Setup automatic cleanup
        setupAutomaticCleanup()
    }
    
    func createTemporaryURL(for filename: String) throws -> URL {
           // Clean the filename
           let cleanFilename = filename.components(separatedBy: "_").last ?? filename
           let tempFilename = "\(UUID().uuidString).\(cleanFilename)"
           let fileURL = cacheDirectory.appendingPathComponent(tempFilename)
           
           // Check if file already exists and remove it
           if FileManager.default.fileExists(atPath: fileURL.path) {
               try FileManager.default.removeItem(at: fileURL)
           }
           
           return fileURL
       }
    
    func cleanupOldFiles() {
        let fileManager = FileManager.default
        let resourceKeys: [URLResourceKey] = [.creationDateKey, .isDirectoryKey]
        
        guard let enumerator = fileManager.enumerator(
            at: cacheDirectory,
            includingPropertiesForKeys: resourceKeys,
            options: .skipsHiddenFiles
        ) else { return }
        
        let cutoffDate = Date().addingTimeInterval(-maxCacheAge)
        
        while let fileURL = enumerator.nextObject() as? URL {
            do {
                let resourceValues = try fileURL.resourceValues(forKeys: Set(resourceKeys))
                if let creationDate = resourceValues.creationDate,
                   let isDirectory = resourceValues.isDirectory,
                   !isDirectory && creationDate < cutoffDate {
                    try fileManager.removeItem(at: fileURL)
                }
            } catch {
                print("Error cleaning up file at \(fileURL): \(error)")
            }
        }
    }
    
    private func setupAutomaticCleanup() {
        // Clean up on app launch
        cleanupOldFiles()
        
        // Register for app termination notification
        NotificationCenter.default.addObserver(
            forName: NSApplication.willTerminateNotification,
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.cleanupOldFiles()
        }
    }
}


================================================
FILE: Achico/Processor/FileProcessor.swift
================================================
import Foundation
import PDFKit
import UniformTypeIdentifiers
import AppKit
import CoreGraphics
import AVFoundation

enum CompressionError: LocalizedError {
        case unsupportedFormat
        case conversionFailed
        case compressionFailed
        case invalidInput
        case videoProcessingFailed
        
        var errorDescription: String? {
            switch self {
            case .unsupportedFormat:
                return "This file format is not supported"
            case .conversionFailed:
                return "Failed to convert the file"
            case .compressionFailed:
                return "Failed to compress the file"
            case .invalidInput:
                return "The input file is invalid or corrupted"
            case .videoProcessingFailed:
                return "Failed to process video file"
            }
        }
    }

class FileProcessor: ObservableObject {
    // MARK: - Published Properties
    @Published var isProcessing = false
    @Published var progress: Double = 0
    @Published var processingResult: ProcessingResult?
    
    // MARK: - Private Properties
    private let processingQueue = DispatchQueue(label: "com.achico.fileprocessing", qos: .userInitiated)
    private let cacheManager = CacheManager.shared
    private let videoProcessor = VideoProcessor()
    
    struct ProcessingResult {
        let originalSize: Int64
        let compressedSize: Int64
        let compressedURL: URL
        let fileName: String
        let originalFileName: String
        
        var savedPercentage: Int {
            guard originalSize > 0 else { return 0 }
            let percentage = Int(((Double(originalSize) - Double(compressedSize)) / Double(originalSize)) * 100)
            return max(0, percentage)
        }
        
        var suggestedFileName: String {
            // Remove UUID from filename if present
            let cleanFilename = originalFileName
                .replacingOccurrences(of: #"[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\."#,
                                    with: "",
                                    options: .regularExpression)
            let fileURL = URL(fileURLWithPath: cleanFilename)
            let filenameWithoutExt = fileURL.deletingPathExtension().lastPathComponent
            let fileExtension = compressedURL.pathExtension
            return "\(filenameWithoutExt)_compressed.\(fileExtension)"
        }
    }
    
    private func processAudio(from url: URL, to tempURL: URL, settings: CompressionSettings) async throws {
        let asset = AVURLAsset(url: url)
        let fileType = FileType(url: url)
        
        // Create a composition to work with the audio
        let composition = AVMutableComposition()
        
        // Try to get the audio track from the asset
        guard let audioTrack = try? await asset.loadTracks(withMediaType: .audio).first,
              let compositionTrack = composition.addMutableTrack(
                withMediaType: .audio,
                preferredTrackID: kCMPersistentTrackID_Invalid) else {
            throw CompressionError.compressionFailed
        }
        
        // Get asset duration using the new API
        let duration = try await asset.load(.duration)
        
        // Insert the audio track into the composition
        try compositionTrack.insertTimeRange(
            CMTimeRange(start: .zero, duration: duration),
            of: audioTrack,
            at: .zero
        )
        
        // Determine preset and output file type
        let (presetName, outputFileType): (String, AVFileType) = {
            switch fileType {
            case .mp3, .wav, .aiff, .m4a:
                return (AVAssetExportPresetAppleM4A, .m4a)
            default:
                return (AVAssetExportPresetAppleM4A, .m4a)
            }
        }()
        
        // Create export session with the composition
        guard let exportSession = AVAssetExportSession(
            asset: composition,
            presetName: presetName
        ) else {
            throw CompressionError.compressionFailed
        }
        
        // Create output URL with correct extension
        let outputURL = tempURL.deletingPathExtension().appendingPathExtension("m4a")
        
        // Remove any existing file at the output URL
        if FileManager.default.fileExists(atPath: outputURL.path) {
            try? FileManager.default.removeItem(at: outputURL)
        }
        
        // Ensure the output directory exists
        try FileManager.default.createDirectory(
            at: outputURL.deletingLastPathComponent(),
            withIntermediateDirectories: true,
            attributes: nil
        )
        
        // Configure export session
        exportSession.outputURL = outputURL
        exportSession.outputFileType = outputFileType
        
        // Monitor progress in a separate task
        let progressTask = Task {
            while !Task.isCancelled &&
                  (exportSession.status == .waiting || exportSession.status == .exporting) {
                await MainActor.run {
                    self.progress = Double(exportSession.progress)
                }
                try? await Task.sleep(nanoseconds: 100_000_000) // Sleep for 0.1 seconds
            }
        }
        
        // Start exporting and await completion
        try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
            exportSession.exportAsynchronously {
                switch exportSession.status {
                case .completed:
                    // Verify the file exists after export
                    if FileManager.default.fileExists(atPath: outputURL.path) {
                        continuation.resume()
                    } else {
                        print("Export completed but file not found at: \(outputURL.path)")
                        continuation.resume(throwing: CompressionError.compressionFailed)
                    }
                case .failed:
                    if let error = exportSession.error {
                        print("Export Session Failed: \(error.localizedDescription)")
                        print("Error Details: \(String(describing: error))")
                        continuation.resume(throwing: error)
                    } else {
                        print("Export Session Failed without error details")
                        continuation.resume(throwing: CompressionError.compressionFailed)
                    }
                case .cancelled:
                    print("Export Session Cancelled")
                    continuation.resume(throwing: CompressionError.compressionFailed)
                default:
                    print("Export Session ended with status: \(exportSession.status.rawValue)")
                    continuation.resume(throwing: CompressionError.compressionFailed)
                }
            }
        }
        
        // Cancel the progress monitoring task
        progressTask.cancel()
        
        // Verify the file exists one final time
        guard FileManager.default.fileExists(atPath: outputURL.path) else {
            throw CompressionError.compressionFailed
        }
        
        // Make sure we're returning the correct path
        if outputURL != tempURL {
            try? FileManager.default.removeItem(at: tempURL)
            try FileManager.default.moveItem(at: outputURL, to: tempURL)
        }
        
        await MainActor.run {
            self.progress = 1.0
        }
    }
    
    // MARK: - Lifecycle
    deinit {
        cleanup()
    }
    
    // MARK: - Public Methods
    @MainActor
    func processFile(url: URL, settings: CompressionSettings? = nil, originalFileName: String? = nil) async throws {
        
        isProcessing = true
        progress = 0
        processingResult = nil
        
        do {
            let result = try await processInBackground(
                url: url,
                settings: settings,
                originalFileName: originalFileName ?? url.lastPathComponent
            )
            
            self.processingResult = result
        } catch {
            isProcessing = false
            throw error
        }
        
        isProcessing = false
        progress = 1.0
    }
    
    func cleanup() {
        processingResult = nil
        cacheManager.cleanupOldFiles()
    }
    
    // MARK: - Private Methods - Main Processing
    private func processInBackground(url: URL, settings: CompressionSettings? = nil, originalFileName: String) async throws -> ProcessingResult {
        let originalSize = try FileManager.default.attributesOfItem(atPath: url.path)[.size] as? Int64 ?? 0
        let originalExtension = url.pathExtension
        let tempURL = try cacheManager.createTemporaryURL(for: originalFileName)
        
        
        
        let compressionSettings = settings ?? CompressionSettings()
        
        let fileType = FileType(url: url)
            if fileType.isVideo {
                try await processVideo(from: url, to: tempURL, settings: compressionSettings)
            } else if fileType.isAudio {
                try await processAudio(from: url, to: tempURL, settings: compressionSettings)
        } else {
            switch url.pathExtension.lowercased() {
            case "pdf":
                try processPDF(from: url, to: tempURL)
            case "jpg", "jpeg":
                try processJPEG(from: url, to: tempURL, settings: compressionSettings)
            case "png":
                try processPNG(from: url, to: tempURL, settings: compressionSettings)
            case "heic":
                try processHEIC(from: url, to: tempURL, settings: compressionSettings)
            case "tiff", "tif":
                try processTIFF(from: url, to: tempURL, settings: compressionSettings)
            case "gif":
                try processGIF(from: url, to: tempURL)
            case "bmp":
                try processBMP(from: url, to: tempURL, settings: compressionSettings)
            case "webp":
                try processWebP(from: url, to: tempURL, settings: compressionSettings)
            case "svg":
                try processSVG(from: url, to: tempURL, settings: compressionSettings)
            case "raw", "cr2", "nef", "arw":
                try processRAW(from: url, to: tempURL, settings: compressionSettings)
            case "ico":
                try processICO(from: url, to: tempURL, settings: compressionSettings)
            default:
                throw CompressionError.unsupportedFormat
            }
        }
        
        let compressedSize = try FileManager.default.attributesOfItem(atPath: tempURL.path)[.size] as? Int64 ?? 0
        print("Debug - Creating ProcessingResult:")
            print("Debug - Temp URL last component: \(tempURL.lastPathComponent)")
            print("Debug - Original filename being used: \(originalFileName)")
            return ProcessingResult(
                originalSize: originalSize,
                compressedSize: compressedSize,
                compressedURL: tempURL,
                fileName: tempURL.lastPathComponent,
                originalFileName: originalFileName
            )
    }
    
    private func processVideo(from url: URL, to tempURL: URL, settings: CompressionSettings) async throws {
        let videoSettings = VideoProcessor.VideoCompressionSettings(
            quality: Float(settings.quality),
            maxWidth: settings.maxDimension != nil ? Int(settings.maxDimension!) : nil,
            bitrateMultiplier: 0.7,
            frameRate: 30,
            audioEnabled: true
        )
        
        do {
            try await videoProcessor.compressVideo(
                inputURL: url,
                outputURL: tempURL,
                settings: videoSettings
            ) { [weak self] progress in
                Task { @MainActor in
                    self?.progress = Double(progress)
                }
            }
        } catch {
            throw CompressionError.videoProcessingFailed
        }
    }
    
    private func processICO(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        guard let compressedData = compressImage(image, format: .png, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        let pngURL = tempURL.deletingPathExtension().appendingPathExtension("png")
        try compressedData.write(to: pngURL)
    }
    
    private func processSVG(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let data = try? Data(contentsOf: url),
              let svgString = String(data: data, encoding: .utf8) else {
            throw CompressionError.conversionFailed
        }
        
        let cleanedSVG = svgString
            .replacingOccurrences(of: "<!--[\\s\\S]*?-->", with: "", options: .regularExpression)
            .replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
            .replacingOccurrences(of: "> <", with: "><")
            .trimmingCharacters(in: .whitespacesAndNewlines)
        
        try cleanedSVG.data(using: .utf8)?.write(to: tempURL)
    }
    
    
    private func processRAW(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
            throw CompressionError.conversionFailed
        }
        
        let options: [CFString: Any] = [
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceThumbnailMaxPixelSize: settings.maxDimension ?? 2048
        ]
        
        guard let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else {
            throw CompressionError.conversionFailed
        }
        
        let image = NSImage(cgImage: cgImage, size: NSSize(width: cgImage.width, height: cgImage.height))
        guard let compressedData = compressImage(image, format: .jpeg, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        let jpegURL = tempURL.deletingPathExtension().appendingPathExtension("jpg")
        try compressedData.write(to: jpegURL)
    }
    
    
    // MARK: - Private Methods - Format-Specific Processing
    private func processPDF(from url: URL, to tempURL: URL) throws {
        guard let document = PDFDocument(url: url) else {
            throw CompressionError.conversionFailed
        }
        
        let newDocument = PDFDocument()
        let totalPages = document.pageCount
        
        for i in 0..<totalPages {
            autoreleasepool {
                if let page = document.page(at: i) {
                    if let compressedPage = try? compressPDFPage(page) {
                        newDocument.insert(compressedPage, at: i)
                    } else {
                        newDocument.insert(page, at: i)
                    }
                }
            }
            
            DispatchQueue.main.async {
                self.progress = Double(i + 1) / Double(totalPages)
            }
        }
        
        newDocument.write(to: tempURL)
    }
    
    private func processJPEG(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        guard let compressedData = compressImage(image, format: .jpeg, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        try compressedData.write(to: tempURL)
    }
    
    private func processPNG(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        guard let compressedData = compressImage(image, format: .png, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        try compressedData.write(to: tempURL)
    }
    
    private func processHEIC(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        guard let compressedData = compressImage(image, format: .jpeg, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        let jpegURL = tempURL.deletingPathExtension().appendingPathExtension("jpg")
        try compressedData.write(to: jpegURL)
    }
    
    private func processTIFF(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        guard let compressedData = compressImage(image, format: .jpeg, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        try compressedData.write(to: tempURL)
    }
    
    private func processGIF(from url: URL, to tempURL: URL) throws {
        guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
            throw CompressionError.conversionFailed
        }
        
        let frameCount = CGImageSourceGetCount(imageSource)
        
        if frameCount > 1 {
            try compressAnimatedGIF(imageSource, frameCount: frameCount, to: tempURL)
        } else {
            guard let image = NSImage(contentsOf: url) else {
                throw CompressionError.conversionFailed
            }
            
            let settings = CompressionSettings(
                pngCompressionLevel: 6,
                preserveMetadata: true,
                maxDimension: 2048,
                optimizeForWeb: true
            )
            
            guard let compressedData = compressImage(image, format: .png, settings: settings) else {
                throw CompressionError.compressionFailed
            }
            
            let pngURL = tempURL.deletingPathExtension().appendingPathExtension("png")
            try compressedData.write(to: pngURL)
        }
    }
    
    private func processBMP(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        guard let compressedData = compressImage(image, format: .png, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        let pngURL = tempURL.deletingPathExtension().appendingPathExtension("png")
        try compressedData.write(to: pngURL)
    }
    
    private func processWebP(from url: URL, to tempURL: URL, settings: CompressionSettings) throws {
        guard let image = NSImage(contentsOf: url) else {
            throw CompressionError.conversionFailed
        }
        
        let hasAlpha = imageHasAlpha(image)
        let format: NSBitmapImageRep.FileType = hasAlpha ? .png : .jpeg
        
        guard let compressedData = compressImage(image, format: format, settings: settings) else {
            throw CompressionError.compressionFailed
        }
        
        let newExt = hasAlpha ? "png" : "jpg"
        let newURL = tempURL.deletingPathExtension().appendingPathExtension(newExt)
        try compressedData.write(to: newURL)
    }
    
    // MARK: - Private Methods - Helper Functions
    private func compressPDFPage(_ page: PDFPage) throws -> PDFPage? {
        let pageRect = page.bounds(for: .mediaBox)
        
        let image = NSImage(size: pageRect.size)
        image.lockFocus()
        if let context = NSGraphicsContext.current?.cgContext {
            page.draw(with: .mediaBox, to: context)
        }
        image.unlockFocus()
        
        guard let tiffData = image.tiffRepresentation,
              let bitmap = NSBitmapImageRep(data: tiffData),
              let compressedData = bitmap.representation(
                using: .jpeg,
                properties: [.compressionFactor: 0.5]
              ),
              let compressedImage = NSImage(data: compressedData) else {
            return nil
        }
        
        return PDFPage(image: compressedImage)
    }
    
    private func compressImage(_ image: NSImage, format: NSBitmapImageRep.FileType, settings: CompressionSettings) -> Data? {
        
        guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
            
            return nil
        }
        
        let processedCGImage: CGImage
        if let maxDimension = settings.maxDimension {
            
            if let resized = resizeImage(cgImage, maxDimension: maxDimension) {
                processedCGImage = resized
                
            } else {
                
                processedCGImage = cgImage
            }
        } else {
            
            processedCGImage = cgImage
        }
        
        let bitmapRep = NSBitmapImageRep(cgImage: processedCGImage)
        
        
        var compressionProperties: [NSBitmapImageRep.PropertyKey: Any] = [:]
        
        switch format {
        case .jpeg:
            compressionProperties[.compressionFactor] = settings.quality
        case .png:
            compressionProperties[.compressionFactor] = 1.0
        default:
            break
        }
        
        return bitmapRep.representation(using: format, properties: compressionProperties)
    }
    
    private func imageHasAlpha(_ image: NSImage) -> Bool {
        guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
            return false
        }
        
        let alphaInfo = cgImage.alphaInfo
        return alphaInfo != .none && alphaInfo != .noneSkipLast && alphaInfo != .noneSkipFirst
    }
    
    private func resizeImage(_ cgImage: CGImage, maxDimension: CGFloat) -> CGImage? {
        let currentWidth = CGFloat(cgImage.width)
        let currentHeight = CGFloat(cgImage.height)
        
        // Calculate scale factor to maintain aspect ratio
        let scaleFactor = min(maxDimension / currentWidth, maxDimension / currentHeight)
        
        // Only resize if the image is larger than maxDimension
        if scaleFactor >= 1.0 {
            return cgImage
        }
        
        let newWidth = Int(currentWidth * scaleFactor)
        let newHeight = Int(currentHeight * scaleFactor)
        
        // Create a bitmap context with the proper color space and bitmap info
        let bitmapInfo: UInt32
        if cgImage.alphaInfo == .none {
            bitmapInfo = CGImageAlphaInfo.noneSkipLast.rawValue
        } else {
            bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
        }
        
        guard let context = CGContext(
            data: nil,
            width: newWidth,
            height: newHeight,
            bitsPerComponent: 8,
            bytesPerRow: 0,
            space: CGColorSpace(name: CGColorSpace.sRGB)!,
            bitmapInfo: bitmapInfo
        ) else {
            print("Debug - Failed to create context")
            return nil
        }
        
        // Set high quality image interpolation
        context.interpolationQuality = .high
        
        // Draw the image in the new size
        let newRect = CGRect(x: 0, y: 0, width: newWidth, height: newHeight)
        context.draw(cgImage, in: newRect)
        
        // Get the resized image
        guard let resizedImage = context.makeImage() else {
            
            return nil
        }
        
        
        return resizedImage
    }
    
    private func compressAnimatedGIF(_ imageSource: CGImageSource, frameCount: Int, to url: URL) throws {
        guard let destination = CGImageDestinationCreateWithURL(
            url as CFURL,
            UTType.gif.identifier as CFString,
            frameCount,
            nil
        ) else {
            throw CompressionError.compressionFailed
        }
        
        if let properties = CGImageSourceCopyProperties(imageSource, nil) {
            CGImageDestinationSetProperties(destination, properties)
        }
        
        let options: [CFString: Any] = [
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceThumbnailMaxPixelSize: 1024
        ]
        
        for i in 0..<frameCount {
            autoreleasepool {
                guard let frameProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, i, nil) else {
                    return
                }
                
                // Extract GIF-specific properties
                let gifProperties = (frameProperties as Dictionary)[kCGImagePropertyGIFDictionary] as? Dictionary<CFString, Any>
                
                // Get delay time for the frame
                let defaultDelay = 0.1
                let delayTime: Double
                if let delay = gifProperties?[kCGImagePropertyGIFDelayTime] as? Double {
                    delayTime = delay
                } else {
                    delayTime = defaultDelay
                }
                
                // Create optimized frame
                guard let frameImage = CGImageSourceCreateImageAtIndex(imageSource, i, options as CFDictionary) else {
                    return
                }
                
                // Prepare frame properties for destination
                let destFrameProperties: [CFString: Any] = [
                    kCGImagePropertyGIFDictionary: [
                        kCGImagePropertyGIFDelayTime: delayTime
                    ]
                ]
                
                CGImageDestinationAddImage(destination, frameImage, destFrameProperties as CFDictionary)
            }
            
            DispatchQueue.main.async {
                self.progress = Double(i + 1) / Double(frameCount)
            }
        }
        
        if !CGImageDestinationFinalize(destination) {
            throw CompressionError.compressionFailed
        }
    }
    
    // MARK: - Metadata Handling
    private func extractMetadata(from imageSource: CGImageSource) -> [CFString: Any]? {
        guard let properties = CGImageSourceCopyProperties(imageSource, nil) as? [CFString: Any] else {
            return nil
        }
        
        var metadata: [CFString: Any] = [:]
        
        // Extract relevant metadata while excluding unnecessary data
        let keysToPreserve: [CFString] = [
            kCGImagePropertyOrientation,
            kCGImagePropertyDPIHeight,
            kCGImagePropertyDPIWidth,
            kCGImagePropertyPixelHeight,
            kCGImagePropertyPixelWidth,
            kCGImagePropertyProfileName
        ]
        
        for key in keysToPreserve {
            if let value = properties[key] {
                metadata[key] = value
            }
        }
        
        return metadata
    }
    
    // MARK: - Quality and Optimization
    private func determineOptimalSettings(for image: NSImage, format: NSBitmapImageRep.FileType) -> CompressionSettings {
        let size = image.size
        let totalPixels = size.width * size.height
        
        // Base settings
        var settings = CompressionSettings()
        
        // Adjust quality based on image size
        if totalPixels > 4_000_000 { // 2000x2000 pixels
            settings.maxDimension = 2048
            settings.quality = 0.7
        } else if totalPixels > 1_000_000 { // 1000x1000 pixels
            settings.maxDimension = 1500
            settings.quality = 0.8
        } else {
            settings.maxDimension = nil
            settings.quality = 0.9
        }
        
        // Format-specific adjustments
        switch format {
        case .jpeg:
            // JPEG-specific optimizations
            if totalPixels > 8_000_000 {
                settings.quality = 0.6
            }
            settings.preserveMetadata = true
            
        case .png:
            // PNG-specific optimizations
            if imageHasAlpha(image) {
                settings.pngCompressionLevel = 7
            } else {
                settings.pngCompressionLevel = 9
            }
            settings.preserveMetadata = true
            
        default:
            settings.preserveMetadata = false
        }
        
        return settings
    }
    
    // MARK: - Progress Tracking
    private func updateProgress(_ progress: Double) {
        DispatchQueue.main.async {
            self.progress = min(max(progress, 0), 1)
        }
    }
}
    
    // MARK: - Extensions
    extension FileProcessor {
        enum FileType {
            case pdf
            case jpeg
            case png
            case heic
            case gif
            case tiff
            case bmp
            case webp
            case svg
            case raw
            case ico
            case mp4
            case mov
            case avi
            case mpeg2
            case quickTime
            case mp3
            case wav
            case m4a
            case aiff
            case unknown
            
            init(url: URL) {
                switch url.pathExtension.lowercased() {
                case "pdf": self = .pdf
                case "jpg", "jpeg": self = .jpeg
                case "png": self = .png
                case "heic": self = .heic
                case "gif": self = .gif
                case "tiff", "tif": self = .tiff
                case "bmp": self = .bmp
                case "webp": self = .webp
                case "svg": self = .svg
                case "raw", "cr2", "nef", "arw": self = .raw
                case "ico": self = .ico
                case "mp4": self = .mp4
                case "mov": self = .mov
                case "avi": self = .avi
                case "mpg", "mpeg": self = .mpeg2
                case "qt": self = .quickTime
                case "mp3": self = .mp3
                case "wav": self = .wav
                case "m4a": self = .m4a
                case "aiff", "aif": self = .aiff
                default: self = .unknown
                }
            }
            
            var isAudio: Bool {
                        switch self {
                        case .mp3, .wav, .m4a, .aiff:
                            return true
                        default:
                            return false
                        }
                    }
            
            var isVideo: Bool {
                switch self {
                case .mp4, .mov, .avi, .mpeg2, .quickTime:
                    return true
                default:
                    return false
                }
            }
            
            var defaultOutputExtension: String {
                switch self {
                case .pdf: return "pdf"
                case .jpeg: return "jpg"
                case .png: return "png"
                case .heic: return "jpg"
                case .gif: return "gif"
                case .tiff: return "jpg"
                case .bmp: return "png"
                case .webp: return "jpg"
                case .svg: return "svg"
                case .raw: return "jpg"
                case .ico: return "png"
                case .mp4, .mov, .avi, .mpeg2, .quickTime: return "mp4"
                case .mp3: return "mp3"
                case .wav: return "wav"
                case .m4a: return "m4a"
                case .aiff: return "aiff"
                case .unknown: return ""
                }
            }
        }
    }


================================================
FILE: Achico/Processor/VideoProcessor.swift
================================================
import Foundation
import AVFoundation

@available(macOS 12.0, *)
actor VideoProcessor {
    enum VideoError: LocalizedError {
        case exportFailed
        case invalidInput
        case compressionFailed
        
        var errorDescription: String? {
            switch self {
            case .exportFailed: return "Failed to export video"
            case .invalidInput: return "Invalid input video"
            case .compressionFailed: return "Video compression failed"
            }
        }
    }
    
    struct VideoCompressionSettings: Sendable {
        let quality: Float
        let maxWidth: Int?
        let bitrateMultiplier: Float
        let frameRate: Int?
        let audioEnabled: Bool
        
        init(
            quality: Float = 0.7,
            maxWidth: Int? = nil,
            bitrateMultiplier: Float = 0.7,
            frameRate: Int? = 30,
            audioEnabled: Bool = true
        ) {
            self.quality = quality
            self.maxWidth = maxWidth
            self.bitrateMultiplier = bitrateMultiplier
            self.frameRate = frameRate
            self.audioEnabled = audioEnabled
        }
    }
    
    func compressVideo(
        inputURL: URL,
        outputURL: URL,
        settings: VideoCompressionSettings,
        progressHandler: @Sendable @escaping (Float) -> Void
    ) async throws {
        let asset = AVAsset(url: inputURL)
        
        // Get video track
        guard let videoTrack = try? await asset.loadTracks(withMediaType: .video).first else {
            throw VideoError.invalidInput
        }
        
        // Get original dimensions and apply size limit if needed
        let originalSize = try await videoTrack.load(.naturalSize)
        var targetSize = originalSize
        
        if let maxWidth = settings.maxWidth {
            let scale = Float(maxWidth) / Float(originalSize.width)
            if scale < 1.0 {
                targetSize = CGSize(
                    width: CGFloat(maxWidth),
                    height: CGFloat(Float(originalSize.height) * scale)
                )
            }
        }
        
        // Get original frame rate
        let nominalFrameRate = try await videoTrack.load(.nominalFrameRate)
        let targetFrameRate = Float(settings.frameRate ?? Int(nominalFrameRate))
        
        // Create export session
        guard let exportSession = AVAssetExportSession(
            asset: asset,
            presetName: AVAssetExportPresetHighestQuality
        ) else {
            throw VideoError.exportFailed
        }
        
        // Calculate bitrate
        let originalBitrate = try await estimateBitrate(for: videoTrack)
        let targetBitrate = Int(Float(originalBitrate) * settings.bitrateMultiplier)
        
        // Configure compression
        let compressionProperties: [String: Any] = [
            AVVideoAverageBitRateKey: targetBitrate,
            AVVideoProfileLevelKey: AVVideoProfileLevelH264HighAutoLevel,
            AVVideoH264EntropyModeKey: AVVideoH264EntropyModeCABAC
        ]
        
        // Video settings
        let videoSettings: [String: Any] = [
            AVVideoCodecKey: AVVideoCodecType.h264,
            AVVideoWidthKey: Int(targetSize.width),
            AVVideoHeightKey: Int(targetSize.height),
            AVVideoCompressionPropertiesKey: compressionProperties
        ]
        
        // Create and configure video composition
        let composition = AVMutableVideoComposition()
        composition.renderSize = targetSize
        composition.frameDuration = CMTime(value: 1, timescale: CMTimeScale(targetFrameRate))
        
        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRange(
            start: .zero,
            duration: try await asset.load(.duration)
        )
        
        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
        
        // Calculate transform for proper resizing
        let originalTransform = try await videoTrack.load(.preferredTransform)
        var finalTransform = originalTransform
        
        let scaleX = targetSize.width / originalSize.width
        let scaleY = targetSize.height / originalSize.height
        
        // Apply scaling transform
        finalTransform = finalTransform.concatenating(CGAffineTransform(scaleX: scaleX, y: scaleY))
        
        layerInstruction.setTransform(finalTransform, at: .zero)
        instruction.layerInstructions = [layerInstruction]
        composition.instructions = [instruction]
        
        // Configure export session
        exportSession.videoComposition = composition
        exportSession.outputURL = outputURL
        exportSession.outputFileType = .mp4
        
        // Use Task for progress monitoring
        let progressTask = Task { @MainActor in
            repeat {
                progressHandler(exportSession.progress)
                try await Task.sleep(nanoseconds: 100_000_000) // 0.1 second
            } while exportSession.status == .exporting
        }
        
        // Start export and wait for completion
        try await withCheckedThrowingContinuation { continuation in
            exportSession.exportAsynchronously {
                progressTask.cancel() // Stop progress monitoring
                switch exportSession.status {
                case .completed:
                    continuation.resume()
                case .failed:
                    let error = exportSession.error ?? VideoError.exportFailed
                    continuation.resume(throwing: error)
                default:
                    continuation.resume(throwing: VideoError.compressionFailed)
                }
            }
        }
    }
    
    private func estimateBitrate(for videoTrack: AVAssetTrack) async throws -> Int {
        let duration = try await videoTrack.load(.timeRange).duration.seconds
        let size = try await videoTrack.load(.totalSampleDataLength)
        return Int(Double(size) * 8 / duration) // bits per second
    }
}


================================================
FILE: Achico/Resources/Assets.xcassets/AccentColor.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "display-p3",
        "components" : {
          "alpha" : "1.000",
          "blue" : "0.850",
          "green" : "0.470",
          "red" : "0.250"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon-16.png",
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "16x16"
    },
    {
      "filename" : "AppIcon-32 1.png",
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "16x16"
    },
    {
      "filename" : "AppIcon-32.png",
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "32x32"
    },
    {
      "filename" : "AppIcon-64.png",
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "32x32"
    },
    {
      "filename" : "AppIcon-128.png",
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "128x128"
    },
    {
      "filename" : "AppIcon-256 1.png",
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "128x128"
    },
    {
      "filename" : "AppIcon-256.png",
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "256x256"
    },
    {
      "filename" : "AppIcon-512 1.png",
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "256x256"
    },
    {
      "filename" : "AppIcon-512.png",
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "512x512"
    },
    {
      "filename" : "AppIcon-1024.png",
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "512x512"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Resources/Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Achico/Resources/CompressionSettings.swift
================================================
import Foundation
import CoreGraphics

public struct CompressionSettings {
    var quality: CGFloat = 0.7        // JPEG/HEIC quality (0.0-1.0)
    var pngCompressionLevel: Int = 6  // PNG compression (0-9)
    var preserveMetadata: Bool = false
    var maxDimension: CGFloat? = nil  // Downsample if larger
    var optimizeForWeb: Bool = true   // Additional optimizations for web use
    var audioBitRate: Int?        // In bits per second
    var audioSampleRate: Double? // In Hertz
    
    public init(
        quality: CGFloat = 0.7,
        pngCompressionLevel: Int = 6,
        preserveMetadata: Bool = false,
        maxDimension: CGFloat? = nil,
        optimizeForWeb: Bool = true
    ) {
        self.quality = quality
        self.pngCompressionLevel = pngCompressionLevel
        self.preserveMetadata = preserveMetadata
        self.maxDimension = maxDimension
        self.optimizeForWeb = optimizeForWeb
    }
}


================================================
FILE: Achico/Resources/FileDropDelegate.swift
================================================
import SwiftUI
import UniformTypeIdentifiers
struct FileDropDelegate: DropDelegate {
    @Binding var isDragging: Bool
    let supportedTypes: [UTType]
    let handleDrop: ([NSItemProvider]) -> Void
    
    func validateDrop(info: DropInfo) -> Bool {
        return info.hasItemsConforming(to: supportedTypes.map(\.identifier))
    }
    
    func dropEntered(info: DropInfo) {
        isDragging = true
    }
    
    func dropExited(info: DropInfo) {
        isDragging = false
    }
    
    func performDrop(info: DropInfo) -> Bool {
        isDragging = false
        let providers = info.itemProviders(for: supportedTypes.map(\.identifier))
        handleDrop(providers)
        return true
    }
}


================================================
FILE: Achico/Resources/MenuBarController.swift
================================================
import SwiftUI
import AppKit

class MenuBarController: NSObject, ObservableObject {
    @Published private(set) var updater = UpdateChecker()
    private var statusItem: NSStatusItem!
    
    override init() {
        super.init()
        
        // Initialize status item on main queue
        DispatchQueue.main.async {
            self.setupMenuBar()
            self.updater.checkForUpdates()
        }
    }
    
    private func setupMenuBar() {
        // Create the status item
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        
        if let button = statusItem.button {
            button.image = NSImage(systemSymbolName: "checkmark.circle", accessibilityDescription: "Update Status")
            
            // Create the menu
            let menu = NSMenu()
            menu.delegate = self
            
            // Set the menu
            statusItem.menu = menu
            
            // Update the button image when the status changes
            updater.onStatusChange = { [weak self] newIcon in
                guard self != nil else { return }
                DispatchQueue.main.async {
                    button.image = NSImage(systemSymbolName: newIcon, accessibilityDescription: "Update Status")
                }
            }
        }
    }
    
    @objc private func checkForUpdates() {
        updater.checkForUpdates()
    }
    
    @objc private func downloadUpdate() {
        if let url = updater.downloadURL {
            NSWorkspace.shared.open(url)
        }
    }
}

extension MenuBarController: NSMenuDelegate {
    func menuWillOpen(_ menu: NSMenu) {
        // Clear existing items
        menu.removeAllItems()
        
        // Add version
        let versionItem = NSMenuItem(title: "Achico v\(Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "1.0.0")", action: nil, keyEquivalent: "")
        versionItem.isEnabled = false
        menu.addItem(versionItem)
        
        menu.addItem(NSMenuItem.separator())
        
        // Add status
        if updater.isChecking {
            let checkingItem = NSMenuItem(title: "Checking for updates...", action: nil, keyEquivalent: "")
            checkingItem.isEnabled = false
            menu.addItem(checkingItem)
        } else if updater.updateAvailable {
            if let version = updater.latestVersion {
                let availableItem = NSMenuItem(title: "Version \(version) Available", action: nil, keyEquivalent: "")
                availableItem.isEnabled = false
                menu.addItem(availableItem)
            }
            let downloadItem = NSMenuItem(title: "Download Update", action: #selector(downloadUpdate), keyEquivalent: "")
            downloadItem.target = self
            menu.addItem(downloadItem)
        } else {
            let upToDateItem = NSMenuItem(title: "App is up to date", action: nil, keyEquivalent: "")
            upToDateItem.isEnabled = false
            menu.addItem(upToDateItem)
        }
        
        menu.addItem(NSMenuItem.separator())
        
        // Add check for updates item
        let checkItem = NSMenuItem(title: "Check for Updates...", action: #selector(checkForUpdates), keyEquivalent: "u")
        checkItem.target = self
        menu.addItem(checkItem)
    }
    
    func menuDidClose(_ menu: NSMenu) {
        // Optional: Handle menu closing
    }
    
    func numberOfItems(in menu: NSMenu) -> Int {
        // Let the menu build dynamically
        return menu.numberOfItems
    }
}


================================================
FILE: Achico/Resources/UpdateChecker.swift
================================================
import Foundation

struct GitHubRelease: Codable {
    let tagName: String
    let name: String
    let body: String
    let htmlUrl: String
    
    enum CodingKeys: String, CodingKey {
        case tagName = "tag_name"
        case name
        case body
        case htmlUrl = "html_url"
    }
}

class UpdateChecker: ObservableObject {
    @Published var updateAvailable = false
    @Published var latestVersion: String?
    @Published var releaseNotes: String?
    @Published var downloadURL: URL?
    @Published var isChecking = false
    @Published var error: String?
    @Published var statusIcon: String = "checkmark.circle"
    
    var onStatusChange: ((String) -> Void)?
    var onUpdateAvailable: (() -> Void)?
    
    private let currentVersion: String
    private let githubRepo: String
    private var updateCheckTimer: Timer?
    
    init() {
            self.currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "1.0.0"
            self.githubRepo = "nuance-dev/Achico"
            setupTimer()
            updateStatusIcon()
        }
    
    private func setupTimer() {
        // Initial check after 2 seconds
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
            self?.checkForUpdates()
        }
        
        // Periodic check every 24 hours
        updateCheckTimer = Timer.scheduledTimer(withTimeInterval: 24 * 60 * 60, repeats: true) { [weak self] _ in
            self?.checkForUpdates()
        }
    }
    
    private func updateStatusIcon() {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if self.isChecking {
                self.statusIcon = "arrow.triangle.2.circlepath"
            } else {
                self.statusIcon = self.updateAvailable ? "exclamationmark.circle" : "checkmark.circle"
            }
            self.onStatusChange?(self.statusIcon)
        }
    }
    
    func checkForUpdates() {
        print("Checking for updates...")
        print("Current version: \(currentVersion)")
        
        isChecking = true
        updateStatusIcon()
        error = nil
        
        let baseURL = "https://api.github.com/repos/\(githubRepo)/releases/latest"
        guard let url = URL(string: baseURL) else {
            error = "Invalid GitHub repository URL"
            isChecking = false
            updateStatusIcon()
            return
        }
        
        var request = URLRequest(url: url)
        request.setValue("application/vnd.github.v3+json", forHTTPHeaderField: "Accept")
        request.setValue("Achico-App/\(currentVersion)", forHTTPHeaderField: "User-Agent")
        
        URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
            DispatchQueue.main.async {
                self?.handleUpdateResponse(data: data, response: response as? HTTPURLResponse, error: error)
            }
        }.resume()
    }
    
    private func handleUpdateResponse(data: Data?, response: HTTPURLResponse?, error: Error?) {
        defer {
            isChecking = false
            updateStatusIcon()
        }
        
        if let error = error {
            print("Network error: \(error)")
            self.error = "Network error: \(error.localizedDescription)"
            return
        }
        
        guard let response = response else {
            print("Invalid response")
            self.error = "Invalid response from server"
            return
        }
        
        print("Response status code: \(response.statusCode)")
        
        guard response.statusCode == 200 else {
            self.error = "Server error: \(response.statusCode)"
            return
        }
        
        guard let data = data else {
            self.error = "No data received"
            return
        }
        
        do {
            
            let decoder = JSONDecoder()
            let release = try decoder.decode(GitHubRelease.self, from: data)
            
            let cleanLatestVersion = release.tagName.replacingOccurrences(of: "v", with: "")
            print("Latest version: \(cleanLatestVersion)")
            print("Current version for comparison: \(currentVersion)")
            
            updateAvailable = compareVersions(current: currentVersion, latest: cleanLatestVersion)
                        if updateAvailable {
                            DispatchQueue.main.async {
                                self.onUpdateAvailable?()
                            }
                        }
            
            latestVersion = cleanLatestVersion
            releaseNotes = release.body
            downloadURL = URL(string: release.htmlUrl)
            
            updateAvailable = compareVersions(current: currentVersion, latest: cleanLatestVersion)
            print("Update available: \(updateAvailable)")
            
        } catch {
            print("Parsing error: \(error)")
            self.error = "Failed to parse response: \(error.localizedDescription)"
        }
    }
    
    private func compareVersions(current: String, latest: String) -> Bool {
        // Clean and split versions
        let currentParts = current.replacingOccurrences(of: "v", with: "")
            .split(separator: ".")
            .compactMap { Int($0) }
        
        let latestParts = latest.replacingOccurrences(of: "v", with: "")
            .split(separator: ".")
            .compactMap { Int($0) }
        
        
        // Ensure we have at least 3 components (major.minor.patch)
        let paddedCurrent = currentParts + Array(repeating: 0, count: max(3 - currentParts.count, 0))
        let paddedLatest = latestParts + Array(repeating: 0, count: max(3 - latestParts.count, 0))
        
        
        // Compare each version component
        for i in 0..<min(paddedCurrent.count, paddedLatest.count) {
            if paddedLatest[i] > paddedCurrent[i] {
                return true
            } else if paddedLatest[i] < paddedCurrent[i] {
                return false
            }
        }
        
        print("Versions are equal")
        return false
    }
    
    deinit {
        updateCheckTimer?.invalidate()
    }
}


================================================
FILE: Achico/UI Components/ButtonGroup.swift
================================================
import SwiftUI

struct ToolbarButton: View {
    let title: String
    let icon: String
    let action: () -> Void
    let isFirst: Bool
    let isLast: Bool
    
    var body: some View {
        Button(action: action) {
            HStack(spacing: 6) {
                Image(systemName: icon)
                    .font(.system(size: 14))
                Text(title)
                    .font(.system(size: 13, weight: .medium))
            }
            .frame(height: 36)
            .padding(.horizontal, 16)
            .foregroundColor(.primary)
            .background(Color.clear)
            .contentShape(Rectangle())
        }
        .buttonStyle(PlainButtonStyle())
    }
}

struct ButtonDivider: View {
    var body: some View {
        Divider()
            .frame(height: 24)
    }
}

struct ButtonGroup: View {
    let buttons: [(title: String, icon: String, action: () -> Void)]
    
    var body: some View {
        HStack(spacing: 0) {
            ForEach(Array(buttons.enumerated()), id: \.offset) { index, button in
                if index > 0 {
                    ButtonDivider()
                }
                
                ToolbarButton(
                    title: button.title,
                    icon: button.icon,
                    action: button.action,
                    isFirst: index == 0,
                    isLast: index == buttons.count - 1
                )
            }
        }
        .background(backgroundView)
    }
    
    private var backgroundView: some View {
        ZStack {
            // Base background
            RoundedRectangle(cornerRadius: 12)
                .fill(Color(NSColor.windowBackgroundColor).opacity(0.5))
            
            // Subtle border
            RoundedRectangle(cornerRadius: 12)
                .strokeBorder(Color.primary.opacity(0.1), lineWidth: 1)
            
            // Glass effect overlay
            RoundedRectangle(cornerRadius: 12)
                .stroke(Color.white.opacity(0.1), lineWidth: 1)
        }
    }
}


================================================
FILE: Achico/UI Components/GlassButtonStyle.swift
================================================
import SwiftUI

struct GlassButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding(.horizontal, 20)
            .padding(.vertical, 10)
            .background(
                RoundedRectangle(cornerRadius: 8)
                    .fill(Color.primary.opacity(0.1))
                    .overlay(
                        RoundedRectangle(cornerRadius: 8)
                            .stroke(Color.primary.opacity(0.2), lineWidth: 1)
                    )
            )
            .opacity(configuration.isPressed ? 0.8 : 1.0)
    }
}


================================================
FILE: Achico/UI Components/TitleBarAccessory.swift
================================================
import SwiftUI

struct TitleBarAccessory: View {
    @AppStorage("isDarkMode") private var isDarkMode = false
    
    var body: some View {
        Button(action: {
            isDarkMode.toggle()
        }) {
            Image(systemName: isDarkMode ? "sun.max.fill" : "moon.fill")
                .foregroundColor(.primary)
        }
        .buttonStyle(PlainButtonStyle())
        .frame(width: 30, height: 30)
    }
}


================================================
FILE: Achico/UI Components/VisualEffectBlur.swift
================================================
import SwiftUI

struct VisualEffectBlur: NSViewRepresentable {
    var material: NSVisualEffectView.Material
    var blendingMode: NSVisualEffectView.BlendingMode
    
    func makeNSView(context: Context) -> NSVisualEffectView {
        let view = NSVisualEffectView()
        view.state = .active
        view.material = material
        view.blendingMode = blendingMode
        view.alphaValue = 0.9
        return view
    }
    
    func updateNSView(_ nsView: NSVisualEffectView, context: Context) {}
}


================================================
FILE: Achico/UI Components/WindowAccessor.swift
================================================
import SwiftUI

struct WindowAccessor: NSViewRepresentable {
    func makeNSView(context: Context) -> NSView {
        let nsView = NSView()
        
        DispatchQueue.main.async {
            if let window = nsView.window {
                let titleBarAccessory = NSTitlebarAccessoryViewController()
                let hostingView = NSHostingView(rootView: TitleBarAccessory())
                
                hostingView.frame.size = hostingView.fittingSize
                titleBarAccessory.view = hostingView
                titleBarAccessory.layoutAttribute = .trailing
                
                window.addTitlebarAccessoryViewController(titleBarAccessory)
            }
        }
        
        return nsView
    }
    
    func updateNSView(_ nsView: NSView, context: Context) {}
}


================================================
FILE: Achico/Views/ContentView.swift
================================================
import SwiftUI
import UniformTypeIdentifiers
import AppKit

struct ContentView: View {
    @StateObject private var processor = FileProcessor()
    @StateObject private var multiProcessor = MultiFileProcessor()
    @State private var isDragging = false
    @State private var showAlert = false
    @State private var alertMessage = ""
    @State private var shouldResize = false
    @State private var maxDimension = "2048"
    
    let supportedTypes: [UTType] = [
        .pdf,      // PDF Documents
        .jpeg,     // JPEG Images
        .tiff,     // TIFF Images
        .png,      // PNG Images
        .heic,     // HEIC Images
        .gif,      // GIF Images
        .bmp,      // BMP Images
        .webP,     // WebP Images
        .svg,      // SVG Images
        .rawImage, // RAW Images
        .ico,      // ICO Images
        .mpeg4Movie,    // MP4 Video
        .movie,         // MOV
        .avi,          // AVI
        .mpeg2Video,   // MPEG-2
        .quickTimeMovie, // QuickTime
        .mpeg4Audio,     // MP4 Audio
        .mp3,          // MP3 Audio
        .wav,          // WAV Audio
        .aiff,         // AIFF Audio
    ]
    
    var body: some View {
        ZStack {
            VisualEffectBlur(material: .headerView, blendingMode: .behindWindow)
                .ignoresSafeArea()
            
            VStack(spacing: 20) {
                if processor.isProcessing {
                    // Single file processing view
                    VStack(spacing: 24) {
                        // Progress Circle
                        ZStack {
                            Circle()
                                .stroke(Color.secondary.opacity(0.2), lineWidth: 4)
                                .frame(width: 60, height: 60)
                            
                            Circle()
                                .trim(from: 0, to: processor.progress)
                                .stroke(Color.accentColor, style: StrokeStyle(lineWidth: 4, lineCap: .round))
                                .frame(width: 60, height: 60)
                                .rotationEffect(.degrees(-90))
                            
                            Text("\(Int(processor.progress * 100))%")
                                .font(.system(size: 14, weight: .medium))
                        }
                        
                        VStack(spacing: 8) {
                            Text("Compressing File")
                                .font(.system(size: 16, weight: .semibold))
                            Text("This may take a moment...")
                                .font(.system(size: 14))
                                .foregroundColor(.secondary)
                        }
                    }
                    .frame(maxWidth: 320)
                    .padding(32)
                    .background(
                        RoundedRectangle(cornerRadius: 16)
                            .fill(Color(NSColor.windowBackgroundColor))
                            .opacity(0.8)
                            .shadow(color: Color.black.opacity(0.1), radius: 20, x: 0, y: 10)
                    )
                } else if let result = processor.processingResult {
                    ResultView(result: result) {
                        Task {
                            await saveCompressedFile(url: result.compressedURL, originalName: result.fileName)
                        }
                    } onReset: {
                        processor.cleanup()
                    }
                } else if !multiProcessor.files.isEmpty {
                    MultiFileView(
                        processor: multiProcessor,
                        shouldResize: $shouldResize,
                        maxDimension: $maxDimension,
                        supportedTypes: supportedTypes
                    )
                } else {
                    ZStack {
                        DropZoneView(
                            isDragging: $isDragging,
                            shouldResize: $shouldResize,
                            maxDimension: $maxDimension,
                            onTap: selectFiles
                        )
                        
                        Rectangle()
                            .fill(Color.clear)
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                            .overlay(isDragging ? Color.accentColor.opacity(0.2) : Color.clear)
                            .onDrop(of: supportedTypes, isTargeted: $isDragging) { providers in
                                handleDrop(providers: providers)
                                return true
                            }
                    }
                }
            }
            .padding()
        }
        .frame(minWidth: 400, minHeight: 500)
        .alert("Error", isPresented: $showAlert) {
            Button("OK", role: .cancel) { }
        } message: {
            Text(alertMessage)
        }
    }
    
    private func selectFiles() {
        let panel = NSOpenPanel()
        panel.allowedContentTypes = supportedTypes
        panel.allowsMultipleSelection = true
        
        if let window = NSApp.windows.first {
            panel.beginSheetModal(for: window) { response in
                if response == .OK {
                    if panel.urls.count == 1, let url = panel.urls.first {
                        print("📁 Selected single file: \(url.path)")
                        print("📝 Original filename: \(url.lastPathComponent)")
                        handleFileSelection(url: url, originalFilename: url.lastPathComponent)  // Pass originalFilename
                    } else if panel.urls.count > 1 {
                        print("📁 Selected multiple files: \(panel.urls.map { $0.lastPathComponent })")
                        Task { @MainActor in
                            multiProcessor.addFiles(panel.urls)
                        }
                    }
                }
            }
        }
    }
        
        private func handleDrop(providers: [NSItemProvider]) {
            print("🔄 Handling drop with \(providers.count) providers")
            if providers.count == 1 {
                guard let provider = providers.first else { return }
                handleSingleFileDrop(provider: provider)
            } else {
                handleMultiFileDrop(providers: providers)
            }
        }
        
    private func handleSingleFileDrop(provider: NSItemProvider) {
        for type in supportedTypes {
            if provider.hasItemConformingToTypeIdentifier(type.identifier) {
                print("📥 Processing dropped file of type: \(type.identifier)")
                provider.loadFileRepresentation(forTypeIdentifier: type.identifier) { url, error in
                    guard let url = url else {
                        print("❌ Failed to load dropped file URL")
                        Task { @MainActor in
                            alertMessage = "Failed to load file"
                            showAlert = true
                        }
                        return
                    }
                    
                    print("📄 Original dropped file URL: \(url.path)")
                    let originalFilename = url.lastPathComponent
                    print("📝 Original dropped filename: \(originalFilename)")
                    
                    let tempURL = FileManager.default.temporaryDirectory
                        .appendingPathComponent(UUID().uuidString)
                        .appendingPathExtension(url.pathExtension)
                    
                    print("🔄 Creating temp file at: \(tempURL.path)")
                    
                    do {
                        try FileManager.default.copyItem(at: url, to: tempURL)
                        print("✅ Successfully copied to temp location")
                        
                        Task { @MainActor in
                            handleFileSelection(url: tempURL, originalFilename: originalFilename)  // Pass originalFilename
                        }
                    } catch {
                        print("❌ Failed to copy dropped file: \(error.localizedDescription)")
                        Task { @MainActor in
                            alertMessage = "Failed to process dropped file"
                            showAlert = true
                        }
                    }
                }
                return
            }
        }
    }

    private func handleFileSelection(url: URL, originalFilename: String? = nil) {
        print("🔄 Processing file selection for URL: \(url.path)")
        let filename = originalFilename ?? url.lastPathComponent
        print("📝 Original filename: \(filename)")
        
        Task {
            let dimensionValue = shouldResize ? Double(maxDimension) ?? 2048 : nil
            let settings = CompressionSettings(
                quality: 0.7,
                pngCompressionLevel: 6,
                preserveMetadata: true,
                maxDimension: dimensionValue != nil ? CGFloat(dimensionValue!) : nil,
                optimizeForWeb: true
            )
            
            do {
                try await processor.processFile(url: url, settings: settings, originalFileName: filename)
            } catch {
                print("❌ File processing error: \(error.localizedDescription)")
                await MainActor.run {
                    alertMessage = error.localizedDescription
                    showAlert = true
                }
            }
        }
    }
        
        private func handleMultiFileDrop(providers: [NSItemProvider]) {
            Task {
                print("📥 Processing multiple dropped files")
                var urls: [URL] = []
                
                for (index, provider) in providers.enumerated() {
                    for type in supportedTypes {
                        if provider.hasItemConformingToTypeIdentifier(type.identifier) {
                            do {
                                let url = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<URL, Error>) in
                                    provider.loadFileRepresentation(forTypeIdentifier: type.identifier) { url, error in
                                        if let error = error {
                                            print("❌ Error loading file \(index + 1): \(error.localizedDescription)")
                                            continuation.resume(throwing: error)
                                        } else if let url = url {
                                            print("📄 Original file \(index + 1) URL: \(url.path)")
                                            print("📝 Original filename \(index + 1): \(url.lastPathComponent)")
                                            
                                            let originalFileName = url.lastPathComponent
                                            let tempURL = FileManager.default.temporaryDirectory
                                                .appendingPathComponent("\(UUID().uuidString)_\(originalFileName)")
                                            
                                            print("🔄 Creating temp file \(index + 1) at: \(tempURL.path)")
                                            
                                            do {
                                                try FileManager.default.copyItem(at: url, to: tempURL)
                                                print("✅ Successfully copied file \(index + 1) to temp location")
                                                continuation.resume(returning: tempURL)
                                            } catch {
                                                print("❌ Failed to copy file \(index + 1): \(error.localizedDescription)")
                                                continuation.resume(throwing: error)
                                            }
                                        } else {
                                            print("❌ No URL available for file \(index + 1)")
                                            continuation.resume(throwing: NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to load file"]))
                                        }
                                    }
                                }
                                
                                urls.append(url)
                            } catch {
                                print("❌ Failed to process dropped file \(index + 1): \(error.localizedDescription)")
                            }
                            break
                        }
                    }
                }
                
                if !urls.isEmpty {
                    print("✅ Successfully processed \(urls.count) files")
                    print("📁 Temp URLs: \(urls.map { $0.path })")
                    await MainActor.run {
                        multiProcessor.addFiles(urls)
                    }
                }
            }
        }
        
    private func handleFileSelection(url: URL) {
        print("🔄 Processing file selection for URL: \(url.path)")
        print("📝 Original filename: \(url.lastPathComponent)")
        
        Task {
            let dimensionValue = shouldResize ? Double(maxDimension) ?? 2048 : nil
            let settings = CompressionSettings(
                quality: 0.7,
                pngCompressionLevel: 6,
                preserveMetadata: true,
                maxDimension: dimensionValue != nil ? CGFloat(dimensionValue!) : nil,
                optimizeForWeb: true
            )
            
            do {
                // Store original filename before processing
                let originalFileName = url.lastPathComponent
                try await processor.processFile(url: url, settings: settings, originalFileName: originalFileName)
            } catch {
                print("❌ File processing error: \(error.localizedDescription)")
                await MainActor.run {
                    alertMessage = error.localizedDescription
                    showAlert = true
                }
            }
        }
    }
        
    @MainActor
    func saveCompressedFile(url: URL, originalName: String) async {
        print("💾 Saving compressed file")
        print("📝 Original name: \(originalName)")
        print("📁 Compressed file URL: \(url.path)")
        
        let panel = NSSavePanel()
        panel.canCreateDirectories = true
        panel.showsTagField = false
        
        // Extract original filename without UUID
        let originalURL = URL(fileURLWithPath: originalName)
        let filenameWithoutExt = originalURL.deletingPathExtension().lastPathComponent
            .replacingOccurrences(of: #"[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\."#,
                                 with: "",
                                 options: .regularExpression)
        let fileExtension = url.pathExtension
        
        let suggestedName = "\(filenameWithoutExt)_compressed.\(fileExtension)"
        print("📝 Suggested save name: \(suggestedName)")
        panel.nameFieldStringValue = suggestedName
        
        panel.allowedContentTypes = [UTType(filenameExtension: fileExtension)].compactMap { $0 }
        panel.message = "Choose where to save the compressed file"
        
        guard let window = NSApp.windows.first else { return }
        
        let response = await panel.beginSheetModal(for: window)
        
        if response == .OK, let saveURL = panel.url {
            print("📥 Saving to: \(saveURL.path)")
            do {
                // Check if file exists
                if FileManager.default.fileExists(atPath: saveURL.path) {
                    try FileManager.default.removeItem(at: saveURL)
                }
                
                try FileManager.default.copyItem(at: url, to: saveURL)
                print("✅ File saved successfully")
                processor.cleanup()
            } catch {
                print("❌ Save error: \(error.localizedDescription)")
                alertMessage = "Failed to save file: \(error.localizedDescription)"
                showAlert = true
            }
        } else {
            print("❌ Save cancelled or window not found")
        }
    }
}


================================================
FILE: Achico/Views/DropZoneView.swift
================================================
import SwiftUI

struct DropZoneView: View {
    @Binding var isDragging: Bool
    @Binding var shouldResize: Bool
    @Binding var maxDimension: String
    let onTap: () -> Void
    
    var body: some View {
        Button(action: onTap) {
            ZStack(alignment: .bottom) {
                // Main drop zone content - centered
                VStack(spacing: 12) {
                    Image(systemName: "doc.circle")
                        .font(.system(size: 32))
                        .foregroundColor(.secondary)
                    
                    Text("Drop your file here")
                        .font(.system(size: 14))
                        .foregroundColor(.secondary)
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                
                // Resize controls - bottom aligned
                HStack(spacing: 12) {
                    Toggle("Resize", isOn: $shouldResize)
                        .toggleStyle(.switch)
                        .labelsHidden()
                    
                    Text("Resize")
                        .font(.system(size: 13))
                        .foregroundColor(.secondary)
                    
                    if shouldResize {
                        TextField("px", text: $maxDimension)
                            .frame(width: 60)
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                            .font(.system(size: 13))
                            .multilineTextAlignment(.trailing)
                        
                        Text("px")
                            .font(.system(size: 13))
                            .foregroundColor(.secondary)
                    }
                }
                .padding(.horizontal, 16)
                .padding(.vertical, 8)
                .background(
                    RoundedRectangle(cornerRadius: 20)
                        .fill(Color(NSColor.controlBackgroundColor).opacity(0.5))
                )
                .padding(.bottom, 24)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(
                RoundedRectangle(cornerRadius: 12)
                    .strokeBorder(isDragging ? Color.accentColor : Color.secondary.opacity(0.2),
                                style: StrokeStyle(lineWidth: 1))
                    .background(Color.clear)
            )
            .padding()
        }
        .buttonStyle(PlainButtonStyle())
    }
}


================================================
FILE: Achico/Views/MenuBarView.swift
================================================
import SwiftUI
import AppKit

struct MenuBarView: View {
    @ObservedObject var updater: UpdateChecker
    @EnvironmentObject var menuBarController: MenuBarController
    @Environment(\.dismiss) var dismiss
    
    private var appIcon: NSImage {
        if let bundleIcon = NSImage(named: NSImage.applicationIconName) {
            return bundleIcon
        }
        return NSWorkspace.shared.icon(forFile: Bundle.main.bundlePath)
    }
    
    var body: some View {
        VStack(spacing: 16) {
            // App Icon and Version
            VStack(spacing: 8) {
                Image(nsImage: appIcon)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 64, height: 64)
                
                Text("Version \(Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "1.0.0")")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }
            .padding(.top, 16)
            
            // Status Section
            Group {
                if updater.isChecking {
                    VStack(spacing: 8) {
                        ProgressView()
                            .scaleEffect(1.2)
                        Text("Checking for updates...")
                            .font(.headline)
                            .foregroundColor(.secondary)
                    }
                } else if let error = updater.error {
                    VStack(spacing: 8) {
                        Image(systemName: "xmark.circle.fill")
                            .font(.system(size: 28))
                            .foregroundColor(.red)
                        Text(error)
                            .font(.subheadline)
                            .foregroundColor(.secondary)
                            .multilineTextAlignment(.center)
                    }
                } else if updater.updateAvailable {
                    VStack(spacing: 12) {
                        Image(systemName: "arrow.down.circle.fill")
                            .font(.system(size: 28))
                            .foregroundColor(.blue)
                        
                        if let version = updater.latestVersion {
                            Text("Version \(version) Available")
                                .font(.headline)
                        }
                        
                        if let notes = updater.releaseNotes {
                            ScrollView {
                                Text(notes)
                                    .font(.footnote)
                                    .foregroundColor(.secondary)
                                    .multilineTextAlignment(.center)
                                    .padding(.horizontal)
                            }
                            .frame(maxHeight: 80)
                        }
                        
                        Button {
                            if let url = updater.downloadURL {
                                NSWorkspace.shared.open(url)
                                dismiss()
                            }
                        } label: {
                            Text("Download Update")
                                .frame(maxWidth: 200)
                        }
                        .buttonStyle(.borderedProminent)
                    }
                } else {
                    VStack(spacing: 8) {
                        Image(systemName: "checkmark.circle.fill")
                            .font(.system(size: 28))
                            .foregroundColor(.green)
                        Text("Achico is up to date")
                            .font(.headline)
                    }
                }
            }
            .frame(maxWidth: .infinity, alignment: .center)
            .padding(.vertical, 8)
            
            Divider()
            
            // Bottom Buttons
            HStack(spacing: 16) {
                Button("Check Again") {
                    updater.checkForUpdates()
                }
                .buttonStyle(.plain)
                .foregroundColor(.blue)
                
                Button("Close") {
                    dismiss()
                }
                .buttonStyle(.plain)
                .foregroundColor(.secondary)
            }
            .padding(.bottom, 16)
            
            Text("Built by [Nuance](https://nuanc.me)")
                            .font(.footnote)
                            .foregroundColor(.secondary)
                            .padding(.bottom, 8)
        }
        .padding(.horizontal)
        .frame(width: 300)
        .fixedSize(horizontal: false, vertical: true)
    }
}


================================================
FILE: Achico/Views/MultiFileProcessingView.swift
================================================
import Foundation
import UniformTypeIdentifiers
import SwiftUI

struct FileProcessingState: Identifiable {
    let id: UUID
    let url: URL
    let originalFileName: String
    var progress: Double
    var result: FileProcessor.ProcessingResult?
    var isProcessing: Bool
    var error: Error?
    
    // Add this computed property
    var displayFileName: String {
        // If the filename contains UUID prefix, remove it
        let filename = url.lastPathComponent
        if let range = filename.range(of: "_") {
            return String(filename[range.upperBound...])
        }
        return originalFileName
    }
    
    init(url: URL) {
        self.id = UUID()
        self.url = url
        self.originalFileName = url.lastPathComponent
        self.progress = 0
        self.result = nil
        self.isProcessing = false
        self.error = nil
    }
}

@MainActor
class MultiFileProcessor: ObservableObject {
    @Published private(set) var files: [FileProcessingState] = []
    @Published private(set) var isProcessingMultiple = false
    private var processingTasks: [UUID: Task<Void, Never>] = [:]
    
    func addFiles(_ urls: [URL]) {
        let newFiles = urls.map { FileProcessingState(url: $0) }
        files.append(contentsOf: newFiles)
        
        // Process each new file individually
        for file in newFiles {
            processFile(with: file.id)
        }
    }
    
    func removeFile(at index: Int) {
        guard index < files.count else { return }
        let fileId = files[index].id
        processingTasks[fileId]?.cancel()
        processingTasks.removeValue(forKey: fileId)
        files.remove(at: index)
    }
    
    func clearFiles() {
        // Cancel all ongoing processing tasks
        for task in processingTasks.values {
            task.cancel()
        }
        processingTasks.removeAll()
        files.removeAll()
    }
    
    private func processFile(with id: UUID) {
        let task = Task {
            await processFileInternal(with: id)
        }
        processingTasks[id] = task
    }
    
    func saveAllFilesToFolder() async {
        let panel = NSOpenPanel()
        panel.canCreateDirectories = true
        panel.canChooseFiles = false
        panel.canChooseDirectories = true
        panel.message = "Choose where to save all compressed files"
        panel.prompt = "Select Folder"
        
        guard let window = NSApp.windows.first else { return }
        let response = await panel.beginSheetModal(for: window)
        
        if response == .OK, let folderURL = panel.url {
            for file in files {
                if let result = file.result {
                    do {
                        // Use the original filename instead of the result filename
                        let originalURL = URL(fileURLWithPath: file.originalFileName)
                        let filenameWithoutExt = originalURL.deletingPathExtension().lastPathComponent
                        let fileExtension = originalURL.pathExtension
                        let newFileName = "\(filenameWithoutExt)_compressed.\(fileExtension)"
                        let destinationURL = folderURL.appendingPathComponent(newFileName)
                        
                        try FileManager.default.copyItem(at: result.compressedURL, to: destinationURL)
                    } catch {
                        print("Failed to save file \(file.originalFileName): \(error.localizedDescription)")
                    }
                }
            }
        }
    }
    
    private func processFileInternal(with id: UUID) async {
        guard let index = files.firstIndex(where: { $0.id == id }) else { return }
        guard index < files.count else { return }
        
        let processor = FileProcessor()
        
        // Update the processing state
        files[index].isProcessing = true
        
        do {
            let settings = CompressionSettings(
                quality: 0.7,
                pngCompressionLevel: 6,
                preserveMetadata: true,
                optimizeForWeb: true
            )
            
            try await processor.processFile(url: files[index].url, settings: settings)
            
            guard index < files.count, files[index].id == id else { return }
            
            if let processingResult = processor.processingResult {
                files[index].result = processingResult
                files[index].isProcessing = false
            }
        } catch {
            guard index < files.count, files[index].id == id else { return }
            files[index].error = error
            files[index].isProcessing = false
        }
        
        // Clean up the task
        processingTasks.removeValue(forKey: id)
    }
    
    func saveCompressedFile(url: URL, originalName: String) async {
        let panel = NSSavePanel()
        panel.canCreateDirectories = true
        panel.showsTagField = false
        
        // Use originalName directly instead of extracting from URL
        let originalURL = URL(fileURLWithPath: originalName)
        let filenameWithoutExt = originalURL.deletingPathExtension().lastPathComponent
        let fileExtension = originalURL.pathExtension
        panel.nameFieldStringValue = "\(filenameWithoutExt)_compressed.\(fileExtension)"
        
        panel.allowedContentTypes = [UTType(filenameExtension: url.pathExtension)].compactMap { $0 }
        panel.message = "Choose where to save the compressed file"
        
        guard let window = NSApp.windows.first else { return }
        
        let response = await panel.beginSheetModal(for: window)
        
        if response == .OK, let saveURL = panel.url {
            do {
                // Check if file exists
                if FileManager.default.fileExists(atPath: saveURL.path) {
                    try FileManager.default.removeItem(at: saveURL)
                }
                
                try FileManager.default.copyItem(at: url, to: saveURL)
            } catch {
                print("Failed to save file: \(error.localizedDescription)")
            }
        }
    }
    
    func downloadAllFiles() async {
        for file in files {
            if let result = file.result {
                await saveCompressedFile(url: result.compressedURL, originalName: file.originalFileName)
            }
        }
    }
}

struct MultiFileView: View {
    @ObservedObject var processor: MultiFileProcessor
    @Binding var shouldResize: Bool
    @Binding var maxDimension: String
    let supportedTypes: [UTType]
    @State private var hoveredFileID: UUID?
    
    init(processor: MultiFileProcessor, shouldResize: Binding<Bool>, maxDimension: Binding<String>, supportedTypes: [UTType]) {
        self._processor = ObservedObject(wrappedValue: processor)
        self._shouldResize = shouldResize
        self._maxDimension = maxDimension
        self.supportedTypes = supportedTypes
    }
    
    var body: some View {
        VStack(spacing: 20) {
            // Header section with ButtonGroup
            HStack {
                Text("Files")
                    .font(.title2)
                    .fontWeight(.semibold)
                
                Spacer()
                
                if !processor.files.isEmpty {
                    ButtonGroup(buttons: [
                        (
                            title: "Save All",
                            icon: "folder.fill.badge.plus",
                            action: {
                                Task {
                                    await processor.saveAllFilesToFolder()
                                }
                            }
                        ),
                        (
                            title: "Clear All",
                            icon: "trash.fill",
                            action: {
                                processor.clearFiles()
                            }
                        )
                    ])
                }
            }
            .padding(.horizontal)
            
            // File list
            VStack(spacing: 0) { // Wrapper for consistent padding
                ScrollView {
                    LazyVStack(spacing: 8) {
                        ForEach(Array(processor.files.enumerated()), id: \.element.id) { index, file in
                            FileRow(
                                file: file,
                                isHovered: hoveredFileID == file.id,
                                onSave: {
                                    if let result = file.result {
                                        Task {
                                            await processor.saveCompressedFile(
                                                url: result.compressedURL,
                                                originalName: file.originalFileName
                                            )
                                        }
                                    }
                                },
                                onRemove: {
                                    processor.removeFile(at: index)
                                }
                            )
                            .onHover { isHovered in
                                hoveredFileID = isHovered ? file.id : nil
                            }
                        }
                    }
                    .padding(.horizontal)
                    .padding(.vertical) // Add vertical padding inside scroll view
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color(NSColor.controlBackgroundColor).opacity(0.5))
            .clipShape(RoundedRectangle(cornerRadius: 12))
        }
        .padding()
    }
}

struct FileRow: View {
    let file: FileProcessingState
    let isHovered: Bool
    let onSave: () -> Void
    let onRemove: () -> Void
    
    var body: some View {
        HStack(spacing: 16) {
            // File icon with extension badge
            ZStack(alignment: .bottomTrailing) {
                getFileIcon(for: file.url.pathExtension.lowercased())
                    .font(.system(size: 28))
                
                Text(file.url.pathExtension.uppercased())
                    .font(.system(size: 8, weight: .bold))
                    .padding(.horizontal, 4)
                    .padding(.vertical, 2)
                    .background(.ultraThinMaterial)
                    .clipShape(RoundedRectangle(cornerRadius: 4))
            }
            
            // File info
            VStack(alignment: .leading, spacing: 4) {
                Text(file.displayFileName)
                    .font(.headline)
                    .lineLimit(1)
                
                Group {
                    if let result = file.result {
                        Label(
                            "Reduced by \(result.savedPercentage)%",
                            systemImage: "arrow.down.circle.fill"
                        )
                        .foregroundStyle(.green)
                    } else if let error = file.error {
                        Label(
                            error.localizedDescription,
                            systemImage: "exclamationmark.circle.fill"
                        )
                        .foregroundStyle(.red)
                    } else if file.isProcessing {
                        Label(
                            "Processing...",
                            systemImage: "arrow.triangle.2.circlepath"
                        )
                        .foregroundStyle(.blue)
                    }
                }
                .font(.subheadline)
            }
            
            Spacer()
            
            // Actions
            HStack(spacing: 12) {
                if file.isProcessing {
                    ProgressView()
                        .controlSize(.small)
                } else if let _ = file.result {
                    Button(action: onSave) {
                        Label("Download", systemImage: "square.and.arrow.down.fill")
                    }
                    .buttonStyle(GlassButtonStyle())
                }
                
                Button(action: onRemove) {
                    Image(systemName: "trash.fill")
                        .foregroundStyle(.red.opacity(0.8))
                }
                .buttonStyle(PlainButtonStyle())
            }
            .opacity(isHovered ? 1 : 0.7)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(isHovered ? Color(NSColor.controlBackgroundColor).opacity(0.7) : Color.clear)
                .overlay(
                    RoundedRectangle(cornerRadius: 12)
                        .stroke(Color.primary.opacity(0.1), lineWidth: 1)
                )
        )
        .contentShape(Rectangle())
    }
    
    @ViewBuilder
    private func getFileIcon(for extension: String) -> some View {
        switch `extension` {
        case "jpg", "jpeg", "png", "heic", "webp":
            Image(systemName: "photo.fill")
                .foregroundStyle(.blue)
        case "mp4", "mov", "avi":
            Image(systemName: "video.fill")
                .foregroundStyle(.purple)
        case "mp3", "wav", "aiff":
            Image(systemName: "music.note")
                .foregroundStyle(.pink)
        case "pdf":
            Image(systemName: "doc.fill")
                .foregroundStyle(.red)
        default:
            Image(systemName: "doc.fill")
                .foregroundStyle(.secondary)
        }
    }
}


================================================
FILE: Achico/Views/ResultView.swift
================================================
import SwiftUI

struct ResultView: View {
    let result: FileProcessor.ProcessingResult
    let onDownload: () -> Void
    let onReset: () -> Void
    
    var body: some View {
        VStack(spacing: 24) {
            // Status Icon
            ZStack {
                Circle()
                    .fill(Color(NSColor.windowBackgroundColor))
                    .frame(width: 64, height: 64)
                    .shadow(color: Color.black.opacity(0.1), radius: 10, x: 0, y: 5)
                
                Image(systemName: result.savedPercentage > 0 ? "checkmark" : "exclamationmark")
                    .font(.system(size: 24, weight: .medium))
                    .foregroundColor(result.savedPercentage > 0 ? .green : .orange)
            }
            
            // Status Text
            VStack(spacing: 8) {
                Text(result.savedPercentage > 0 ? "Compression Complete" : "Already Optimized")
                    .font(.system(size: 16, weight: .semibold))
                
                if result.savedPercentage > 0 {
                    Text("File size reduced by \(result.savedPercentage)%")
                        .font(.system(size: 14))
                        .foregroundColor(.secondary)
                } else {
                    Text("No further compression needed")
                        .font(.system(size: 14))
                        .foregroundColor(.secondary)
                }
            }
            
            // File Size Info
            HStack(spacing: 32) {
                VStack(spacing: 4) {
                    Text("Original")
                        .font(.system(size: 12))
                        .foregroundColor(.secondary)
                    Text(formatFileSize(result.originalSize))
                        .font(.system(size: 14, weight: .medium))
                }
                
                VStack(spacing: 4) {
                    Text("Compressed")
                        .font(.system(size: 12))
                        .foregroundColor(.secondary)
                    Text(formatFileSize(result.compressedSize))
                        .font(.system(size: 14, weight: .medium))
                }
            }
            .padding(.vertical, 16)
            .padding(.horizontal, 24)
            .background(
                RoundedRectangle(cornerRadius: 12)
                    .fill(Color(NSColor.controlBackgroundColor))
                    .opacity(0.5)
            )
            
            // Action Buttons
            HStack(spacing: 12) {
                Button(action: onReset) {
                    Text("New File")
                        .font(.system(size: 14, weight: .medium))
                        .frame(maxWidth: .infinity)
                        .frame(height: 36)
                }
                .buttonStyle(SecondaryButtonStyle())
                
                Button(action: onDownload) {
                    Text("Save")
                        .font(.system(size: 14, weight: .medium))
                        .frame(maxWidth: .infinity)
                        .frame(height: 36)
                }
                .buttonStyle(PrimaryButtonStyle())
            }
            .padding(.top, 8)
        }
        .padding(32)
        .frame(maxWidth: 320)
        .background(
            RoundedRectangle(cornerRadius: 16)
                .fill(Color(NSColor.windowBackgroundColor))
                .opacity(0.8)
                .shadow(color: Color.black.opacity(0.1), radius: 20, x: 0, y: 10)
        )
    }
    
    private func formatFileSize(_ size: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = [.useMB]
        formatter.countStyle = .file
        return formatter.string(fromByteCount: size)
    }
}

// Add new custom button styles
struct PrimaryButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(.white)
            .background(Color.accentColor)
            .cornerRadius(8)
            .opacity(configuration.isPressed ? 0.9 : 1.0)
    }
}

struct SecondaryButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(.primary)
            .background(Color(NSColor.controlBackgroundColor).opacity(0.5))
            .cornerRadius(8)
            .overlay(
                RoundedRectangle(cornerRadius: 8)
                    .strokeBorder(Color.primary.opacity(0.1), lineWidth: 1)
            )
            .opacity(configuration.isPressed ? 0.9 : 1.0)
    }
}


================================================
FILE: Achico.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 77;
	objects = {

/* Begin PBXFileReference section */
		C82F044E2CCB3DD20012C07B /* Achico.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Achico.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
		C8A16E302CE0FC6D00F427B2 /* Exceptions for "Achico" folder in "Achico" target */ = {
			isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
			membershipExceptions = (
				Info.plist,
			);
			target = C82F044D2CCB3DD20012C07B /* Achico */;
		};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
		C82F04502CCB3DD20012C07B /* Achico */ = {
			isa = PBXFileSystemSynchronizedRootGroup;
			exceptions = (
				C8A16E302CE0FC6D00F427B2 /* Exceptions for "Achico" folder in "Achico" target */,
			);
			path = Achico;
			sourceTree = "<group>";
		};
/* End PBXFileSystemSynchronizedRootGroup section */

/* Begin PBXFrameworksBuildPhase section */
		C82F044B2CCB3DD20012C07B /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		C82F04452CCB3DD20012C07B = {
			isa = PBXGroup;
			children = (
				C82F04502CCB3DD20012C07B /* Achico */,
				C82F044F2CCB3DD20012C07B /* Products */,
			);
			sourceTree = "<group>";
		};
		C82F044F2CCB3DD20012C07B /* Products */ = {
			isa = PBXGroup;
			children = (
				C82F044E2CCB3DD20012C07B /* Achico.app */,
			);
			name = Products;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		C82F044D2CCB3DD20012C07B /* Achico */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = C82F045D2CCB3DD40012C07B /* Build configuration list for PBXNativeTarget "Achico" */;
			buildPhases = (
				C82F044A2CCB3DD20012C07B /* Sources */,
				C82F044B2CCB3DD20012C07B /* Frameworks */,
				C82F044C2CCB3DD20012C07B /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			fileSystemSynchronizedGroups = (
				C82F04502CCB3DD20012C07B /* Achico */,
			);
			name = Achico;
			packageProductDependencies = (
			);
			productName = Achico;
			productReference = C82F044E2CCB3DD20012C07B /* Achico.app */;
			productType = "com.apple.product-type.application";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		C82F04462CCB3DD20012C07B /* Project object */ = {
			isa = PBXProject;
			attributes = {
				BuildIndependentTargetsInParallel = 1;
				LastSwiftUpdateCheck = 1600;
				LastUpgradeCheck = 1610;
				TargetAttributes = {
					C82F044D2CCB3DD20012C07B = {
						CreatedOnToolsVersion = 16.0;
					};
				};
			};
			buildConfigurationList = C82F04492CCB3DD20012C07B /* Build configuration list for PBXProject "Achico" */;
			developmentRegion = en;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = C82F04452CCB3DD20012C07B;
			minimizedProjectReferenceProxies = 1;
			preferredProjectObjectVersion = 77;
			productRefGroup = C82F044F2CCB3DD20012C07B /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				C82F044D2CCB3DD20012C07B /* Achico */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		C82F044C2CCB3DD20012C07B /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		C82F044A2CCB3DD20012C07B /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin XCBuildConfiguration section */
		C82F045B2CCB3DD40012C07B /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				DEAD_CODE_STRIPPING = YES;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				ENABLE_USER_SCRIPT_SANDBOXING = YES;
				GCC_C_LANGUAGE_STANDARD = gnu17;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
				MACOSX_DEPLOYMENT_TARGET = 15.0;
				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
				MTL_FAST_MATH = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = macosx;
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
			};
			name = Debug;
		};
		C82F045C2CCB3DD40012C07B /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				DEAD_CODE_STRIPPING = YES;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_USER_SCRIPT_SANDBOXING = YES;
				GCC_C_LANGUAGE_STANDARD = gnu17;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
				MACOSX_DEPLOYMENT_TARGET = 15.0;
				MTL_ENABLE_DEBUG_INFO = NO;
				MTL_FAST_MATH = YES;
				SDKROOT = macosx;
				SWIFT_COMPILATION_MODE = wholemodule;
			};
			name = Release;
		};
		C82F045E2CCB3DD40012C07B /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
				ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
				CODE_SIGN_ENTITLEMENTS = Achico/Achico.entitlements;
				"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
				CODE_SIGN_STYLE = Automatic;
				COMBINE_HIDPI_IMAGES = YES;
				CURRENT_PROJECT_VERSION = 26;
				DEAD_CODE_STRIPPING = YES;
				DEVELOPMENT_ASSET_PATHS = "\"Achico/Preview Content\"";
				DEVELOPMENT_TEAM = YYMLDY74QZ;
				ENABLE_HARDENED_RUNTIME = YES;
				ENABLE_PREVIEWS = YES;
				GENERATE_INFOPLIST_FILE = YES;
				INFOPLIST_FILE = Achico/Info.plist;
				INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
				INFOPLIST_KEY_NSHumanReadableCopyright = "";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/../Frameworks",
				);
				MACOSX_DEPLOYMENT_TARGET = 14.0;
				MARKETING_VERSION = 3.2.1;
				PRODUCT_BUNDLE_IDENTIFIER = Minimal.Achico;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = YES;
				SWIFT_VERSION = 5.0;
			};
			name = Debug;
		};
		C82F045F2CCB3DD40012C07B /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
				ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
				CODE_SIGN_ENTITLEMENTS = Achico/Achico.entitlements;
				"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
				CODE_SIGN_STYLE = Automatic;
				COMBINE_HIDPI_IMAGES = YES;
				CURRENT_PROJECT_VERSION = 26;
				DEAD_CODE_STRIPPING = YES;
				DEVELOPMENT_ASSET_PATHS = "\"Achico/Preview Content\"";
				DEVELOPMENT_TEAM = YYMLDY74QZ;
				ENABLE_HARDENED_RUNTIME = YES;
				ENABLE_PREVIEWS = YES;
				GENERATE_INFOPLIST_FILE = YES;
				INFOPLIST_FILE = Achico/Info.plist;
				INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
				INFOPLIST_KEY_NSHumanReadableCopyright = "";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/../Frameworks",
				);
				MACOSX_DEPLOYMENT_TARGET = 14.0;
				MARKETING_VERSION = 3.2.1;
				PRODUCT_BUNDLE_IDENTIFIER = Minimal.Achico;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_EMIT_LOC_STRINGS = YES;
				SWIFT_VERSION = 5.0;
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		C82F04492CCB3DD20012C07B /* Build configuration list for PBXProject "Achico" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				C82F045B2CCB3DD40012C07B /* Debug */,
				C82F045C2CCB3DD40012C07B /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		C82F045D2CCB3DD40012C07B /* Build configuration list for PBXNativeTarget "Achico" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				C82F045E2CCB3DD40012C07B /* Debug */,
				C82F045F2CCB3DD40012C07B /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = C82F04462CCB3DD20012C07B /* Project object */;
}


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 nuance-dev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Achico - A Free MacOS Native File Compression App

A lightweight, native macOS app that intelligently compresses files while maintaining quality. Support for PDF, images, videos, and more! Simple, fast, and efficient!

![image](https://github.com/user-attachments/assets/4e10b8a7-decc-4e0b-8b56-f88198e75ec9)

## Features

### File Support

- **PDFs**: Smart compression while preserving readability
- **Images**: Support for JPEG, PNG, HEIC, TIFF, GIF, BMP, WebP, SVG, RAW, and ICO
- **Videos**: MP4, MOV, AVI, and other common formats
- **Audio**: M4V, WAV, MP3, AIFF
- **File Resizing**: Optionally resize images and videos while compressing

### Core Features

- **Multiple Input Methods**: Drag & drop or click to select files
- **Real-time Progress**: Watch your files being compressed with a clean progress indicator
- **Compression Stats**: See how much space you've saved instantly
- **Dark and Light modes**: Seamlessly integrates with your system preferences
- **Native Performance**: Built with SwiftUI for optimal macOS integration

### Compression Options

- **Quality Control**: Adjust compression levels to balance size and quality
- **Size Limits**: Set maximum dimensions for images and videos
- **Format Conversion**: Automatic conversion of less efficient formats
- **Metadata Handling**: Option to preserve or strip metadata

![compression-demo](https://github.com/user-attachments/assets/e494937d-7e52-4d6c-9046-d6b0d577c67e)

## 💻 Get Started

Download from the [releases](https://github.com/nuance-dev/Achico/releases/) page.

## ⚡️ How it Works

1. Drop or select your files
2. Adjust compression settings (optional)
3. Watch the magic happen
4. Get your compressed files
5. That's it!
6. Update: you can now resize your images and videos
7. Update: you can now drop multiple files
   ![42630](https://github.com/user-attachments/assets/6def2137-fd12-4f7d-b59a-4476ae506331)

## 🛠 Technical Details

- Built natively for macOS using SwiftUI
- Uses specialized frameworks for each file type:
  - PDFKit for PDF compression
  - AVFoundation for video processing
  - Core Graphics for image optimization
- Efficient memory management for handling large files
- Clean, modern interface following Apple's design guidelines
- Parallel processing for better performance

## 🔮 Features Coming Soon

- Batch processing
- Folder monitoring
- Quick Look integration
- Custom presets for different use cases
- Additional file format support
- Advanced compression options
- Progress notifications

## 🤝 Contributing

We welcome contributions! Here's how you can help:

1. Clone the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

Please ensure your PR:

- Follows the existing code style
- Includes appropriate tests if applicable
- Updates documentation as needed

## 📝 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🔗 Links

- Website: [Nuance](https://nuanc.me)
- Report issues: [GitHub Issues](https://github.com/nuance-dev/Achico/issues)
- Follow updates: [@NuanceDev](https://twitter.com/Nuancedev)

## Requirements

- macOS 14.0 or later

## Supported File Formats

### Images

- JPEG/JPG
- PNG
- HEIC
- TIFF/TIF
- GIF (including animated)
- BMP
- WebP
- SVG
- RAW (CR2, NEF, ARW)
- ICO

### Videos

- MP4
- MOV
- AVI
- MPEG/MPG

### Documents

- PDF
Download .txt
gitextract_q763oxjx/

├── Achico/
│   ├── Achico.entitlements
│   ├── App/
│   │   ├── AchicoApp.swift
│   │   └── AppDelegate.swift
│   ├── Info.plist
│   ├── Preview Content/
│   │   └── Preview Assets.xcassets/
│   │       ├── AppIcon-1024.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-128.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-16.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-256.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-32.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-512.imageset/
│   │       │   └── Contents.json
│   │       ├── AppIcon-64.imageset/
│   │       │   └── Contents.json
│   │       └── Contents.json
│   ├── Processor/
│   │   ├── CacheManager.swift
│   │   ├── FileProcessor.swift
│   │   └── VideoProcessor.swift
│   ├── Resources/
│   │   ├── Assets.xcassets/
│   │   │   ├── AccentColor.colorset/
│   │   │   │   └── Contents.json
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── Contents.json
│   │   ├── CompressionSettings.swift
│   │   ├── FileDropDelegate.swift
│   │   ├── MenuBarController.swift
│   │   └── UpdateChecker.swift
│   ├── UI Components/
│   │   ├── ButtonGroup.swift
│   │   ├── GlassButtonStyle.swift
│   │   ├── TitleBarAccessory.swift
│   │   ├── VisualEffectBlur.swift
│   │   └── WindowAccessor.swift
│   └── Views/
│       ├── ContentView.swift
│       ├── DropZoneView.swift
│       ├── MenuBarView.swift
│       ├── MultiFileProcessingView.swift
│       └── ResultView.swift
├── Achico.xcodeproj/
│   └── project.pbxproj
├── LICENSE
└── README.md
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (131K chars).
[
  {
    "path": "Achico/Achico.entitlements",
    "chars": 436,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "Achico/App/AchicoApp.swift",
    "chars": 1963,
    "preview": "import SwiftUI\nimport AppKit\n\n@main\nstruct AchicoApp: App {\n    @NSApplicationDelegateAdaptor(AppDelegate.self) var appD"
  },
  {
    "path": "Achico/App/AppDelegate.swift",
    "chars": 187,
    "preview": "import Cocoa\n\nclass AppDelegate: NSObject, NSApplicationDelegate {\n    func applicationWillTerminate(_ notification: Not"
  },
  {
    "path": "Achico/Info.plist",
    "chars": 181,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-1024.imageset/Contents.json",
    "chars": 310,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-1024.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-128.imageset/Contents.json",
    "chars": 309,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-128.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n  "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-16.imageset/Contents.json",
    "chars": 308,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-16.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n   "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-256.imageset/Contents.json",
    "chars": 309,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-256.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n  "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-32.imageset/Contents.json",
    "chars": 308,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-32.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n   "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-512.imageset/Contents.json",
    "chars": 309,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-512.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n  "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/AppIcon-64.imageset/Contents.json",
    "chars": 308,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-64.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n   "
  },
  {
    "path": "Achico/Preview Content/Preview Assets.xcassets/Contents.json",
    "chars": 63,
    "preview": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Achico/Processor/CacheManager.swift",
    "chars": 2791,
    "preview": "// CacheManager.swift\nimport Foundation\nimport AppKit\n\nclass CacheManager {\n    static let shared = CacheManager()\n    \n"
  },
  {
    "path": "Achico/Processor/FileProcessor.swift",
    "chars": 32027,
    "preview": "import Foundation\nimport PDFKit\nimport UniformTypeIdentifiers\nimport AppKit\nimport CoreGraphics\nimport AVFoundation\n\nenu"
  },
  {
    "path": "Achico/Processor/VideoProcessor.swift",
    "chars": 6083,
    "preview": "import Foundation\nimport AVFoundation\n\n@available(macOS 12.0, *)\nactor VideoProcessor {\n    enum VideoError: LocalizedEr"
  },
  {
    "path": "Achico/Resources/Assets.xcassets/AccentColor.colorset/Contents.json",
    "chars": 335,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"display-p3\",\n        \"components\" : {\n          \"alpha"
  },
  {
    "path": "Achico/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1287,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon-16.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : "
  },
  {
    "path": "Achico/Resources/Assets.xcassets/Contents.json",
    "chars": 63,
    "preview": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Achico/Resources/CompressionSettings.swift",
    "chars": 930,
    "preview": "import Foundation\nimport CoreGraphics\n\npublic struct CompressionSettings {\n    var quality: CGFloat = 0.7        // JPEG"
  },
  {
    "path": "Achico/Resources/FileDropDelegate.swift",
    "chars": 706,
    "preview": "import SwiftUI\nimport UniformTypeIdentifiers\nstruct FileDropDelegate: DropDelegate {\n    @Binding var isDragging: Bool\n "
  },
  {
    "path": "Achico/Resources/MenuBarController.swift",
    "chars": 3561,
    "preview": "import SwiftUI\nimport AppKit\n\nclass MenuBarController: NSObject, ObservableObject {\n    @Published private(set) var upda"
  },
  {
    "path": "Achico/Resources/UpdateChecker.swift",
    "chars": 6245,
    "preview": "import Foundation\n\nstruct GitHubRelease: Codable {\n    let tagName: String\n    let name: String\n    let body: String\n   "
  },
  {
    "path": "Achico/UI Components/ButtonGroup.swift",
    "chars": 2031,
    "preview": "import SwiftUI\n\nstruct ToolbarButton: View {\n    let title: String\n    let icon: String\n    let action: () -> Void\n    l"
  },
  {
    "path": "Achico/UI Components/GlassButtonStyle.swift",
    "chars": 617,
    "preview": "import SwiftUI\n\nstruct GlassButtonStyle: ButtonStyle {\n    func makeBody(configuration: Configuration) -> some View {\n  "
  },
  {
    "path": "Achico/UI Components/TitleBarAccessory.swift",
    "chars": 424,
    "preview": "import SwiftUI\n\nstruct TitleBarAccessory: View {\n    @AppStorage(\"isDarkMode\") private var isDarkMode = false\n    \n    v"
  },
  {
    "path": "Achico/UI Components/VisualEffectBlur.swift",
    "chars": 509,
    "preview": "import SwiftUI\n\nstruct VisualEffectBlur: NSViewRepresentable {\n    var material: NSVisualEffectView.Material\n    var ble"
  },
  {
    "path": "Achico/UI Components/WindowAccessor.swift",
    "chars": 804,
    "preview": "import SwiftUI\n\nstruct WindowAccessor: NSViewRepresentable {\n    func makeNSView(context: Context) -> NSView {\n        l"
  },
  {
    "path": "Achico/Views/ContentView.swift",
    "chars": 16532,
    "preview": "import SwiftUI\nimport UniformTypeIdentifiers\nimport AppKit\n\nstruct ContentView: View {\n    @StateObject private var proc"
  },
  {
    "path": "Achico/Views/DropZoneView.swift",
    "chars": 2517,
    "preview": "import SwiftUI\n\nstruct DropZoneView: View {\n    @Binding var isDragging: Bool\n    @Binding var shouldResize: Bool\n    @B"
  },
  {
    "path": "Achico/Views/MenuBarView.swift",
    "chars": 4796,
    "preview": "import SwiftUI\nimport AppKit\n\nstruct MenuBarView: View {\n    @ObservedObject var updater: UpdateChecker\n    @Environment"
  },
  {
    "path": "Achico/Views/MultiFileProcessingView.swift",
    "chars": 13729,
    "preview": "import Foundation\nimport UniformTypeIdentifiers\nimport SwiftUI\n\nstruct FileProcessingState: Identifiable {\n    let id: U"
  },
  {
    "path": "Achico/Views/ResultView.swift",
    "chars": 4636,
    "preview": "import SwiftUI\n\nstruct ResultView: View {\n    let result: FileProcessor.ProcessingResult\n    let onDownload: () -> Void\n"
  },
  {
    "path": "Achico.xcodeproj/project.pbxproj",
    "chars": 11855,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 77;\n\tobjects = {\n\n/* Begin PBXFileReference secti"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2024 nuance-dev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 3525,
    "preview": "# Achico - A Free MacOS Native File Compression App\n\nA lightweight, native macOS app that intelligently compresses files"
  }
]

About this extraction

This page contains the full source code of the nuance-dev/achico GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (119.2 KB), approximately 27.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!