# 9. Hafta — StatelessWidget ve StatefulWidget

## Bu hafta ne yapacağız?

Bir Flutter atölyesinin katılımcı sayısını anlık değiştiren sayaç geliştireceğiz. Ekranda değişmeyen başlıklarla değişen sayı arasındaki fark üzerinden `StatelessWidget`, `StatefulWidget`, `State` ve `setState` kavramlarını öğreneceğiz. Ardından gerçek zamanlı çalışan Pomodoro sayacı yapacağız.

## Kazanımlar

- Değişmeyen arayüzü `StatelessWidget` ile kurma
- Değişen veriyi `State` nesnesinde tutma
- Kullanıcı olayından sonra `setState` ile ekranı yenileme
- Durumu alt ve üst sınırlar içinde koruma
- `Timer` kaynağını yaşam döngüsüne uygun kapatma

## Uygulama 09 — Atölye Katılımcı Sayacı

### 1. Hangi widget neden durumlu?

Uygulamanın tema ve başlangıç sayfasını oluşturan `SayacApp` değişmez; bu nedenle `StatelessWidget` olur. Katılımcı sayısı düğmelerle değiştiği için ekran `StatefulWidget` olmalıdır.

```dart
class SinifSayaci extends StatefulWidget {
  const SinifSayaci({super.key});

  @override
  State<SinifSayaci> createState() => _SinifSayaciState();
}
```

### 2. Durumu tanımlama

```dart
int katilimci = 12;
int hedef = 20;
```

Bu değişkenler `build` içinde tanımlanmaz. Aksi hâlde ekran her çizildiğinde yeniden başlangıç değerine döner.

### 3. Durumu güvenli değiştirme

```dart
void degistir(int fark) {
  setState(() {
    katilimci = (katilimci + fark).clamp(0, hedef);
  });
}
```

`clamp`, değeri 0–20 aralığında tutar. Sayı değişince ilerleme çubuğu ve kalan yer de aynı durumdan yeniden hesaplanır:

```dart
final oran = katilimci / hedef;
Text('${hedef - katilimci} boş yer kaldı');
```

Testte bir katılımcı eklendi; sayaç 13, kalan yer 7 oldu.

![13 katılımcıyı gösteren Atölye Sayacı](../../screenshots/week-09-adapted.png)

## Özgün proje — Pomodoro Sayacı

Pomodoro ekranında yalnız kullanıcı eylemi değil, zaman da durumu değiştirir. Kalan saniye, çalışıyor bilgisi ve tamamlanan tur sayısı `State` içinde tutulur.

```dart
static const calismaSuresi = 25 * 60;
int kalan = calismaSuresi;
int tamamlanan = 0;
bool calisiyor = false;
Timer? zamanlayici;
```

### Zamanlayıcıyı başlatma

```dart
zamanlayici = Timer.periodic(const Duration(seconds: 1), (_) {
  if (!mounted) return;
  setState(() {
    if (kalan > 1) {
      kalan--;
    } else {
      kalan = calismaSuresi;
      tamamlanan++;
      calisiyor = false;
      zamanlayici?.cancel();
    }
  });
});
```

`mounted`, widget ekrandan kaldırılmışsa güncelleme yapılmasını engeller. Sayaç durdurulurken, sıfırlanırken ve widget kapanırken `Timer` iptal edilir:

```dart
@override
void dispose() {
  zamanlayici?.cancel();
  super.dispose();
}
```

### Saniyeyi saat görünümüne çevirme

```dart
final dakika = (kalan ~/ 60).toString().padLeft(2, '0');
final saniye = (kalan % 60).toString().padLeft(2, '0');
```

Testte sayaç başlatıldı, sanal olarak bir saniye ilerletildi ve `24:59` olduğu doğrulandı; ardından duraklatıldı. Görsel, gerçek sayaç mantığının ürettiği bu durumu gösterir.

![Bir saniye çalıştırılıp duraklatılmış Pomodoro Sayacı](../../screenshots/week-09-original.png)

## Sıra sende

1. Kolay: Katılımcı sayacının hedefini 25 yap.
2. Orta: Pomodoro uygulamasına 5 dakikalık mola modu ekle.
3. İleri: Dört odak turundan sonra otomatik 15 dakikalık uzun mola başlat.

Çözümünü gönderdikten ve geri bildirim aldıktan sonra Pomodoro Sayacı’nın gerçek Dart kodu ile çalışan proje paketi açılacaktır. İpucu yalnız durum değişkenlerini belirlemene yardım edecek; çözüm düğmesi eksiksiz `lib/main.dart` içeriğini gösterecektir.

## Kontrol listesi

- Yalnız değişen ekran bölümü `StatefulWidget` içinde tutuldu.
- Durum `build` metodunda yeniden oluşturulmadı.
- Sayaç alt ve üst sınırları aşmıyor.
- `Timer`, `dispose` içinde iptal ediliyor.
- İki proje Flutter widget testinden geçti ve gerçek ekran çıktıları görsel olarak doğrulandı.
