# Implementation — imajViewer

> Teknik uygulama dokümanı
> Versiyon: 1.0

---

## 1. Mimari Genel Bakış

```
┌──────────────────────────────────────────────────┐
│                  Flutter App                      │
│  ┌────────────┐  ┌────────────────────────────┐  │
│  │ window_mgr │  │     ViewerScreen            │  │
│  │ (frameless)│  │  ┌──────────────────────┐   │  │
│  └────────────┘  │  │  CustomTitleBar      │   │  │
│                  │  │  (minimize, close)    │   │  │
│                  │  ├──────────────────────┤   │  │
│                  │  │  ImageCanvas          │   │  │
│                  │  │  (InteractiveViewer)  │   │  │
│                  │  │  - Scroll → Zoom      │   │  │
│                  │  │  - Drag → Pan         │   │  │
│                  │  └──────────────────────┘   │  │
│                  └────────────────────────────┘  │
│  ┌────────────────────────────────────────────┐  │
│  │         ImageCacheManager                   │  │
│  │  - PrecacheImage                            │  │
│  │  - LRU eviction (> N images)                │  │
│  │  - File → Memory → GPU Texture              │  │
│  └────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘
```

## 2. Bileşen Ağacı (Widget Tree)

```
MaterialApp (dark theme)
└── ViewerScreen (StatefulWidget)
    ├── Stack
    │   ├── InteractiveViewer (zoom + pan)
    │   │   └── RawImage (resim)
    │   ├── CustomTitleBar (Positioned: top-right)
    │   │   ├── IconButton (minimize)
    │   │   └── IconButton (close)
    │   └── (koyu arka plan)
    └── DragTarget (sürükle-bırak dosya alanı)
```

## 3. Data Flow

```
Kullanıcı dosya bırakır / açar
       │
       ▼
ViewerScreen.dragResult / openFileDialog
       │
       ▼
ImageList (List<String> filePaths)
       │
       ▼
preloadImages() → ImageCache'e ekle
       │
       ▼
Indexed, currentIndex değişince
       │
       ▼
InteractiveViewer.builder → Image.file(path)
       │
       ▼
Flutter ImageCache → GPU Texture → Render
```

## 4. Adım Adım Uygulama

### Adım 1: Proje İskeleti
- `flutter create imajViewer`
- `--platforms=linux` ile oluştur
- Temele dark tema, frameless window ekle

**Dosyalar:** `main.dart`, `app.dart`

### Adım 2: window_manager Kurulumu
- pubspec.yaml: `window_manager: ^0.4.3`
- `main()` içinde `windowManager.ensureInitialized()`
- `waitUntilReadyToShow` → frameless ayarları:
  - `setTitleBarStyle(TitleBarStyle.hidden)`
  - `setSize(Size(1280, 800))`
  - `setMinimumSize(Size(800, 600))`
  - `setBackgroundColor(Colors.transparent)`
- Linux'ta `linux/my_app.cc`'de window_manager için ek ayar gerekebilir

**Dosyalar:** `lib/main.dart`, `pubspec.yaml`

### Adım 3: CustomTitleBar Widget
- Sağ üst köşede, sabit konumda
- Siyah yarı saydam arka plan
- minimize (—) ve kapat (X) butonları
- **Püf nokta:** Butonların üzerine gelince InteractiveViewer zoom yapmamalı
  - `AbsorbPointer` veya `IgnorePointer` ile InteractiveViewer etkileşimini engelle
- Pencere boyutlandırma ve sürükleme kenarlıkları (window_manager'in `setResizable` özelliği)

**Dosya:** `lib/widgets/custom_title_bar.dart`

### Adım 4: ImageCanvas (Ana Görüntüleme)
- `InteractiveViewer` widget'ı
  - `boundaryMargin: EdgeInsets.all(double.infinity)` → sınırsız kaydırma
  - `minScale: 0.1`, `maxScale: 10.0`
  - `onInteractionUpdate` → zoom oranını göstermek için (ops.)
  - `transformationController` ile programatik zoom kontrolü
- Mouse wheel event: `Listener` ile `onPointerSignal` yakala
  - `PointerScrollEvent` → transformationController ile zoom
  - Fare imlecinin resim üzerindeki konumuna göre zoom odağı

**Püf nokta:**
`InteractiveViewer`'ın default scroll-to-zoom desteği vardır ama imleç odağında zoom
için `TransformationController`'a manuel matrix hesaplaması yapmak gerekir.

**Dosya:** `lib/widgets/image_canvas.dart`

### Adım 5: Resim Yönetimi (ImageManager)
- `ChangeNotifier` ile state yönetimi
- Dışarıdan dosya eklendiğinde `notifyListeners()` + `precacheImage()`
- `ImageCache.maximumSize` ve `maximumSizeBytes` ayarı
- **Performans stratejisi:**
  - Sadece görünen resim bellekte tutulur
  - 12+ resim için `ImageCache.maximumSizeBytes` = 512MB
  - Resim değiştirince önceki resmin cache'ini düşürmeye gerek yok (Flutter LRU)
- Sürükle-bırak: `DragTarget<List<File>>` widget'ı

**Dosya:** `lib/services/image_manager.dart`

### Adım 6: Dosya Açma (Dialog + DragDrop)
- `file_picker` paketi ile `Ctrl+O` kısayolu
- `DragTarget` ile sürükle-bırak
- Desteklenen format filtreleri: PNG, JPEG, WebP, BMP, GIF
- **Dikkat:** Flutter Linux'ta DragTarget çalışıyor — ayrıca `window_manager`'dan `onDragFile` event'i de var

**Dosya:** `lib/services/file_handler.dart`

### Adım 7: Klavye Kısayolları
- Flutter'daki `Shortcuts` + `Actions` sistemi
- `← →` → resim değiştir
- `Ctrl+O` → dosya aç
- `F11` → tam ekran (fullscreen toggle)
- `Esc` → tam ekrandan çık
- `Ctrl+Q` → çıkış

**Dosya:** `lib/shortcuts/app_shortcuts.dart`

### Adım 8: Birleştirme ve Test
- Ana ekranı `ViewerScreen`'de topla
- `Listener(onPointerSignal)` + `InteractiveViewer` entegrasyonu
- `flutter run -d linux` ile test
- Performance profiling: `flutter run --profile`

### Adım 9: Derleme
- `flutter build linux --release`
- Binary: `build/linux/x64/release/bundle/imajViewer`

## 5. pubspec.yaml Bağımlılıkları

```yaml
dependencies:
  flutter:
    sdk: flutter
  window_manager: ^0.4.3
  file_picker: ^8.0.0
  path: ^1.9.0
```

## 6. Önemli Dikkat Noktaları

### Zoom Odağı (Cursor-based Zoom)
InteractiveViewer varsayılan zoom odağı merkezdir. İmleç odağında zoom için
`TransformationController` ile manuel matrix çarpımı:

```
1. Scroll event yakala (PointerScrollEvent)
2. İmlecin resim üzerindeki koordinatını hesapla
3. Matrix4.translationValues(-txt) * Matrix4.diagonal3(values(scale)) * Matrix4.translationValues(txt)
```

Detaylı implementasyon `image_canvas.dart`'da yapılacak.

### Frameless Window Sürükleme
Window_manager zaten varsayılan olarak fare ile pencerenin herhangi bir
yerinden sürüklenmesine izin vermez. Bunun için:
- CustomTitleBar alanını `DragToMoveArea` ile sarmak
- Veya `windowManager.startDragging()` çağırmak

Biz `DragToMoveArea` widget'ını kullanacağız.

### Performans
- Flutter'ın `ImageCache`'i varsayılan olarak 50 MB ve 1000 entry ile sınırlıdır
- 12 adet 4K resim için `ImageCache.maximumSizeBytes` 1 GB'a çıkarılmalı
- `RepaintBoundary` ile sadece değişen bölgelerin yeniden çizilmesi sağlanır
- `Texture` bazlı render ile GPU'da işleme devam eder

## 7. Timeline

| Adım | İş | Tahmini Süre |
|---|---|---|
| 1-2 | Proje iskeleti + window_manager | 15 dk |
| 3 | CustomTitleBar | 15 dk |
| 4 | ImageCanvas + zoom | 30 dk |
| 5-6 | Resim yönetimi + dosya açma | 30 dk |
| 7 | Kısayollar | 10 dk |
| 8-9 | Birleştirme + build | 20 dk |
| **Toplam** | | **~2 saat** |
