# RULESET: macOS App Development with SwiftUI (Based on 'macOS by Tutorials') Bu dosya, "macOS by Tutorials" (Ray Wenderlich / Kodeco) kitabındaki best practice'lere dayanarak yüksek kaliteli, native hissettiren bir macOS uygulaması geliştirmek için gerekli kuralları, mimari desenleri ve kod standartlarını içerir. **GÖREV:** Bir macOS uygulaması geliştirirken aşağıdaki kurallara kesinlikle uy. iOS alışkanlıklarını (NavigationLink vb.) macOS'e aynen kopyalama. Mac kullanıcılarının beklentilerine (Menü çubuğu, Çoklu Pencere, Klavye Kısayolları) öncelik ver. --- ## 1. TEMEL FELSEFE VE MİMARİ (Core Philosophy) ### iOS Portu Değil, Mac Uygulaması * **Kural:** Uygulamayı sadece "büyük ekranlı bir iPad uygulaması" gibi tasarlama. Mac kullanıcıları fare/trackpad kullanır, pencereleri boyutlandırır ve klavye kısayollarına bağımlıdır. * **Kural:** `SFSafariViewController` macOS'te yoktur ve kullanılmamalıdır. Kullanıcıyı tarayıcıya (`Link` veya `NSWorkspace.open`) yönlendirmek Mac kültürüne daha uygundur. ### Uygulama Yaşam Döngüsü (App Lifecycle) * **Yapı:** `@main` struct'ı `App` protokolüne uymalıdır. * **WindowGroup:** Ana arayüzü `WindowGroup` içine al. Bu, macOS'in otomatik olarak çoklu pencere (multi-window) ve sekme (tab) desteği sunmasını sağlar. ```swift @main struct MyApp: App { @StateObject var appState = AppState() // Global state var body: some Scene { WindowGroup { ContentView() .environmentObject(appState) } .commands { // Menü komutları buraya SidebarCommands() ToolbarCommands() } } } ``` --- ## 2. PENCERE YÖNETİMİ (Window Management) ### Pencere Boyutlandırma (Sizing) * **Kural:** iOS'in aksine, Mac'te pencereler serbestçe boyutlandırılabilir. Ancak mantıklı sınırlar koymalısın. * **Kod:** `ContentView`'un en dış katmanına `.frame()` modifier ekle. * `minWidth` / `minHeight`: UI'ın bozulmayacağı en küçük boyut. * `maxWidth` / `maxHeight`: Genellikle `.infinity` olmalı. * `idealWidth` / `idealHeight`: Uygulama ilk açıldığında önerilen boyut. ```swift .frame(minWidth: 700, idealWidth: 1000, maxWidth: .infinity, minHeight: 400, idealHeight: 800, maxHeight: .infinity) ``` ### Pencere Başlıkları (Titles) * **Kural:** Çoklu pencerelerde her pencerenin içeriğine göre dinamik başlığı olmalıdır. * **Kod:** `.navigationTitle(_:)` kullan. Eğer sidebar'da bir seçim varsa başlık ona göre değişmeli, yoksa varsayılan uygulama adı görünmelidir. --- ## 3. NAVİGASYON VE SIDEBAR (Navigation) ### NavigationView Yapısı * **Kural (KRİTİK):** `NavigationLink` kullanma. macOS'te "push" navigasyonu (bir ekranın diğerinin üzerine kayması) nadirdir. * **Desen:** Sidebar + Detail (Split View) yapısını kullan. * **Uygulama:** `NavigationView` içine tüm panelleri (Sidebar, Detail) en baştan koy. Görünürlük, bir `@Binding` selection değişkeni ile yönetilir. ```swift NavigationView { SidebarView(selection: $selection) // Sol Panel DetailView(selection: selection) // Sağ Panel } ``` ### Sidebar Tasarımı * **List Style:** `.listStyle(.sidebar)` kullan. Bu, satırların hafif transparan olmasını ve seçimin sistem rengiyle (AccentColor) vurgulanmasını sağlar. * **Selection:** `List(selection: $selection)` bağlamasını kullan. `Tag` yapısını `NavigationLink` yerine tercih et. * **Kategoriler:** Listeyi `Section`'lara böl. Başlıkları büyük harfle yazma (iOS gibi değil), Mac standartlarına uy. --- ## 4. UI BİLEŞENLERİ (UI Components) ### Grid (Izgara) Görünümü * **Kullanım:** Çok sayıda öğe gösterirken `LazyVGrid` kullan. * **Sütunlar:** Sabit sütun sayısı yerine `.adaptive(minimum:maximum:)` kullanarak pencere genişletildiğinde sütun sayısının artmasını sağla. ```swift let columns = [GridItem(.adaptive(minimum: 250, maximum: 250), spacing: 20)] ``` ### Table (Tablo) Görünümü (macOS Exclusive) * **Kural:** Veri yoğunluklu listeler için `List` yerine SwiftUI `Table` görünümünü kullan. * **Özellikler:** Sıralama (`sortOrder`), Çoklu seçim (`selection: Set`), ve Sütun genişlikleri (`width(min:ideal:max)`) mutlaka eklenmeli. * **Alternatif Satır Renkleri:** `Table`, varsayılan olarak satırları alternatif renklerle (zebra stripe) boyar. Bunu koru. ### Kart Tasarımı ve Hover Efektleri * **Kural:** Mac kullanıcıları "tıklanabilir" alanları anlamak için fare imlecini kullanır. * **İpucu:** Tıklanabilir alanlarda imleci değiştirmek için `.onHover` ve `NSCursor` kullan. ```swift .onHover { inside in inside ? NSCursor.pointingHand.push() : NSCursor.pop() } ``` * **Bug Fix:** Kartlara gölge (`shadow`) eklerken `.clipped()` kullanmayı unutma, aksi takdirde gölge iç elementlere de uygulanabilir (SwiftUI bug workaround). --- ## 5. MENÜLER (Menus) ### Command Protocol * **Yapı:** Menüleri `View` dosyalarından ayır ve `Commands` protokolüne uyan ayrı bir dosyada (örn. `Menus.swift`) tut. * **Hazır Gruplar:** Apple'ın hazır menü gruplarını mutlaka ekle: * `SidebarCommands()`: View menüsüne "Toggle Sidebar" ekler. * `ToolbarCommands()`: View menüsüne Toolbar özelleştirme seçeneklerini ekler. ### Özel Menü Öğeleri * **Yerleşim:** `CommandGroup(before: .help)` veya `CommandGroup(after: .newItem)` gibi yerleşimler kullan. * **Klavye Kısayolları:** `.keyboardShortcut(_:modifiers:)` ile her önemli aksiyona kısayol ata. * *Not:* Menülerde kısayollar otomatik olarak büyük harf görünür, ekstra Shift eklemene gerek yoktur. * **Picker Entegrasyonu:** Ayarlar için (örn. Tema seçimi) menü içine `Picker` koy. Otomatik olarak alt menü (submenu) ve tik işareti (checkmark) oluşturur. --- ## 6. ARAÇ ÇUBUĞU (Toolbar) ### Yapı ve Özelleştirme * **Kural:** `ToolbarItem` veya `ToolbarItemGroup` kullan. * **Customizable:** Kullanıcının sağ tıkla toolbar'ı düzenleyebilmesi için toolbar'a ve öğelere `.id()` ver. ```swift .toolbar(id: "mainToolbar") { ToolbarItem(id: "refresh", placement: .primaryAction) { ... } } ``` * **Placement:** * `.navigation`: Sol taraf (Sidebar toggle vb.) * `.primaryAction`: Sağ taraf (En önemli buton) * `.automatic`: Sistem karar verir. ### Arama (Search) * **Kullanım:** `.searchable(text: $searchText)` modifier'ını `NavigationView`'a ekle. Bu, toolbar'a otomatik olarak native bir arama çubuğu yerleştirir. --- ## 7. VERİ VE STATE YÖNETİMİ (Data Persistence) ### Sandboxing & Network * **Kritik:** macOS uygulamaları varsayılan olarak internete çıkamaz. "Signing & Capabilities" altından **Outgoing Connections (Client)** tikini açmalısın. ### Ayarların Saklanması (Persistence) * **Global Ayarlar:** Uygulama geneli ayarlar (örn. Tema, "Show Totals") için `@AppStorage` kullan (UserDefaults wrapper). * **Pencere Bazlı Ayarlar:** Her pencerenin kendi durumunu hatırlaması için (örn. Seçili sekme, Arama metni) `@SceneStorage` kullan. ```swift @SceneStorage("viewMode") var viewMode: ViewMode = .grid ``` --- ## 8. SWIFTUI & APPKIT ENTEGRASYONU ### Ne Zaman AppKit Kullanılmalı? * SwiftUI'ın yetersiz kaldığı durumlarda (örn. Sidebar'ı kod ile açıp kapatmak, Window odağını değiştirmek, First Responder yönetimi) `NSApp`, `NSWindow` veya `NSCursor`'a erişmekten çekinme. * **Örnek (Sidebar Toggle):** ```swift func toggleSidebar() { NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil) } ``` --- ## 9. CHECKLIST FOR AGENTS Bir özellik eklerken şu soruları sor: 1. **Pencere:** Bu özellik yeni bir pencerede açıldığında nasıl davranacak? (`@SceneStorage` kullanıldı mı?) 2. **Menü:** Bu aksiyonun Menü çubuğunda bir karşılığı ve klavye kısayolu var mı? 3. **Mouse:** Hover efektleri var mı? Tıklanabilir alanlar belli mi? 4. **Platform:** Bu bir iOS davranışı mı (örn. Bottom Sheet, Navigation Push)? Eğer öyleyse macOS karşılığını (Sheet, Split View değişimi) kullan. 5. **Boyut:** Pencere küçüldüğünde veya büyüdüğünde (`GridItem.adaptive`, `Table` sütunları) arayüz uyum sağlıyor mu?