173 lines
8.3 KiB
Markdown
173 lines
8.3 KiB
Markdown
# 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<ID>`), 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? |