バス機能をReducer + Freezed State + Repositoryパターンにリファクタリング#513
Conversation
ドメインモデルをimmutableなfreezedクラスに移行し、 copyWithや等値比較を自動生成できるようにする。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
シングルトンを廃止し、WidgetRef依存を除去することで 他のRepositoryと統一されたパターンに揃える。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
個別のUI状態コントローラーを1つのfreezed Stateと Reducerに集約し、状態管理を一元化する。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BusScreenをHookConsumerWidgetに変更し、BusCardは パラメータでデータを受け取る形にしてprovider依存を除去する。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BusReducerへの移行が完了したため、不要になった 7つの個別コントローラーとfeature内リポジトリを削除する。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
動作確認済み |
There was a problem hiding this comment.
Pull request overview
バス機能の状態管理・ドメインモデル・データ取得層を整理し、Reducer + Freezed State + Repository パターンへ移行するためのリファクタリングです。
Changes:
- バス関連ドメイン(BusStop/BusTrip/BusTripStop)を
@freezed化し、lib/domain配下へ移動 - 既存の複数Riverpodコントローラを
BusReducer+BusStateに統合し、画面側はbusReducerProvider経由に集約 - BusRepository を abstract + Impl に再構成し、
lib/repository/に移設・Provider登録
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/repository/repository_provider.dart | BusRepository の Provider を追加 |
| lib/repository/bus_repository.dart | バスデータ取得の Repository 抽象/実装を追加 |
| lib/feature/root/root_screen.dart | Bus画面 import を新しい bus_screen.dart に更新 |
| lib/feature/bus/widget/bus_card_home.dart | 旧ホーム用バスカード(旧Provider依存)を削除 |
| lib/feature/bus/repository/bus_repository.dart | 旧シングルトンRepositoryを削除 |
| lib/feature/bus/domain/bus_stop.dart | 旧feature配下のBusStopモデルを削除(domainへ移動) |
| lib/feature/bus/controller/my_bus_stop_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/controller/bus_stops_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/controller/bus_polling_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/controller/bus_is_weekday_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/controller/bus_is_to_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/controller/bus_is_scrolled_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/controller/bus_data_controller.dart | 旧コントローラ削除(Reducerへ統合) |
| lib/feature/bus/bus.dart | 旧BusScreen実装を削除(bus_screen.dart へ) |
| lib/feature/bus/bus_timetable.dart | 新domainモデル/format関数参照へ更新 |
| lib/feature/bus/bus_stop_select.dart | busReducerProvider 経由でバス停選択に更新 |
| lib/feature/bus/bus_state.dart | Freezed の BusState を追加 |
| lib/feature/bus/bus_screen.dart | HookConsumerWidget ベースの新Bus画面を追加 |
| lib/feature/bus/bus_reducer.dart | BusReducer(AsyncNotifier + polling + actions)を追加 |
| lib/feature/bus/bus_card.dart | Provider依存を一部削減しつつ、Reducer操作へ接続 |
| lib/domain/bus_type.dart | BusType を domain に追加 |
| lib/domain/bus_trip.dart | BusTrip/BusTripStop を Freezed 化して domain へ移行 |
| lib/domain/bus_stop.dart | BusStop を Freezed 化して domain へ移行 |
Comments suppressed due to low confidence (2)
lib/feature/bus/bus_timetable.dart:2
- 時刻フォーマットのためだけに
bus_reducer.dartに依存しており、UI層がReducer/Provider定義へ引きずられる構造になっています。formatDurationは純粋関数なので、busのutil(例:bus_utils.dart)等に移してUI側はそれだけをimportする方が依存関係が明確になります。
lib/feature/bus/bus_card.dart:69 - PR説明では「BusCardからprovider依存を除去」とありますが、この箇所で
busReducerProviderを直接readしておりWidgetが状態変更を握っています。onSwapPressedのようなコールバックをBusCardの引数で受け取り、親(BusScreen等)側でtoggleDirection()を呼ぶ形にすると、BusCardをプレゼンテーショナルに保てます。
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (savedId != null) { | ||
| final found = allStops.where((s) => s.id == savedId); | ||
| if (found.isNotEmpty) return found.first; | ||
| } |
There was a problem hiding this comment.
保存済みのバス停IDが無い/見つからない場合に _defaultBusStop をそのまま返しており、Firebaseから取得した allStops 側の最新情報(名称・routeList・selectable等)と不整合になる可能性があります。旧実装は常にFirebaseの stop(id=14013) を採用していたので、フォールバック時も allStops から該当IDを検索して返し、見つからない場合のみ _defaultBusStop に落とす形にすると安全です。
| } | |
| } | |
| final defaultFound = allStops.where((s) => s.id == _defaultBusStop.id); | |
| if (defaultFound.isNotEmpty) return defaultFound.first; |
| WidgetsBinding.instance.addPostFrameCallback((_) { | ||
| if (state.isScrolled) return; | ||
| final currentContext = busKey.currentContext; | ||
| if (currentContext == null) return; | ||
| final box = currentContext.findRenderObject()! as RenderBox; |
There was a problem hiding this comment.
addPostFrameCallback を build 内で毎回登録しているため、currentTime 更新などでリビルドが発生するたびにコールバックが積まれます(isScrolled で早期returnはするものの登録自体は行われます)。スクロール処理は useEffect 等で isScrolled / tripWidgets 変更時のみ1回登録する形にすると不要なフレーム処理を避けられます。
Generated by 🚫 Danger |
やったこと
BusStop,BusTripStop,BusTrip)を@freezedクラスに変換BusRepositoryをシングルトンからabstract + Implパターンに変更し、lib/repository/に移動BusReducer+BusState(freezed)に統合BusReducer経由のデータ取得に移行(BusScreenをHookConsumerWidget化)BusCardからprovider依存を除去し、パラメータでデータを受け取る形に変更確認したこと
task buildでコード生成が正常に完了することtask formatでフォーマットが通ることtask analyzeでバス関連ファイルにエラー・警告がないことUI 差分
UI変更なし(内部リファクタリングのみ)
メモ
BusRepository.changeDirectionOnCurrentLocationは未使用だったため削除formatDurationはトップレベル関数としてbus_reducer.dartに配置