// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Template: dev/snippets/config/templates/freeform.tmpl
//
// Comment lines marked with "▼▼▼" and "▲▲▲" are used for authoring
// of samples, and may be ignored if you are just exploring the sample.

// Flutter code sample for RestorableRouteFuture
//
//***************************************************************************
//* ▼▼▼▼▼▼▼▼ description ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)

// This example uses a [RestorableRouteFuture] in the `_MyHomeState` to push a
// new `MyCounter` route and to retrieve its return value.

//* ▲▲▲▲▲▲▲▲ description ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//***************************************************************************

//****************************************************************************
//* ▼▼▼▼▼▼▼▼ code-imports ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)

import 'package:flutter/material.dart';

//* ▲▲▲▲▲▲▲▲ code-imports ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//****************************************************************************

//*************************************************************************
//* ▼▼▼▼▼▼▼▼ code-main ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)

void main() => runApp(const MyApp());

//* ▲▲▲▲▲▲▲▲ code-main ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//*************************************************************************

//*****************************************************************************
//* ▼▼▼▼▼▼▼▼ code-preamble ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      restorationScopeId: 'app',
      home: Scaffold(
        appBar: AppBar(title: const Text('RestorableRouteFuture Example')),
        body: const MyHome(),
      ),
    );
  }
}

//* ▲▲▲▲▲▲▲▲ code-preamble ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//*****************************************************************************

//********************************************************************
//* ▼▼▼▼▼▼▼▼ code ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)

class MyHome extends StatefulWidget {
  const MyHome({Key? key}) : super(key: key);

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> with RestorationMixin {
  final RestorableInt _lastCount = RestorableInt(0);
  late RestorableRouteFuture<int> _counterRoute;

  @override
  String get restorationId => 'home';

  @override
  void initState() {
    super.initState();
    _counterRoute = RestorableRouteFuture<int>(
        onPresent: (NavigatorState navigator, Object? arguments) {
      // Defines what route should be shown (and how it should be added
      // to the navigator) when `RestorableRouteFuture.present` is called.
      return navigator.restorablePush(
        _counterRouteBuilder,
        arguments: arguments,
      );
    }, onComplete: (int count) {
      // Defines what should happen with the return value when the route
      // completes.
      setState(() {
        _lastCount.value = count;
      });
    });
  }

  @override
  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
    // Register the `RestorableRouteFuture` with the state restoration framework.
    registerForRestoration(_counterRoute, 'route');
    registerForRestoration(_lastCount, 'count');
  }

  @override
  void dispose() {
    super.dispose();
    _lastCount.dispose();
    _counterRoute.dispose();
  }

  // A static `RestorableRouteBuilder` that can re-create the route during
  // state restoration.
  static Route<int> _counterRouteBuilder(
      BuildContext context, Object? arguments) {
    return MaterialPageRoute<int>(
      builder: (BuildContext context) => MyCounter(
        title: arguments!.toString(),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text('Last count: ${_lastCount.value}'),
          ElevatedButton(
            onPressed: () {
              // Show the route defined by the `RestorableRouteFuture`.
              _counterRoute.present('Awesome Counter');
            },
            child: const Text('Open Counter'),
          ),
        ],
      ),
    );
  }
}

// Widget for the route pushed by the `RestorableRouteFuture`.
class MyCounter extends StatefulWidget {
  const MyCounter({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyCounter> createState() => _MyCounterState();
}

class _MyCounterState extends State<MyCounter> with RestorationMixin {
  final RestorableInt _count = RestorableInt(0);

  @override
  String get restorationId => 'counter';

  @override
  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
    registerForRestoration(_count, 'count');
  }

  @override
  void dispose() {
    super.dispose();
    _count.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        leading: BackButton(
          onPressed: () {
            // Return the current count of the counter from this route.
            Navigator.of(context).pop(_count.value);
          },
        ),
      ),
      body: Center(
        child: Text('Count: ${_count.value}'),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          setState(() {
            _count.value++;
          });
        },
      ),
    );
  }
}

//* ▲▲▲▲▲▲▲▲ code ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//********************************************************************
