Files
imajviewer/docs/Implementation.md

210 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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** |