flutter ディレクトリ構成

https://github.com/mono0926/wdb106-flutter

```
.
├── analysis_options.yaml // lint
├── lib
│   ├── app.dart
│   ├── main.dart // ProviderScopeでラップ
│   ├── model
│   │   ├── api.dart
│   │   ├── controllers
│   │   │   ├── xxx_controller
│   │   │   │   ├── xxx_controller.dart
│   │   │   │   │   // StateNotifierとProviderを定義(controllers.dartで一括exportのためstateのexport)
│   │   │   │   │   // stateの変更系メソッド定義
│   │   │   │   ├── xxx_state.dart
│   │   │   │   │   // controllerにセットするstateを定義
│   │   │   │   │   // 表示に使用するフィールド定義(ソート済リストやフォーマット文字列など('合計${xxx.total}'))
│   │   │   │   └── xxx_state.freezed.dart
│   │   │   └── controllers.dart // controllers配下のcontrollerをexport
│   │   ├── entities // APIやDBなど外部リソースから取得したJSONデータなどをマッピングさせるオブジェクト
│   │   │   ├── xxx
│   │   │   │   ├── xxx.dart // ※1
│   │   │   │   └── xxx.freezed.dart
│   │   │   └── entities.dart // 各entityをexport(他のentityのimportが../entities.dartでできる)
│   │   └── model.dart // entities.dart, controllers.dartをexport
│   ├── pages // 画面単位で分割
│   │   └── xxx_page
│   │       ├── xxx_button.dart
│   │       ├── xxx_page.dart
│   │       └── tile
│   │           ├── xxx_tile.dart
│   │           ├── xxx_tile_controller.dart
│   │           │   // local使用のStateNotifier, xxx_tileのみで使用するのでProviderで外部公開しない
│   │           ├── xxx_tile_state.dart // local使用のstate
│   │           └── xxx_tile_state.freezed.dart
│   ├── providers
│   │   ├── navigator.dart // ※2
│   │   └── providers.dart // navigator.dartをexport
│   ├── util
│   │   └── logger.dart
│   └── widgets // 共通widget
│       ├── xxx_image.dart
│       ├── xxx_info.dart
│       ├── navigation_bar_button.dart
│       └── widgets.dart // 'package:flutter/material.dart'と各widgetsをexport
└── test
    ├── helper
    │   └── dummy_xxx.dart // モックデータ
    ├── model
    │   ├── api_test.dart
    │   ├── controllers
    │   │   └── xxx_controller_test.dart
    │   └── entities
    │       └── xxx.dart
    ├── pages
    │   └── xxx_page
    │       └── xxx_tile_controller_test.dart
    └── smoke_test.dart
```

※1

- fromJsonコンストラクタでjson => オブジェクト生成


https://pub.dev/packages/freezed/versions/0.12.7#fromjson---classes-with-multiple-constructors

```dart
@freezed
abstract class xxx with _$xxx {
  factory xxx({
    required int id,
    required int price,
    required String title,
    required String imageUrl,
  }) = _xxx;
  xxx._(); // private constructor https://stackoverflow.com/questions/55143244/is-it-possible-to-have-a-private-constructor-in-dart

  factory xxx.fromJson(Map<String, dynamic> json) => _$xxxFromJson(json);
}
```

※2

```dart
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final navigatorKeyProvider = Provider((_) => GlobalKey<NavigatorState>());

extension NavigatorStateEx on NavigatorState {
  BuildContext get descendantContext => overlay!.context;
}
```

- navigatorKeyProviderをMaterialAppのnavigatorkeyに差し込むことでどこでも画面遷移可能になる

```dart
class MyApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
        final navigatorKey = watch(navigatorKeyProvider);
        
        // return widgets
        onTap: () {
            navigatorKey.currentState.pushNamed("foo");
        }
```

https://twitter.com/_mono/status/1286061012353814528

- NavigatorStateEx
    - Navigator.of()でNavigatorStateを取れるcontext得るために、NavigatorStateのoverlay.contextを渡すために使用

```dart
navigatorKey.currentState.descendantContext; // get BuildContext
```

https://twitter.com/Krgm4D/status/1261832450042257410

https://twitter.com/_mono/status/1121245809444438016

monoさんありがとうございます！！！