# 30. Hafta — Konum ve Sensör Mantığı

## Bu hafta ne yapacağız?

Flutter uygulamasında cihazın konum hizmetini güvenli biçimde kullanacağız. Önce konum servisinin açık olup olmadığını denetleyecek, ardından kullanıcı iznini yönetecek ve güncel koordinatı alacağız. İkinci uygulamada art arda alınan konum noktalarından yürüyüş mesafesi ve süresi hesaplayacağız.

Konum bilgisi kişisel veridir. Bu nedenle uygulama, konumu yalnız kullanıcının açık bir işlemi sonrasında istemeli; verinin neden gerektiğini açıklamalı ve gereksiz doğrulukta ya da sürede takip yapmamalıdır.

## Kazanımlar

- `geolocator` paketini projeye ekleme
- Konum hizmetinin açık olma durumunu denetleme
- Geçici ve kalıcı izin reddini ayırt etme
- Güncel enlem, boylam ve doğruluk bilgisini alma
- Asenkron işlem sırasında yüklenme ve hata durumlarını gösterme
- İki koordinat arasındaki mesafeyi hesaplama
- Konum sağlayıcısını soyutlayarak widget testinde sahte veri kullanma
- Konum verisinin gizlilik ve güvenlik gereksinimlerini açıklama

## Hazırlık

`pubspec.yaml` dosyasına konum paketi eklenir:

```yaml
dependencies:
  flutter:
    sdk: flutter
  geolocator: ^14.0.2
```

Android ve iOS için konum izinleri ayrıca platform dosyalarında tanımlanmalıdır. Paket eklemek tek başına izin penceresinin doğru çalışmasını garanti etmez.

## Çözümlü uygulama — Okul Konum Kartı

### Konum modelini oluşturma

Arayüz, eklenti paketinin `Position` sınıfına doğrudan bağımlı değildir:

```dart
class KonumBilgisi {
  const KonumBilgisi(this.enlem, this.boylam, this.dogruluk);

  final double enlem;
  final double boylam;
  final double dogruluk;
}
```

### Konum servisini soyutlama

```dart
abstract class KonumServisi {
  Future<KonumBilgisi> konumuAl();
}
```

Gerçek cihazda `CihazKonumServisi`, testte ise belirli koordinatlar döndüren `SahteKonumServisi` kullanılır. Böylece ekran testi GPS donanımına veya izin penceresine bağlı kalmaz.

### Hizmet ve izin denetimi

```dart
if (!await Geolocator.isLocationServiceEnabled()) {
  throw Exception('Konum hizmeti kapalı');
}

var izin = await Geolocator.checkPermission();
if (izin == LocationPermission.denied) {
  izin = await Geolocator.requestPermission();
}

if (izin == LocationPermission.denied ||
    izin == LocationPermission.deniedForever) {
  throw Exception('Konum izni verilmedi');
}
```

Akışın sırası önemlidir:

1. Cihazın konum hizmeti denetlenir.
2. Mevcut uygulama izni okunur.
3. Gerekirse kullanıcıdan izin istenir.
4. İzin hâlâ reddedilmişse konum alınmaz.

`deniedForever`, kullanıcının izni sistem ayarlarından değiştirmesi gerektiğini belirtir. Üretim uygulamasında bu durumda ayarlara yönlendiren açıklayıcı bir seçenek sunulabilir.

### Güncel koordinatı alma

```dart
final konum = await Geolocator.getCurrentPosition(
  locationSettings: const LocationSettings(
    accuracy: LocationAccuracy.high,
  ),
);

return KonumBilgisi(
  konum.latitude,
  konum.longitude,
  konum.accuracy,
);
```

`accuracy`, ölçümün yaklaşık hata payını metre cinsinden verir. Bu değer sıfır hata anlamına gelmez; çevre, cihaz ve kullanılan konum kaynağı sonucu etkiler.

### Arayüz durumlarını yönetme

```dart
setState(() {
  yukleniyor = true;
  mesaj = 'Uydu ve ağ bilgisi bekleniyor…';
});

try {
  final sonuc = await widget.servis.konumuAl();
  if (!mounted) return;
  setState(() {
    konum = sonuc;
    yukleniyor = false;
    mesaj = 'Güncel konum başarıyla alındı';
  });
} catch (hata) {
  if (!mounted) return;
  setState(() {
    yukleniyor = false;
    mesaj = hata.toString().replaceFirst('Exception: ', '');
  });
}
```

Yükleme sırasında düğme devre dışı bırakılır. Böylece öğrenci art arda dokunarak birden fazla konum isteği başlatamaz.

## Gerçek Flutter ekranı

Test, sahte servis üzerinden Ankara koordinatını ve 6,4 metre doğruluk bilgisini döndürdü. Ardından koordinat, doğruluk ve başarı mesajını doğrulayıp uygulamanın gerçek Flutter render çıktısını kaydetti.

![Okul Konum Kartı gerçek Flutter ekranı](../../screenshots/week-30-adapted.png)

## Özgün uygulama — Yürüyüş Günlüğü

Yürüyüş günlüğü art arda kaydedilen rota noktalarını saklar:

```dart
class Nokta {
  const Nokta(this.enlem, this.boylam, this.zaman);

  final double enlem;
  final double boylam;
  final DateTime zaman;
}
```

### Rota mesafesini hesaplama

```dart
double get mesafe {
  var toplam = 0.0;
  for (var i = 1; i < noktalar.length; i++) {
    toplam += Geolocator.distanceBetween(
      noktalar[i - 1].enlem,
      noktalar[i - 1].boylam,
      noktalar[i].enlem,
      noktalar[i].boylam,
    );
  }
  return toplam;
}
```

Her nokta yalnız kendinden önceki noktayla karşılaştırılır. Bütün parça mesafeleri toplanarak rota uzunluğu bulunur.

### Süreyi hesaplama

```dart
Duration get sure => noktalar.length < 2
    ? Duration.zero
    : noktalar.last.zaman.difference(noktalar.first.zaman);
```

İki nokta yoksa anlamlı bir yürüyüş süresi oluşmadığı için sıfır döndürülür.

### Yeni rota noktası ekleme

```dart
final nokta = await widget.servis.konumuAl();
if (!mounted) return;

setState(() {
  noktalar.add(nokta);
  bekleniyor = false;
  durum = '${noktalar.length}. rota noktası kaydedildi';
});
```

![Yürüyüş Günlüğü gerçek Flutter ekranı](../../screenshots/week-30-original.png)

Test iki farklı koordinatı on iki dakika arayla ekledi. Uygulama 132 metrelik toplam mesafeyi, süreyi, nokta sayısını ve iki rota kaydını gerçek arayüzde gösterdi.

## Konum doğruluğu ve sensör mantığı

- `lowest`: çok düşük güç tüketimi, düşük doğruluk
- `low`: yaklaşık konum gereken işler
- `medium`: dengeli kullanım
- `high`: daha hassas konum
- `best`: cihazın sağlayabildiği yüksek doğruluk

Her uygulama en yüksek doğruluğa ihtiyaç duymaz. Örneğin şehir seçimi için yaklaşık konum yeterliyken yaya rotasında daha yüksek doğruluk gerekebilir. Yüksek doğruluk pil tüketimini ve konum alma süresini artırabilir.

## Gizlilik ilkeleri

- İzin istemeden önce konumun neden gerekli olduğunu açıklayın.
- Kullanıcı işlemi olmadan arka planda takip başlatmayın.
- Yalnız ihtiyaç duyulan doğruluğu kullanın.
- Koordinatı gereksiz yere sunucuya göndermeyin.
- Kaydedilen konum için silme ve açık onay seçenekleri sunun.
- Çocukların kullandığı eğitim uygulamalarında konum verisini özellikle sınırlayın.
- Ekran görüntüsü veya log içine gerçek öğrenci koordinatı koymayın.

## Sık yapılan hatalar

- Konum hizmeti kapalıyken doğrudan koordinat istemek
- `deniedForever` durumunu normal ret ile aynı şekilde yönetmek
- `await` sonrasında `mounted` kontrolü yapmamak
- Tek ölçümü kesin konum sanmak
- Metre ve kilometre birimlerini karıştırmak
- Aynı noktayı tekrar tekrar ekleyip mesafeyi yapay olarak büyütmek
- Konum sağlayıcısını doğrudan widget içine gömerek testi cihaz bağımlı yapmak

## Üç uygulama görevi

### Kolay — Yakındaki okul kartı

Öğrencinin konumunu yalnız düğmeye basınca alın. Sabit okul koordinatıyla arasındaki kuş uçuşu mesafeyi metre ve kilometre olarak gösterin.

### Orta — Servis buluşma noktası

Öğrencinin konumu ile servis durağı arasındaki mesafeyi hesaplayın. Konum izni reddedildiğinde elle mahalle seçme alternatifi sunun.

### İleri — Güvenli yürüyüş kaydı

Zaman aralıklarıyla rota noktaları toplayın. Doğruluğu belirli sınırdan kötü olan noktaları hesaba katmayın, toplam mesafeyi ve ortalama hızı gösterin. Takibi açık bir durdurma düğmesiyle sonlandırın.

## Test ve kontrol

- Hizmet kapalı durumu anlaşılır mesaj üretiyor mu?
- İlk kullanımda izin isteniyor mu?
- Reddedilen izin konum isteğini durduruyor mu?
- Koordinatlar istenen ondalık hassasiyetle gösteriliyor mu?
- Doğruluk bilgisi kullanıcıya açıklanıyor mu?
- İki rota noktası arasındaki mesafe doğru hesaplanıyor mu?
- Süre ilk ve son noktanın zamanlarından bulunuyor mu?
- Test gerçek GPS yerine sahte servis kullanıyor mu?
- Konum ancak kullanıcının açık işlemiyle alınıyor mu?

## Geri bildirim ve çözüm erişimi

Öğrenci uygulamasını gönderip geri bildirim aldıktan sonra **İpucunu göster** yalnızca hizmet–izin–konum sırasını ve mesafe hesabının yaklaşımını açıklar. **Örnek çözümü göster** gerçek `KonumServisi`, izin yönetimi, arayüz ve rota hesaplama kodlarını açar. İndirme bağlantıları iki bağımsız çalışan Flutter projesini sunar.

## Kaynak projeler

- Konu uygulaması: `08 - Cihaz Özellikleri ve Kalite/Uygulamalar/Uygulama-30-Konum Kartı`
- Özgün uygulama: `08 - Cihaz Özellikleri ve Kalite/Uygulamalar/Ozgun-30-Yürüyüş Günlüğü`
