first commit

This commit is contained in:
2026-01-11 16:21:23 +03:00
commit a92b0d2081
3 changed files with 385 additions and 0 deletions

209
tvOS_Development_Rules.md Normal file
View File

@@ -0,0 +1,209 @@
# MASTER RULESET: Professional tvOS Development with SwiftUI
**VERSION:** 2.0 (Comprehensive)
**TARGET:** AI Coding Agents (Claude 3.5 Sonnet, GPT-4o, etc.)
**CONTEXT:** Building a high-end, native Apple TV application.
Bu belge, tvOS ekosistemi için "State of the Art" uygulama geliştirme kurallarını içerir. Aşağıdaki yönergeler, dokunmatik ekran mantığından (Touch Paradigm) tamamen çıkıp, uzaktan kumanda odaklı (Focus Paradigm) bir yapı kurmayı zorunlu kılar.
---
## 1. TEMEL FELSEFE: "10-FOOT EXPERIENCE"
tvOS uygulamaları, kullanıcı ekrandan 3-4 metre uzaktayken (10-foot UI) kullanılır. Bu fiziksel mesafe, tasarım ve kod mimarisini kökten değiştirir.
### 1.1. Görsel Hiyerarşi ve Okunabilirlik
* **KURAL:** Asla iOS yazı boyutlarını kullanma. Kullanıcı uzaktadır.
* **Typography:** Apple'ın dinamik type stillerini (`.font(.headline)`, `.font(.caption)`) kullan, ancak bunları manuel olarak scale etmen gerekirse şu minimumları baz al:
* **Title:** 57pt+
* **Headline:** 38pt+
* **Body:** 29pt+ (Asla 29pt altına düşme).
* **Caption:** Sadece ikincil bilgiler için, min 25pt.
* **Renk ve Kontrast:** TV ekranlarının renk gamutları farklıdır. Yüksek kontrastlı renkler kullan. Koyu mod (Dark Mode) tvOS'te varsayılan ve en çok tercih edilen moddur; tasarımını buna göre optimize et.
### 1.2. Safe Area ve Overscan
* **KURAL:** TV üreticileri ekranın kenarlarını kırpabilir (Overscan). Kritik UI öğelerini asla ekranın tam kenarına yapıştırma.
* **Standart Padding:** Ana içerik için kenarlardan **90px**, dikeyde ise **60px** güvenli alan bırak. SwiftUI'ın standart `safeAreaPadding` modifier'ı genellikle bunu doğru yönetir.
---
## 2. FOCUS ENGINE MİMARİSİ (CORE MECHANIC)
Uygulamanın kalbi **Focus Engine**'dir. Eğer Focus Engine doğru çalışmazsa, uygulama kullanılamaz.
### 2.1. Odaklanma Mantığı (The Golden Rule)
* **KURAL:** Ekranda her an **mutlaka** bir nesne odaklanmış olmalıdır. Odaksız bir ekran, bozuk bir ekrandır.
* **Varsayılan Odak:** Bir ekran açıldığında, sistem en sol-üstteki öğeye odaklanır. Bunu değiştirmek için `preferredDefaultFocus` veya SwiftUI'da `@FocusState` kullan.
### 2.2. Focus State Yönetimi (SwiftUI Pattern)
Code Agent olarak, odağı programatik olarak yönetmen gereken durumlar olacaktır (örn. Yan menü açıldığında odağı oraya taşımak).
```swift
struct HomeView: View {
// Focus state tanımları (Enum kullanımı best practice'tir)
enum FocusableField: Hashable {
case sidebar
case contentGrid
case search
}
@FocusState private var focusedField: FocusableField?
var body: some View {
HStack {
SidebarView()
.focused($focusedField, equals: .sidebar)
ContentGridView()
.focused($focusedField, equals: .contentGrid)
}
.onAppear {
// Ekran açıldığında odağı zorla içeriğe ver
focusedField = .contentGrid
}
}
}
2.3. Focus Section (Önemli)
Büyük UI grupları (örneğin bir Sidebar ve bir Grid) arasında geçiş yaparken, sistem bazen odağı kaybedebilir veya yanlış bir öğeye atlayabilir. Bunu engellemek için .focusSection() kullan.
Kullanım: Sidebar konteynerine .focusSection() ekle. Bu, Focus Engine'e "Buraya girildiğinde, en son kalınan öğeyi hatırla veya en mantıklı giriş noktasına git" emrini verir.
3. NAVİGASYON PATENLERİ
3.1. TabView (Ana İskelet)
tvOS için en standart ve güvenli yapı TabView'dur.
Stil: .tabViewStyle(.automatic) kullan. tvOS 13 ve öncesinde üstte (Top Bar), sonrasında duruma göre Sidebar veya Top Bar olarak render edilir.
İpucu: Her tab'ın kendine ait bir NavigationView (veya yeni NavigationStack) barındırması gerekir.
3.2. Shelf (Raf) Yapısı
Netflix/Apple TV+ tarzı içerik gösterimi için "Shelves" yapısını kullan.
Mimari: Dikey bir ScrollView içinde, yatay ScrollView'lar barındıran satırlar.
Önemli Detay: Yatay kaydırma yaparken (Shelf içinde), satırın başlığının da (Section Header) hafifçe büyümesi veya parlaması UX açısından harikadır.
Swift
ScrollView(.vertical) {
VStack(alignment: .leading) {
ForEach(categories) { category in
Text(category.title)
.font(.headline)
.padding(.leading, 80) // Overscan koruması
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 40) {
ForEach(category.items) { item in
MovieCard(item: item)
}
}
.padding(.horizontal, 80) // Başlangıç/Bitiş boşluğu
.padding(.vertical, 40) // Odaklanınca büyüme payı (Clip olmaması için)
}
}
}
}
4. UI BİLEŞENLERİ VE PARALLAX
4.1. Kartlar ve Butonlar
KURAL: tvOS'te "Tıklanabilir" her şey bir Button veya NavigationLink olmalıdır. Asla TapGesture kullanma.
Card Style: Kullanıcı bir öğeye odaklandığında, öğe hafifçe büyümeli, gölgesi artmalı ve üzerindeki parlama efekti (Shimmer) oynamalıdır.
Kod: SwiftUI'da bu bedavadır, ancak doğru modifier'ı kullanırsan:
Swift
Button(action: { openDetails() }) {
// Resim ve Overlay
ZStack(alignment: .bottom) {
AsyncImage(url: url) { image in
image.resizable().aspectRatio(contentMode: .fill)
}
Text("Title").padding()
}
}
.buttonStyle(.card) // <--- SİHİRLİ MODIFIER
4.2. Context Menüler
Kullanıcı bir öğe üzerindeyken kumandadaki butona uzun basarsa ne olur?
Best Practice: .contextMenu ekleyerek "Favorilere Ekle", "Fragman İzle" gibi ikincil aksiyonları sun.
5. UZAKTAN KUMANDA (SIRI REMOTE) GİRİŞLERİ
5.1. Metin Girişi (Text Input)
YASAK: Kullanıcıyı kumanda ile e-posta/şifre yazmaya zorlama. Bu en kötü tvOS deneyimidir.
ÇÖZÜM 1 (Siri): Arama alanlarında .searchable() kullan. Bu, dikte özelliğini otomatik açar.
ÇÖZÜM 2 (Authentication): Giriş yapmak için QR Kod veya Web URL + Kod (Device Flow) yöntemini kullan. "Telefonda devam et" seçeneği sun.
ÇÖZÜM 3 (Continuity): TextField kullanıldığında, aynı iCloud hesabına bağlı iPhone'a otomatik bildirim gider. Buna güven ama tek çare yapma.
5.2. Play/Pause Butonu
Kumandadaki Play/Pause butonu globaldir. Özel bir video oynatıcı yapıyorsan, bu butonun event'ini yakalamak için onPlayPauseCommand modifier'ını kullan.
6. MEDIA OYNATMA (VIDEO PLAYBACK)
6.1. Native Player Kullanımı
KURAL: Mümkünse her zaman AVPlayerViewController (UIKit wrap) veya SwiftUI VideoPlayer kullan.
Neden? Native player; Siri Remote ile ileri/geri sarma, altyazı menüsü, ses kontrolü ve Picture-in-Picture desteğini otomatik verir. Custom player yazmak tvOS'te çok zordur ve genellikle native hissi veremez.
6.2. Info Panel
Video oynarken kullanıcı aşağı kaydırırsa (Swipe Down), bir bilgi paneli (Info/Metadata) açılmalıdır. AVPlayerItem'ın externalMetadata özelliğini doldurarak buraya Poster, Başlık ve Açıklama bilgilerini gönder.
7. KAYNAK YÖNETİMİ VE PERFORMANS
7.1. App Size & ODR
tvOS uygulamalarının ana paketi 4GB ile sınırlıdır (App Store kuralı). Ancak yerel depolama garanti edilmez; sistem yer açmak için verileri silebilir.
Best Practice: Büyük asset'leri (videolar, yüksek çözünürlüklü level görselleri) uygulamanın içine gömme. On-Demand Resources (ODR) kullan. Agent olarak kod yazarken, assetlerin sunucudan çekileceğini veya ODR etiketleriyle çağrılacağını varsay.
7.2. Görüntü Yükleme
Listelerde yüzlerce yüksek çözünürlüklü poster olabilir. AsyncImage kullanırken mutlaka transaction animasyonu ekle ve disk cache mekanizması (örn. Kingfisher veya özel bir cache manager) kur. TV ekranı büyüktür, düşük çözünürlüklü resimler çok kötü görünür.
8. CHECKLIST FOR AGENT (GENERATION RULES)
Kod üretirken aşağıdaki listeyi adım adım kontrol et:
Platform Check: Kod sadece tvOS için mi? (#if os(tvOS)) Gerekirse macOS/iOS kodlarını ayıkla.
Focus Check: Yazdığın View'da FocusState tanımlı mı? İlk açılışta nereye odaklanacağı belli mi?
Interaction: Tıklanabilir alanlar .buttonStyle(.card) veya .buttonStyle(.plain) ile sarmalanmış mı? (Default button stili bazen şeffaf olabilir, dikkat et).
Layout: List yerine LazyVGrid veya ScrollView + HStack (Shelf) yapısı tercih edildi mi? (List tvOS'te ekranı ikiye bölen eski bir stile sahiptir, full-screen deneyimi için Grid daha iyidir).
Input: Login ekranı mı yazıyorsun? Klavye açtırma. QR Kod gösteren bir View oluştur.
9. SAMPLE CODE STRUCTURE (STARTING POINT)
Swift
import SwiftUI
@main
struct TVApp: App {
var body: some Scene {
WindowGroup {
MainTabView()
}
}
}
struct MainTabView: View {
var body: some View {
TabView {
HomeView()
.tabItem {
Label("Home", systemImage: "tv")
}
SearchView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")
}
SettingsView()
.tabItem {
Label("Settings", systemImage: "gear")
}
}
}
}