commit 21280197acf0d58740fa17f1a898c3e226857f57 Author: Ümit Tunç Date: Wed Apr 29 21:25:36 2026 +0300 docs: create implementation plan for project fastwatcher diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md new file mode 100644 index 0000000..daf8493 --- /dev/null +++ b/docs/implementation-plan.md @@ -0,0 +1,97 @@ +### 1. Temel Teknoloji Yığını ve Kütüphaneler + +| Kategori | Kütüphane / Teknoloji | Neden Bu Tercih Edilmeli? | +| :--- | :--- | :--- | +| **State Management** | `flutter_riverpod` | SOLID'in Dependency Inversion (D) prensibini uygulamak ve servisleri izole etmek için en modern ve güvenli yöntem. | +| **Cihaz Keşfi (mDNS)** | `nsd` veya `bonsoir` | Zero-config ağ keşfi için endüstri standardı. TV kendini yayınlar, telefon bulur. | +| **Ağ İletişimi** | `shelf` (Local HTTP Server) | TV tarafında raw TCP socket yerine küçük bir REST API (HTTP Server) kurmak hata yönetimini ve loglamayı inanılmaz kolaylaştırır. | +| **Video Oynatıcı** | `media_kit` | *Chewie/Video_player yerine kesinlikle bunu kullanmalısın.* libmpv tabanlıdır. HLS (.m3u8), MKV ve özel codec'leri Android TV'de kusursuz oynatır. | +| **Link Yakalama** | `receive_sharing_intent` | Mobil cihazda tarayıcıdan "Paylaş" aksiyonunu dinlemek için. | +| **Lokal Depolama** | `shared_preferences` | Cihazın "TV" mi yoksa "Mobil" mi olduğunu ilk seçimden sonra hatırlamak için. | + +--- + +### 2. Proje Klasör Yapısı (Clean Architecture) + +Kodun test edilebilir ve modüler olması için *Feature-First* (Özellik Odaklı) bir Clean Architecture yapısı kurmalıyız: + +```text +lib/ +├── core/ # Tüm projede ortak kullanılan yapılar +│ ├── constants/ # Port numaraları, API endpoint'leri +│ ├── error/ # Custom exception sınıfları +│ └── network/ # Temel ağ arayüzleri +├── features/ +│ ├── setup/ # Cihaz rolü (TV/Telefon) seçim ekranı +│ ├── discovery/ # mDNS ile cihaz arama ve eşleşme (Mobil) +│ ├── receiver/ # TV tarafı: Local server ve oynatıcı +│ └── sender/ # Mobil taraf: Link yakalama ve gönderme +└── main.dart # Riverpod ProviderScope ve Init işlemleri +``` + +Her `feature` (özellik) kendi içinde şu üç katmana ayrılmalıdır (SOLID uygulamasının kalbi): +* **domain:** Sadece saf Dart kodları. Arayüzler (`abstract class`), entity'ler. +* **data:** Dış dünyayla iletişim. API çağrıları, paket implementasyonları. +* **presentation:** UI (Widget'lar) ve State (Riverpod Notifier'lar). + +--- + +### 3. Kritik İş Akışları ve "Best Practice" Yöntemler + +#### A. İlk Açılış ve Rol Seçimi (Setup) +Kullanıcı uygulamayı ilk açtığında karşısına iki dev buton çıkar: "Ben bir Telefonum (Gönderici)" ve "Ben bir TV'yim (Alıcı)". +* **Best Practice:** Bu seçim yapıldığı an `SharedPreferences`'a kaydedilir (`role = 'sender' | 'receiver'`). Uygulamanın bir sonraki açılışında `main.dart` bu değeri okur ve kullanıcıyı doğrudan ilgili ana ekrana yönlendirir. + +#### B. Cihaz Eşleştirme (Discovery - mDNS) +Bluetooth yerine aynı ağda **mDNS (Zero-conf)** kullanmak en stabil "Best Practice" yöntemdir. + +1. **TV (Receiver):** Uygulama açılır açılmaz arka planda `nsd` ile bir servis kaydeder. Örnek servis adı: `FastWatcher._http._tcp`. Ayrıca `shelf` ile 8080 portunda bir HTTP server dinlemeye başlar (`POST /play`). +2. **Mobil (Sender):** "Eşleş" butonuna basıldığında ağı tarar. Bulunan cihazların IP'sini bir listeye koyar. Kullanıcı TV'sine dokunduğunda IP adresi telefona kaydedilir. + +#### C. İletişim Protokolü (HTTP üzerinden) +Raw Socket'ler veriyi bölebilir veya bağlantı kopmalarında sorun yaratabilir. TV'de mini bir HTTP sunucusu kurmak çok daha "Solid" bir çözümdür. + +* **Mobil'in Gönderdiği Payload (JSON):** + ```json + { + "url": "https://site.com/master.m3u8", + "title": "The Instigators (Opsiyonel)", + "timestamp": 1714415045 + } + ``` +* **TV'nin Yanıtı:** `200 OK` (Başarıyla aldım, oynatmaya başlıyorum). + +--- + +### 4. SOLID Prensiplerinin Projeye Uygulanması + +Bu projeyi "Solid" yapacak mimari kararlar şunlardır: + +* **S (Tek Sorumluluk):** `DiscoveryService` sadece ağı tarar. UI'a karışmaz. Ekrana yazdırma işini `DiscoveryNotifier` (State) ve `DiscoveryScreen` yapar. +* **O (Açık/Kapalı):** İletişim katmanını bir `abstract class NetworkClient` olarak tanımla. Şu an Wi-Fi (HTTP) kullanıyoruz. Yarın Bluetooth eklemek istersen, mevcut kodu bozmadan yeni bir `BluetoothClient` implementasyonu ekleyebilirsin. +* **L (Liskov Yerine Geçme):** Eğer TV tarafında birden fazla oynatıcı motoru kullanma ihtimalin varsa (örn: `MediaKitPlayer` ve yedek olarak `ExoPlayer`), ikisi de bir `abstract class AppVideoPlayer` arayüzünden türemelidir. +* **I (Arayüz Ayrımı):** Sender ve Receiver çok farklı işler yapar. Her iki rol için devasa tek bir arayüz yazmak yerine, `ILinkSender` ve `ILinkReceiver` olarak küçük arayüzlere böl. +* **D (Bağımlılıkların Tersine Çevrilmesi):** UI sınıfların (Widget'lar) asla doğrudan `nsd` veya `shelf` paketini bilmemelidir. Araya yazdığın soyut Repository sınıflarını (Riverpod üzerinden) UI'a enjekte etmelisin. + +--- + +### 5. Geliştirme Adımları (Faz Planı) + +**Faz 1: Çekirdek ve İletişim (UI Olmadan)** +1. Proje yapısını ve Riverpod kurulumunu tamamla. +2. TV tarafı için `shelf` ile basit bir HTTP server yaz ve Postman ile test et. +3. TV tarafında `nsd` servisini başlat. +4. Mobil tarafta ağı tarayıp TV'nin IP'sini bulan kodu yaz. + +**Faz 2: Gönderim ve Oynatma** +1. Mobil cihazdan HTTP POST ile TV'ye manuel bir test linki (.m3u8) gönder. +2. TV tarafında `media_kit` paketini kur ve gelen linki tam ekranda (kumanda odaklamalarına dikkat ederek) oynatan sayfayı tasarla. + +**Faz 3: Entegrasyon (Link Yakalama)** +1. Mobil tarafa `receive_sharing_intent` paketini kur. +2. Android Manifest ayarlarını yapıp, tarayıcıdan uygulamana link düşmesini sağla. +3. Gelen linki ayrıştır (Parse) ve eşleşmiş olan TV'ye fırlat. + +Bu mimariyle yazdığın bir kod hem çok hızlı çalışacak hem de aylar sonra dönüp baktığında nerede ne olduğunu saniyeler içinde bulabileceksin. + +İlk olarak projeyi ayağa kaldırdıktan sonra, `shelf` ile TV tarafındaki o mini HTTP sunucusunun arayüzünü (Interface) tasarlayarak başlamak ister misin? Sana o kısmın Dependency Inversion'a uygun örnek kodunu yazabilirim. \ No newline at end of file