build: github acik kaynak hazirligi — LICENSE/CI/topluluk dosyalari eklendi, binary'ler takipten cikarildi, README EN, kok dokumanlar docs/'a tasindi

This commit is contained in:
Alhan committed 2026-08-06 05:49:43 +03:00
1 parent cd3f573f57
commit 8972ef7225
35 files changed
+560 -151

No files matched your search

+209
View File
@@ -0,0 +1,209 @@
# 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** |