# Navigation Hub

<div id="introduction"></div>

## Giris

Navigation Hub'lar, tum widget'lariniz icin navigasyonu **yonetebileceginiz** merkezi bir yerdir.
Kutudan ciktigi haliyle saniyeler icinde alt, ust ve journey navigasyon duzenleri olusturabilirsiniz.

Bir uygulamaniz oldugunu ve alt navigasyon cubugu ekleyerek kullanicilarin uygulamanizdaki farkli sekmeler arasinda gezinmesini istediginizi **hayal edelim**.

Bunu olusturmak icin bir Navigation Hub kullanabilirsiniz.

Uygulamanizda Navigation Hub'i nasil kullanabileceginize bakalim.

<div id="basic-usage"></div>

## Temel Kullanim

Asagidaki komutu kullanarak bir Navigation Hub olusturabilirsiniz.

``` bash
metro make:navigation_hub base
```

Komut sizi interaktif bir kurulum surecinden gecirecektir:

1. **Bir duzen turu secin** - `navigation_tabs` (alt navigasyon) veya `journey_states` (sirali akis) arasinda secim yapin.
2. **Sekme/durum adlarini girin** - Sekmeleriniz veya journey durumlari icin virgullerle ayrilmis adlar girin.

Bu, `resources/pages/navigation_hubs/base/` dizininiz altinda dosyalar olusturacaktir:
- `base_navigation_hub.dart` - Ana hub widget'i
- `tabs/` veya `states/` - Her sekme veya journey durumu icin alt widget'lari icerir

Olusturulan bir Navigation Hub su sekilde gorunur:

``` dart
import 'package:flutter/material.dart';
import 'package:nylo_framework/nylo_framework.dart';
import '/resources/pages/navigation_hubs/base/tabs/home_tab_widget.dart';
import '/resources/pages/navigation_hubs/base/tabs/settings_tab_widget.dart';

class BaseNavigationHub extends NyStatefulWidget with BottomNavPageControls {
  static RouteView path = ("/base", (_) => BaseNavigationHub());

  BaseNavigationHub()
      : super(
            child: () => _BaseNavigationHubState(),
            stateName: path.stateName());

  /// Durum eylemleri
  static NavigationHubStateActions stateActions = NavigationHubStateActions(path.stateName());
}

class _BaseNavigationHubState extends NavigationHub<BaseNavigationHub> {

  /// Duzen olusturucu
  @override
  NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();

  /// Durumun korunup korunmayacagi
  @override
  bool get maintainState => true;

  /// Baslangic indeksi
  @override
  int get initialIndex => 0;

  /// Navigasyon sayfalari
  _BaseNavigationHubState() : super(() => {
      0: NavigationTab.tab(title: "Home", page: HomeTab()),
      1: NavigationTab.tab(title: "Settings", page: SettingsTab()),
  });

  /// Dokunma olayini isle
  @override
  onTap(int index) {
    super.onTap(index);
  }
}
```

Navigation Hub'in **iki** sekmesi oldugunu gorebilirsiniz: Home ve Settings.

`layout` metodu hub'in duzen turunu dondurur. Duzeninizi yapilandirirken tema verilerine ve medya sorgularina erisebilmeniz icin bir `BuildContext` alir.

Navigation Hub'a `NavigationTab`'lar ekleyerek daha fazla sekme olusturabilirsiniz.

Oncelikle, Metro kullanarak yeni bir widget olusturmaniz gerekir.

``` bash
metro make:stateful_widget news_tab
```

Ayni anda birden fazla widget de olusturabilirsiniz.

``` bash
metro make:stateful_widget news_tab,notifications_tab
```

Ardindan, yeni widget'i Navigation Hub'a ekleyebilirsiniz.

``` dart
_BaseNavigationHubState() : super(() => {
    0: NavigationTab.tab(title: "Home", page: HomeTab()),
    1: NavigationTab.tab(title: "Settings", page: SettingsTab()),
    2: NavigationTab.tab(title: "News", page: NewsTab()),
});
```

Navigation Hub'i kullanmak icin, router'iniza baslangic rotasi olarak ekleyin:

``` dart
import 'package:nylo_framework/nylo_framework.dart';

appRouter() => nyRoutes((router) {
    ...
    router.add(BaseNavigationHub.path).initialRoute();
});

// veya uygulamanizin herhangi bir yerinden Navigation Hub'a git

routeTo(BaseNavigationHub.path);
```

Navigation Hub ile yapabileceginiz cok **daha fazla** sey var, bazi ozelliklerine bakalim.

<div id="bottom-navigation"></div>

### Alt Navigasyon

`layout` metodundan `NavigationHubLayout.bottomNav` dondurerek duzeni alt navigasyon cubuguna ayarlayabilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
```

Alt navigasyon cubugunu asagidaki gibi ozellikler ayarlayarak ozellestebilirsiniz:

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav(
        backgroundColor: Colors.white,
        selectedItemColor: Colors.blue,
        unselectedItemColor: Colors.grey,
        elevation: 8.0,
        iconSize: 24.0,
        selectedFontSize: 14.0,
        unselectedFontSize: 12.0,
        showSelectedLabels: true,
        showUnselectedLabels: true,
        type: BottomNavigationBarType.fixed,
    );
```

`style` parametresini kullanarak alt navigasyon cubuguna hazir bir stil uygulayabilirsiniz.

``` dart
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav(
    style: BottomNavStyle.material(), // Varsayilan Flutter material stili
);
```

<div id="custom-nav-bar-builder"></div>

### Ozel Nav Bar Builder

Navigasyon cubugunuz uzerinde tam kontrol icin `navBarBuilder` parametresini kullanabilirsiniz.

Bu, navigasyon verilerini almaya devam ederken herhangi bir ozel widget olusturmanizi saglar.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav(
        navBarBuilder: (context, data) {
            return MyCustomNavBar(
                items: data.items,
                currentIndex: data.currentIndex,
                onTap: data.onTap,
            );
        },
    );
```

`NavBarData` nesnesi sunlari icerir:

| Ozellik | Tur | Aciklama |
| --- | --- | --- |
| `items` | `List<BottomNavigationBarItem>` | Navigasyon cubugu ogeleri |
| `currentIndex` | `int` | Su anda secili olan indeks |
| `onTap` | `ValueChanged<int>` | Bir sekmeye dokunuldugunda cagirilan callback |

Iste tamamen ozel bir glass navigasyon cubugu ornegi:

``` dart
NavigationHubLayout.bottomNav(
    navBarBuilder: (context, data) {
        return Padding(
            padding: EdgeInsets.all(16),
            child: ClipRRect(
                borderRadius: BorderRadius.circular(25),
                child: BackdropFilter(
                    filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
                    child: Container(
                        decoration: BoxDecoration(
                            color: Colors.white.withValues(alpha: 0.7),
                            borderRadius: BorderRadius.circular(25),
                        ),
                        child: BottomNavigationBar(
                            items: data.items,
                            currentIndex: data.currentIndex,
                            onTap: data.onTap,
                            backgroundColor: Colors.transparent,
                            elevation: 0,
                        ),
                    ),
                ),
            ),
        );
    },
)
```

> **Not:** `navBarBuilder` kullanildiginda `style` parametresi yok sayilir.

<div id="top-navigation"></div>

### Ust Navigasyon

`layout` metodundan `NavigationHubLayout.topNav` dondurerek duzeni ust navigasyon cubuguna degistirebilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.topNav();
```

Ust navigasyon cubugunu asagidaki gibi ozellikler ayarlayarak ozellestebilirsiniz:

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.topNav(
        backgroundColor: Colors.white,
        labelColor: Colors.blue,
        unselectedLabelColor: Colors.grey,
        indicatorColor: Colors.blue,
        indicatorWeight: 3.0,
        isScrollable: false,
        hideAppBarTitle: true,
    );
```

<div id="journey-navigation"></div>

### Journey Navigasyonu

`layout` metodundan `NavigationHubLayout.journey` dondurerek duzeni journey navigasyonuna degistirebilirsiniz.

Bu, baslangic akislari veya cok adimli formlar icin harikadir.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
        progressStyle: JourneyProgressStyle(
          indicator: JourneyProgressIndicator.segments(),
        ),
    );
```

Journey duzeni icin bir `backgroundGradient` de ayarlayabilirsiniz:

``` dart
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
    backgroundGradient: LinearGradient(
        colors: [Colors.blue, Colors.purple],
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
    ),
    progressStyle: JourneyProgressStyle(
      indicator: JourneyProgressIndicator.linear(),
    ),
);
```

> **Not:** `backgroundGradient` ayarlandiginda, `backgroundColor`'dan onceliklidir.

Journey navigasyon duzenini kullanmak istiyorsaniz, **widget'lariniz** `JourneyState` kullanmalidir cunku yolculugu yonetmenize yardimci olacak bircok yardimci metot icerir.

`make:navigation_hub` komutunu `journey_states` duzeni ile kullanarak tum yolculugu olusturabilirsiniz:

``` bash
metro make:navigation_hub onboarding
# Sec: journey_states
# Gir: welcome, personal_info, add_photos
```

Bu, hub'i ve tum journey state widget'larini `resources/pages/navigation_hubs/onboarding/states/` altinda olusturacaktir.

Veya tek tek journey widget'lari olusturmak icin su komutu kullanabilirsiniz:

``` bash
metro make:journey_widget welcome,phone_number_step,add_photos_step
```

Ardindan yeni widget'lari Navigation Hub'a ekleyebilirsiniz.

``` dart
_MyNavigationHubState() : super(() => {
    0: NavigationTab.journey(
        page: Welcome(),
    ),
    1: NavigationTab.journey(
        page: PhoneNumberStep(),
    ),
    2: NavigationTab.journey(
        page: AddPhotosStep(),
    ),
});
```

<div id="journey-progress-styles"></div>

### Ilerleme Stilleri

Ilerleme gostergesi stilini `JourneyProgressStyle` sinifini kullanarak ozellestirebilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
        progressStyle: JourneyProgressStyle(
            indicator: JourneyProgressIndicator.linear(
                activeColor: Colors.blue,
                inactiveColor: Colors.grey,
                thickness: 4.0,
            ),
        ),
    );
```

Asagidaki ilerleme gostergelerini kullanabilirsiniz:

- `JourneyProgressIndicator.none()`: Hicbir sey render etmez - belirli bir sekmede gostergeyi gizlemek icin kullanislidir.
- `JourneyProgressIndicator.linear()`: Dogrusal ilerleme cubugu.
- `JourneyProgressIndicator.dots()`: Nokta tabanli ilerleme gostergesi.
- `JourneyProgressIndicator.numbered()`: Numarali adim ilerleme gostergesi.
- `JourneyProgressIndicator.segments()`: Bolumlu ilerleme cubugu stili.
- `JourneyProgressIndicator.circular()`: Dairesel ilerleme gostergesi.
- `JourneyProgressIndicator.timeline()`: Zaman cizelgesi stili ilerleme gostergesi.
- `JourneyProgressIndicator.custom()`: Bir builder fonksiyonu kullanan ozel ilerleme gostergesi.

``` dart
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
    progressStyle: JourneyProgressStyle(
        indicator: JourneyProgressIndicator.custom(
            builder: (context, currentStep, totalSteps, percentage) {
                return LinearProgressIndicator(
                    value: percentage,
                    backgroundColor: Colors.grey[200],
                    color: Colors.blue,
                    minHeight: 4.0,
                );
            },
        ),
    ),
);
```

Ilerleme gostergesi konumunu ve dolgusunu `JourneyProgressStyle` icinde ozellestirebilirsiniz:

``` dart
@override
NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.journey(
    progressStyle: JourneyProgressStyle(
        indicator: JourneyProgressIndicator.dots(),
        position: ProgressIndicatorPosition.bottom,
        padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
    ),
);
```

Asagidaki ilerleme gostergesi konumlarini kullanabilirsiniz:

- `ProgressIndicatorPosition.top`: Ekranin ustunde ilerleme gostergesi.
- `ProgressIndicatorPosition.bottom`: Ekranin altinda ilerleme gostergesi.

#### Sekme Bazinda Ilerleme Stili Gecersiz Kilma

`NavigationTab.journey(progressStyle: ...)` kullanarak layout duzeyindeki `progressStyle`'i tek tek sekmeler icin gecersiz kilabilirsiniz. Kendi `progressStyle`'i olmayan sekmeler layout varsayilanini devralir. Layout varsayilani ve sekme bazinda stil olmayan sekmeler ilerleme gostergesi gostermez.

``` dart
_MyNavigationHubState() : super(() => {
    0: NavigationTab.journey(
        page: Welcome(),
    ),
    1: NavigationTab.journey(
        page: PhoneNumberStep(),
        progressStyle: JourneyProgressStyle(
            indicator: JourneyProgressIndicator.numbered(),
        ), // yalnizca bu sekme icin duzen varsayilanini gecersiz kilar
    ),
    2: NavigationTab.journey(
        page: AddPhotosStep(),
    ),
});
```

<div id="journey-state"></div>

### JourneyState

`JourneyState` sinifi, baslangic akislari ve cok adimli yolculuklar olusturmayi kolaylastirmak icin journey'e ozel islevlerle `NyState`'i genisletir.

Yeni bir `JourneyState` olusturmak icin asagidaki komutu kullanabilirsiniz.

``` bash
metro make:journey_widget onboard_user_dob
```

Veya ayni anda birden fazla widget olusturmak istiyorsaniz, asagidaki komutu kullanabilirsiniz.

``` bash
metro make:journey_widget welcome,phone_number_step,add_photos_step
```

Olusturulan bir JourneyState widget'i su sekilde gorunur:

``` dart
import 'package:flutter/material.dart';
import '/resources/pages/navigation_hubs/onboarding/onboarding_navigation_hub.dart';
import '/resources/widgets/buttons/buttons.dart';
import 'package:nylo_framework/nylo_framework.dart';

class Welcome extends StatefulWidget {
  const Welcome({super.key});

  @override
  createState() => _WelcomeState();
}

class _WelcomeState extends JourneyState<Welcome> {
  _WelcomeState() : super(
      navigationHubState: OnboardingNavigationHub.path.stateName());

  @override
  get init => () {
    // Baslangic mantiginizi buraya yazin
  };

  @override
  Widget view(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          Expanded(
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text('Welcome', style: Theme.of(context).textTheme.headlineMedium),
                  const SizedBox(height: 20),
                  Text('This onboarding journey will help you get started.'),
                ],
              ),
            ),
          ),

          // Navigasyon dugmeleri
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              if (!isFirstStep)
                Flexible(
                  child: Button.textOnly(
                    text: "Back",
                    textColor: Colors.black87,
                    onPressed: onBackPressed,
                  ),
                )
              else
                const SizedBox.shrink(),
              Flexible(
                child: Button.primary(
                  text: "Continue",
                  onPressed: nextStep,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  /// Journey'nin bir sonraki adima devam edip edemeyecegini kontrol et
  @override
  Future<bool> canContinue() async {
    return true;
  }

  /// Bir sonraki adima gecmeden once cagrilan metot
  @override
  Future<void> onBeforeNext() async {
    // Orn. oturum verilerini kaydet
  }

  /// Journey tamamlandiginda cagrilan metot (son adimda)
  @override
  Future<void> onComplete() async {}
}
```

**JourneyState** sinifinin ileri gitmek icin `nextStep`, geri gitmek icin `onBackPressed` kullandigini fark edeceksiniz.

`nextStep` metodu tam dogrulama yasam dongusu boyunca calisir: `canContinue()` -> `onBeforeNext()` -> navigasyon (veya son adimda ise `onComplete()`) -> `onAfterNext()`.

Ayrica istege bagli navigasyon dugmeleriyle yapilandirilmis bir duzen olusturmak icin `buildJourneyContent` kullanabilirsiniz:

``` dart
@override
Widget view(BuildContext context) {
    return buildJourneyContent(
      content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('Welcome', style: Theme.of(context).textTheme.headlineMedium),
          const SizedBox(height: 20),
          Text('This onboarding journey will help you get started.'),
        ],
      ),
      nextButton: Button.primary(
        text: isLastStep ? "Get Started" : "Continue",
        onPressed: nextStep,
      ),
      backButton: isFirstStep ? null : Button.textOnly(
        text: "Back",
        textColor: Colors.black87,
        onPressed: onBackPressed,
      ),
    );
}
```

`buildJourneyContent` metodunda kullanabileceginiz ozellikler sunlardir.

| Ozellik | Tur | Aciklama |
| --- | --- | --- |
| `content` | `Widget` | Sayfanin ana icerigi. |
| `nextButton` | `Widget?` | Ileri dugmesi widget'i. |
| `backButton` | `Widget?` | Geri dugmesi widget'i. |
| `contentPadding` | `EdgeInsetsGeometry` | Icerik icin dolgu. |
| `header` | `Widget?` | Ust bilgi widget'i. |
| `footer` | `Widget?` | Alt bilgi widget'i. |
| `crossAxisAlignment` | `CrossAxisAlignment` | Icerigin capraz eksen hizalamasi. |

<div id="journey-state-helper-methods"></div>

### JourneyState Yardimci Metotlari

`JourneyState` sinifi, yolculugunuzun davranisini ozellestirmek icin kullanabileceginiz yardimci metotlara ve ozelliklere sahiptir.

| Metot / Ozellik | Aciklama |
| --- | --- |
| [`nextStep()`](#next-step) | Dogrulama ile sonraki adima gider. `Future<bool>` dondurur. |
| [`previousStep()`](#previous-step) | Onceki adima gider. `Future<bool>` dondurur. |
| [`onBackPressed()`](#on-back-pressed) | Onceki adima gitmek icin basit yardimci. |
| [`onComplete()`](#on-complete) | Yolculuk tamamlandiginda (son adimda) cagrilir. |
| [`onBeforeNext()`](#on-before-next) | Sonraki adima gecmeden once cagrilir. |
| [`onAfterNext()`](#on-after-next) | Sonraki adima gectikten sonra cagrilir. |
| [`canContinue()`](#can-continue) | Sonraki adima gecmeden once dogrulama kontrolu. |
| [`isFirstStep`](#is-first-step) | Yolculuktaki ilk adim ise true dondurur. |
| [`isLastStep`](#is-last-step) | Yolculuktaki son adim ise true dondurur. |
| [`currentStep`](#current-step) | Mevcut adim indeksini dondurur (0 tabanli). |
| [`totalSteps`](#total-steps) | Toplam adim sayisini dondurur. |
| [`completionPercentage`](#completion-percentage) | Tamamlanma yuzdesi dondurur (0.0 ile 1.0 arasi). |
| [`goToStep(int index)`](#go-to-step) | Indeksle belirli bir adima atlar. |
| [`goToNextStep()`](#go-to-next-step) | Sonraki adima atlar (dogrulama yok). |
| [`goToPreviousStep()`](#go-to-previous-step) | Onceki adima atlar (dogrulama yok). |
| [`goToFirstStep()`](#go-to-first-step) | Ilk adima atlar. |
| [`goToLastStep()`](#go-to-last-step) | Son adima atlar. |
| [`exitJourney()`](#exit-journey) | Root navigator'i kapatarak yolculuktan cikar. |
| [`resetCurrentStep()`](#reset-current-step) | Mevcut adimin durumunu sifirlar. |
| [`onJourneyComplete`](#on-journey-complete) | Yolculuk tamamlandiginda cagirilan callback (son adimda override edin). |
| [`buildJourneyPage()`](#build-journey-page) | Scaffold ile tam ekran journey sayfasi olusturur. |


<div id="next-step"></div>

#### nextStep

`nextStep` metodu tam dogrulama ile sonraki adima gider. Yasam dongusunu takip eder: `canContinue()` -> `onBeforeNext()` -> navigasyon veya `onComplete()` -> `onAfterNext()`.

Dogrulamayi atlamak icin `force: true` gecebilirsiniz.

``` dart
@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: isLastStep ? "Get Started" : "Continue",
            onPressed: nextStep, // dogrulamayı calistirir, sonra navigate eder
        ),
    );
}
```

Dogrulamayi atlamak icin:

``` dart
onPressed: () => nextStep(force: true),
```

<div id="previous-step"></div>

#### previousStep

`previousStep` metodu onceki adima gider. Basarili olursa `true`, zaten ilk adimdaysa `false` dondurur.

``` dart
onPressed: () async {
    bool success = await previousStep();
    if (!success) {
      // Zaten ilk adimda
    }
},
```

<div id="on-back-pressed"></div>

#### onBackPressed

`onBackPressed` metodu dahili olarak `previousStep()` cagiran basit bir yardimcidir.

``` dart
@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        backButton: isFirstStep ? null : Button.textOnly(
            text: "Back",
            textColor: Colors.black87,
            onPressed: onBackPressed,
        ),
    );
}
```

<div id="on-complete"></div>

#### onComplete

`onComplete` metodu, son adimda `nextStep()` tetiklendiginde (dogrulama gecildikten sonra) cagrilir.

``` dart
@override
Future<void> onComplete() async {
    print("Journey completed");
}
```

<div id="on-before-next"></div>

#### onBeforeNext

`onBeforeNext` metodu, sonraki adima gecmeden once cagrilir.

Ornegin, sonraki adima gecmeden once veri kaydetmek istiyorsaniz burada yapabilirsiniz.

``` dart
@override
Future<void> onBeforeNext() async {
    // Orn. verileri oturuma kaydet
    // session('onboarding', {
    //   'name': 'Anthony Gordon',
    //   'occupation': 'Software Engineer',
    // });
}
```

<div id="on-after-next"></div>

#### onAfterNext

`onAfterNext` metodu, sonraki adima gectikten sonra cagrilir.

``` dart
@override
Future<void> onAfterNext() async {
    // print('Bir sonraki adima gecildi');
}
```

<div id="can-continue"></div>

#### canContinue

`canContinue` metodu, `nextStep()` tetiklendiginde cagrilir. Navigasyonu engellemek icin `false` dondurun.

``` dart
@override
Future<bool> canContinue() async {
    // Dogrulama mantiginizi buraya yazin
    // Journey devam edebiliyorsa true, edemiyorsa false dondur
    if (nameController.text.isEmpty) {
        showToastSorry(description: "Please enter your name");
        return false;
    }
    return true;
}
```

<div id="is-first-step"></div>

#### isFirstStep

`isFirstStep` ozelligi, yolculuktaki ilk adim ise true dondurur.

``` dart
backButton: isFirstStep ? null : Button.textOnly(
    text: "Back",
    textColor: Colors.black87,
    onPressed: onBackPressed,
),
```

<div id="is-last-step"></div>

#### isLastStep

`isLastStep` ozelligi, yolculuktaki son adim ise true dondurur.

``` dart
nextButton: Button.primary(
    text: isLastStep ? "Get Started" : "Continue",
    onPressed: nextStep,
),
```

<div id="current-step"></div>

#### currentStep

`currentStep` ozelligi mevcut adim indeksini dondurur (0 tabanli).

``` dart
Text("Step ${currentStep + 1} of $totalSteps"),
```

<div id="total-steps"></div>

#### totalSteps

`totalSteps` ozelligi yolculuktaki toplam adim sayisini dondurur.

<div id="completion-percentage"></div>

#### completionPercentage

`completionPercentage` ozelligi tamamlanma yuzdesi olarak 0.0 ile 1.0 arasinda bir deger dondurur.

``` dart
LinearProgressIndicator(value: completionPercentage),
```

<div id="go-to-step"></div>

#### goToStep

`goToStep` metodu indeksle dogrudan belirli bir adima atlar. Bu islem dogrulama **tetiklemez**.

``` dart
nextButton: Button.primary(
    text: "Skip to photos",
    onPressed: () {
        goToStep(2); // 2. indeks adimina atla
    },
),
```

<div id="go-to-next-step"></div>

#### goToNextStep

`goToNextStep` metodu dogrulama olmadan sonraki adima atlar. Zaten son adimdaysa hicbir sey yapmaz.

``` dart
onPressed: () {
    goToNextStep(); // dogrulamayi atla ve bir sonraki adima git
},
```

<div id="go-to-previous-step"></div>

#### goToPreviousStep

`goToPreviousStep` metodu dogrulama olmadan onceki adima atlar. Zaten ilk adimdaysa hicbir sey yapmaz.

``` dart
onPressed: () {
    goToPreviousStep();
},
```

<div id="go-to-first-step"></div>

#### goToFirstStep

`goToFirstStep` metodu ilk adima atlar.

``` dart
onPressed: () {
    goToFirstStep();
},
```

<div id="go-to-last-step"></div>

#### goToLastStep

`goToLastStep` metodu son adima atlar.

``` dart
onPressed: () {
    goToLastStep();
},
```

<div id="exit-journey"></div>

#### exitJourney

`exitJourney` metodu root navigator'i kapatarak yolculuktan cikar.

``` dart
onPressed: () {
    exitJourney(); // kok navigatordan cik
},
```

<div id="reset-current-step"></div>

#### resetCurrentStep

`resetCurrentStep` metodu mevcut adimin durumunu sifirlar.

``` dart
onPressed: () {
    resetCurrentStep();
},
```

<div id="on-journey-complete"></div>

### onJourneyComplete

`onJourneyComplete` getter'i, kullanicinin akisi tamamladiginda ne olacagini tanimlamak icin yolculugunuzun **son adiminda** override edilebilir.

``` dart
class _CompleteStepState extends JourneyState<CompleteStep> {
  _CompleteStepState() : super(
      navigationHubState: OnboardingNavigationHub.path.stateName());

  /// Journey tamamlandiginda callback
  @override
  void Function()? get onJourneyComplete => () {
    // Ana sayfaniza veya bir sonraki hedefe git
    routeTo(HomePage.path);
  };

  @override
  Widget view(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          ...
          Button.primary(
            text: "Get Started",
            onPressed: onJourneyComplete, // tamamlama callback'ini tetikler
          ),
        ],
      ),
    );
  }
}
```

<div id="build-journey-page"></div>

### buildJourneyPage

`buildJourneyPage` metodu `Scaffold` ve `SafeArea` ile sarilmis tam ekran bir journey sayfasi olusturur.

``` dart
@override
Widget view(BuildContext context) {
    return buildJourneyPage(
      content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('Welcome', style: Theme.of(context).textTheme.headlineMedium),
        ],
      ),
      nextButton: Button.primary(
        text: "Continue",
        onPressed: nextStep,
      ),
      backgroundColor: Colors.white,
    );
}
```

| Ozellik | Tur | Aciklama |
| --- | --- | --- |
| `content` | `Widget` | Sayfanin ana icerigi. |
| `nextButton` | `Widget?` | Ileri dugmesi widget'i. |
| `backButton` | `Widget?` | Geri dugmesi widget'i. |
| `contentPadding` | `EdgeInsetsGeometry` | Icerik icin dolgu. |
| `header` | `Widget?` | Ust bilgi widget'i. |
| `footer` | `Widget?` | Alt bilgi widget'i. |
| `backgroundColor` | `Color?` | Scaffold'un arka plan rengi. |
| `appBar` | `Widget?` | Istege bagli bir AppBar widget'i. |
| `crossAxisAlignment` | `CrossAxisAlignment` | Icerigin capraz eksen hizalamasi. |

<div id="navigating-within-a-tab"></div>

## Sekme Icindeki Widget'lara Gezinme

`pushTo` yardimcisini kullanarak bir sekme icindeki widget'lara gezinebilirsiniz.

Sekmenizin icinde, baska bir widget'a gitmek icin `pushTo` yardimcisini kullanabilirsiniz.

``` dart
_HomeTabState extends State<HomeTab> {
    ...
    void _navigateToSettings() {
        pushTo(SettingsPage());
    }
    ...
}
```

Gezindiginiz widget'a veri de gecebilirsiniz.

``` dart
_HomeTabState extends State<HomeTab> {
    ...
    void _navigateToSettings() {
        pushTo(SettingsPage(), data: {"name": "Anthony"});
    }
    ...
}
```

Bir sekme icindeki ic icegecmis navigatordan cikis yaparken, sekmenin yerel navigatoru yerine kok navigatordan cikmak icin `rootNavigator: true` kullanin:

``` dart
// Sekmenin yerel navigatorundan cik (varsayilan)
pop();

// Kok navigatordan cik - bir modal veya katman
// kok navigator kullanilarak gonderildiginde bunu kullanin
pop(rootNavigator: true);
```

`rootNavigator` parametresi `NyState`, `NyController`, `StateAction.pop()` ve `BuildContext` uzantisindaki `pop()` metodunda kullanilabilir.

<div id="tabs"></div>

## Sekmeler

Sekmeler, Navigation Hub'in ana yapi taslaridir.

`NavigationTab` sinifini ve adlandirilmis constructor'larini kullanarak Navigation Hub'a sekmeler ekleyebilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
    ...
    _MyNavigationHubState() : super(() => {
        0: NavigationTab.tab(
            title: "Home",
            page: HomeTab(),
            icon: Icon(Icons.home),
            activeIcon: Icon(Icons.home),
        ),
        1: NavigationTab.tab(
            title: "Settings",
            page: SettingsTab(),
            icon: Icon(Icons.settings),
            activeIcon: Icon(Icons.settings),
        ),
    });
```

Yukaridaki ornekte, Navigation Hub'a Home ve Settings olmak uzere iki sekme ekledik.

Farkli sekme turlerini kullanabilirsiniz:

- `NavigationTab.tab()` - Standart navigasyon sekmesi.
- `NavigationTab.badge()` - Rozet sayili sekme.
- `NavigationTab.alert()` - Uyari gostergeli sekme.
- `NavigationTab.journey()` - Journey navigasyon duzenleri icin sekme.

<div id="adding-badges-to-tabs"></div>

## Sekmelere Rozet Ekleme

Sekmelerinize rozet eklemeyi kolaylastirdik.

Rozetler, kullanicilara bir sekmede yeni bir sey oldugunu gostermenin harika bir yoludur.

Ornegin, bir sohbet uygulamaniz varsa, sohbet sekmesinde okunmamis mesaj sayisini gosterebilirsiniz.

Bir sekmeye rozet eklemek icin `NavigationTab.badge` constructor'ini kullanabilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
    ...
    _MyNavigationHubState() : super(() => {
        0: NavigationTab.badge(
            title: "Chats",
            page: ChatTab(),
            icon: Icon(Icons.message),
            activeIcon: Icon(Icons.message),
            initialCount: 10,
        ),
        1: NavigationTab.tab(
            title: "Settings",
            page: SettingsTab(),
            icon: Icon(Icons.settings),
            activeIcon: Icon(Icons.settings),
        ),
    });
```

Yukaridaki ornekte, Chat sekmesine baslangic sayisi 10 olan bir rozet ekledik.

Rozet sayisini programatik olarak da guncelleyebilirsiniz.

``` dart
/// Rozet sayisini artir
BaseNavigationHub.stateActions.incrementBadgeCount(tab: 0);

/// Rozet sayisini guncelle
BaseNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 5);

/// Rozet sayisini temizle
BaseNavigationHub.stateActions.clearBadgeCount(tab: 0);
```

Varsayilan olarak rozet sayisi hatirlanir. Her oturumda rozet sayisini **temizlemek** istiyorsaniz, `rememberCount`'u `false` olarak ayarlayabilirsiniz.

``` dart
0: NavigationTab.badge(
    title: "Chats",
    page: ChatTab(),
    icon: Icon(Icons.message),
    activeIcon: Icon(Icons.message),
    initialCount: 10,
    rememberCount: false,
),
```

<div id="adding-alerts-to-tabs"></div>

## Sekmelere Uyari Ekleme

Sekmelerinize uyari ekleyebilirsiniz.

Bazen rozet sayisi gostermek istemeyebilirsiniz, ancak kullaniciya bir uyari gostergesi gostermek isteyebilirsiniz.

Bir sekmeye uyari eklemek icin `NavigationTab.alert` constructor'ini kullanabilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    NavigationHubLayout? layout(BuildContext context) => NavigationHubLayout.bottomNav();
    ...
    _MyNavigationHubState() : super(() => {
        0: NavigationTab.alert(
            title: "Chats",
            page: ChatTab(),
            icon: Icon(Icons.message),
            activeIcon: Icon(Icons.message),
            alertColor: Colors.red,
            alertEnabled: true,
            rememberAlert: false,
        ),
        1: NavigationTab.tab(
            title: "Settings",
            page: SettingsTab(),
            icon: Icon(Icons.settings),
            activeIcon: Icon(Icons.settings),
        ),
    });
```

Bu, Chat sekmesine kirmizi renkte bir uyari ekleyecektir.

Uyariyi programatik olarak da guncelleyebilirsiniz.

``` dart
/// Uyariyi etkinlestir
BaseNavigationHub.stateActions.alertEnableTab(tab: 0);

/// Uyariyi devre disi birak
BaseNavigationHub.stateActions.alertDisableTab(tab: 0);
```

<div id="initial-index"></div>

## Baslangic Indeksi

Varsayilan olarak, Navigation Hub ilk sekmede (indeks 0) baslar. Bunu `initialIndex` getter'ini override ederek degistirebilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    int get initialIndex => 1; // Ikinci sekmeden basla
    ...
}
```

<div id="maintaining-state"></div>

## Durumu Koruma

Varsayilan olarak, Navigation Hub'in durumu korunur.

Bu, bir sekmeye gittiginizde sekmenin durumunun saklanacagi anlamina gelir.

Her gittiginizde sekmenin durumunu temizlemek istiyorsaniz, `maintainState`'i `false` olarak ayarlayabilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    bool get maintainState => false;
    ...
}
```

<div id="on-tap"></div>

## onTap

Bir sekmeye dokunuldugunda ozel mantik eklemek icin `onTap` metodunu override edebilirsiniz.

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    @override
    onTap(int index) {
        // Ozel mantiginizi buraya ekleyin
        // Orn. analitik takibi, onay gosterme vb.
        super.onTap(index); // Sekme gecisini islemek icin her zaman super'i cagirin
    }
}
```

<div id="state-actions"></div>

## Durum Eylemleri

Durum eylemleri, uygulamanizin herhangi bir yerinden Navigation Hub ile etkilesim kurmanin bir yoludur.

Kullanabileceginiz durum eylemleri sunlardir:

``` dart
/// Belirli bir indeksteki sekmeyi sifirla
/// Orn. MyNavigationHub.stateActions.resetTabIndex(0);
resetTabIndex(int tabIndex);

/// Mevcut sekmeyi programatik olarak degistir
/// Orn. MyNavigationHub.stateActions.currentTabIndex(2);
currentTabIndex(int tabIndex);

/// Rozet sayisini guncelle
/// Orn. MyNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 2);
updateBadgeCount({required int tab, required int count});

/// Rozet sayisini artir
/// Orn. MyNavigationHub.stateActions.incrementBadgeCount(tab: 0);
incrementBadgeCount({required int tab});

/// Rozet sayisini temizle
/// Orn. MyNavigationHub.stateActions.clearBadgeCount(tab: 0);
clearBadgeCount({required int tab});

/// Bir sekme icin uyariyi etkinlestir
/// Orn. MyNavigationHub.stateActions.alertEnableTab(tab: 0);
alertEnableTab({required int tab});

/// Bir sekme icin uyariyi devre disi birak
/// Orn. MyNavigationHub.stateActions.alertDisableTab(tab: 0);
alertDisableTab({required int tab});

/// Journey duzeninde bir sonraki sayfaya git
/// Orn. await MyNavigationHub.stateActions.nextPage();
Future<bool> nextPage();

/// Journey duzeninde bir onceki sayfaya git
/// Orn. await MyNavigationHub.stateActions.previousPage();
Future<bool> previousPage();

/// Belirli bir sekmeyi yenile, yeniden olusturmayi zorla
/// Orn. MyNavigationHub.stateActions.refreshTab(0);
void refreshTab(int tabIndex);

/// Tum sekmeleri yenile, yeniden olusturmayi zorla
/// Orn. MyNavigationHub.stateActions.refresh();
void refresh();
```

Bir durum eylemi kullanmak icin asagidakileri yapabilirsiniz:

``` dart
MyNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 2);

MyNavigationHub.stateActions.resetTabIndex(0);

MyNavigationHub.stateActions.currentTabIndex(2); // 2. sekmeye gec

await MyNavigationHub.stateActions.nextPage(); // Journey: bir sonraki sayfaya git

MyNavigationHub.stateActions.refreshTab(0); // 0. sekmeyi yeniden olusturmaya zorla

MyNavigationHub.stateActions.refresh(); // Tum sekmeleri yeniden olusturmaya zorla
```

<div id="loading-style"></div>

## Yukleme Stili

Kutudan ciktigi haliyle, Navigation Hub sekme yuklenirken **varsayilan** yukleme Widget'inizi (resources/widgets/loader_widget.dart) gosterecektir.

Yukleme stilini guncellemek icin `loadingStyle`'i ozellestirebilirsiniz.

| Stil | Aciklama |
| --- | --- |
| normal | Varsayilan yukleme stili |
| skeletonizer | Iskelet yukleme stili |
| none | Yukleme stili yok |

Yukleme stilini su sekilde degistirebilirsiniz:

``` dart
@override
LoadingStyle get loadingStyle => LoadingStyle.normal();
// or
@override
LoadingStyle get loadingStyle => LoadingStyle.skeletonizer();
```

Stillerden birindeki yukleme Widget'ini guncellemek istiyorsaniz, `LoadingStyle`'a bir `child` gecebilirsiniz.

``` dart
@override
LoadingStyle get loadingStyle => LoadingStyle.normal(
    child: Center(
        child: Text("Loading..."),
    ),
);
```

Simdi, sekme yuklenirken "Loading..." metni goruntulecektir.

Asagida ornek:

``` dart
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ...
    _MyNavigationHubState() : super(() async {

      await sleep(3); // 3 saniye yuklemeyi simule et

      return {
        0: NavigationTab.tab(
          title: "Home",
          page: HomeTab(),
        ),
        1: NavigationTab.tab(
          title: "Settings",
          page: SettingsTab(),
        ),
      };
    });

    @override
    LoadingStyle get loadingStyle => LoadingStyle.normal(
        child: Center(
            child: Text("Loading..."),
        ),
    );
    ...
}
```

<div id="creating-a-navigation-hub"></div>

## Navigation Hub Olusturma

Bir Navigation Hub olusturmak icin [Metro](/docs/7.x/metro) kullanabilirsiniz, asagidaki komutu calistirin.

``` bash
metro make:navigation_hub base
```

Komut, duzen turunu secebileceginiz ve sekmelerinizi veya journey durumlarinizi tanimlayabileceginiz interaktif bir kurulum surecinde size rehberlik edecektir.

Bu, `resources/pages/navigation_hubs/base/` dizininizde alt widget'larin `tabs/` veya `states/` alt klasorlerinde duzenlendirilmis bir `base_navigation_hub.dart` dosyasi olusturacaktir.
