# 画面設計書 25-位置情報選択画面

## 概要

本ドキュメントは、Bagisto eコマースモバイルアプリにおける位置情報選択画面の設計仕様を記述したものです。Googleマップを使用して住所を視覚的に選択する機能を提供し、住所追加・編集画面との連携を実現します。

### 本画面の処理概要

本画面は、Googleマップを表示して位置情報から住所を取得するための画面です。現在地取得、地図上でのピン移動、住所検索機能を提供し、選択した位置の住所データを呼び出し元画面に返却します。

**業務上の目的・背景**：住所入力は配送先設定における重要なプロセスですが、手動入力は面倒でエラーが発生しやすいです。位置情報を活用することで、ユーザーは地図上で直感的に配送先を選択でき、正確な住所データを取得することができます。これにより、配送エラーの削減とユーザー体験の向上が実現されます。

**画面へのアクセス方法**：住所追加・編集画面のAppBarにある位置情報ボタンをタップすることでアクセスします。

**主要な操作・処理内容**：
1. 画面初期化時に現在地または指定された住所の位置を取得する
2. Googleマップを表示し、中央にピンアイコンを配置する
3. 地図を移動するとカメラ位置に応じて住所を逆ジオコーディングで取得する
4. 現在地ボタンで現在位置に移動する
5. 検索バーから住所検索画面へ遷移し、検索結果の位置に移動する
6. 画面下部の住所エリアをタップして住所データを返却する

**画面遷移**：住所追加・編集画面から本画面に遷移します。住所検索画面（PlaceSearch）へ遷移可能です。住所選択完了時は住所データをMap形式で返却して前画面に戻ります。

**権限による表示制御**：位置情報の権限が必要です。権限がない場合は権限リクエストが行われます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 73 | 位置情報取得 | 主機能 | Googleマップを使用した住所選択、現在地取得機能 |

## 画面種別

選択

## URL/ルーティング

Navigator.pushによる直接遷移（ルート名なし）

## 入出力項目

### 入力パラメータ

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|------|------|------|
| address | 入力 | String | 任意 | 初期表示する住所（ジオコーディングで位置取得） |

### 出力データ

| 項目名 | 入出力 | 型 | 説明 |
|--------|--------|------|------|
| street1 | 出力 | String | 通り名（street） |
| street2 | 出力 | String | 詳細住所（thoroughfare） |
| street3 | 出力 | String | 地区（subLocality） |
| city | 出力 | String | 市区町村（locality） |
| state | 出力 | String | 都道府県/州（administrativeArea） |
| zip | 出力 | String | 郵便番号（postalCode） |
| country | 出力 | String | 国名（country） |
| countryCode | 出力 | String | 国コード（isoCountryCode） |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| Googleマップ | GoogleMap | 全画面表示のマップウィジェット |
| 中央ピン | Icon | 地図中央に固定表示される赤いピンアイコン |
| 検索バー | Container | 住所検索画面への遷移トリガー |
| 戻るボタン | Icon | 左上の戻るアイコン |
| 現在地ボタン | CircleAvatar | 右下の現在地取得ボタン |
| 住所表示エリア | Container | 画面下部の選択住所表示エリア |
| 住所テキスト | Text | 逆ジオコーディングで取得した住所文字列 |

## イベント仕様

### 1-画面初期化イベント

画面初期化時（initState）に現在地または指定住所の位置情報を取得します。

処理フロー：
1. widget.addressが指定されている場合、address変数に設定
2. getCurrentLocation()を呼び出し
3. 住所が指定されている場合：locationFromAddress()でジオコーディング
4. 住所が指定されていないまたは失敗時：currentLocation.getLocation()で現在地取得
5. latitude、longitudeを設定
6. setStateでUIを更新

### 2-地図カメラ移動イベント

地図をドラッグしてカメラを移動した際の処理です。

処理フロー：
1. onCameraMoveコールバックでpositionを更新
2. onCameraIdleコールバックで移動完了を検知
3. getLocation(position)を呼び出して逆ジオコーディング
4. address変数を空文字にリセット

### 3-逆ジオコーディングイベント

地図の中央位置から住所を取得する処理です。

処理フロー：
1. placemarkFromCoordinates()で緯度・経度から住所情報を取得
2. Placemarkの各フィールドを確認
3. addressMapに各フィールドを設定（street, city, state, zip, country, countryCode）
4. address文字列を構築（カンマ区切り）
5. setStateでUIを更新

### 4-現在地取得イベント

現在地ボタン押下時の処理です。

処理フロー：
1. getCurrentLocation()を呼び出し
2. currentLocation.getLocation()で現在地を取得
3. latitude、longitudeを更新
4. _controller.animateCameraでマップを現在地に移動
5. position変数を更新

### 5-住所検索イベント

検索バータップ時の処理です。

処理フロー：
1. Navigator.pushでPlaceSearch画面へ遷移
2. 戻り値としてLatLngを受け取る
3. placeSearch(value)を呼び出し
4. latitude、longitude、positionを更新
5. _controller.animateCameraでマップを検索位置に移動
6. getLocation(location)で逆ジオコーディング

### 6-住所選択完了イベント

画面下部の住所エリアタップ時の処理です。

処理フロー：
1. Navigator.pop(context, addressMap)で住所データを返却
2. 呼び出し元画面で住所データをフォームに設定

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| - | - | - | 本画面ではデータベース操作は行わない |

本画面は位置情報の選択と住所データの取得のみを行い、データベースへの直接的な操作は行いません。取得した住所データは呼び出し元画面に返却され、そこで保存処理が行われます。

## メッセージ仕様

| メッセージ種別 | メッセージキー | 表示内容 | 表示条件 |
|--------------|--------------|---------|---------|
| プレースホルダー | StringConstants.searchLocation | 場所を検索 | 検索バー |
| ラベル | StringConstants.selectLocation | 場所を選択 | 住所エリアヘッダー |
| 処理中 | StringConstants.pleaseWait | お待ちください | 住所取得中 |

## 例外処理

| 例外状況 | 処理内容 | ユーザーへの表示 |
|---------|---------|----------------|
| 位置情報権限なし | 権限リクエストダイアログを表示 | システムダイアログ |
| 現在地取得失敗 | Navigator.pop(context)で前画面に戻る | 自動で戻る |
| ジオコーディング失敗 | デフォルト位置（インド・デリー近郊）を使用 | デフォルト位置を表示 |
| 逆ジオコーディング失敗 | 住所文字列が空のまま | 「お待ちください」表示継続 |

## 備考

- Google Maps SDKを使用（google_maps_flutter パッケージ）
- geocodingパッケージで住所⇔座標変換
- locationパッケージで現在地取得
- デフォルト位置は緯度28.6296987、経度77.3762753（インド・デリー近郊）
- ズームレベルは16.0で固定
- ピンアイコンは地図中央に固定表示され、地図移動で位置が変わる
- LocationScreenBlocはPlaceSearch画面でのみ使用
- 住所データはMap<String, dynamic>形式で返却

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、位置情報と住所データの構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | location_screen.dart | `lib/screens/location/view/location_screen.dart` | addressMapの構造を確認（35行目） |

**読解のコツ**: addressMapはMap<String, dynamic>で、street1, street2, street3, city, state, zip, country, countryCodeのキーを持ちます。geocodingパッケージのPlacemarkクラスの各フィールドに対応しています。

#### Step 2: エントリーポイントを理解する

処理の起点となるファイル・関数を特定します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | location_screen.dart | `lib/screens/location/view/location_screen.dart` | LocationScreenクラスがエントリーポイント |

**主要処理フロー**:
1. **40-48行目**: initStateでaddress設定、getCurrentLocation()呼び出し
2. **55-214行目**: _buildUIでGoogleマップと各UIコンポーネントを構築
3. **63-85行目**: GoogleMapウィジェットの設定（onCameraMove, onCameraIdle）
4. **216-243行目**: getCurrentLocationで現在地取得
5. **245-257行目**: placeSearchで検索結果の位置に移動
6. **259-298行目**: getLocationで逆ジオコーディング

#### Step 3: 住所検索画面を理解する

PlaceSearch画面の処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | place_search.dart | `lib/screens/location/view/place_search.dart` | 住所検索とLatLng返却の処理 |
| 3-2 | location_bloc.dart | `lib/screens/location/bloc/location_bloc.dart` | 検索イベントの処理 |
| 3-3 | location_repo.dart | `lib/screens/location/bloc/location_repo.dart` | Place API呼び出し |

#### Step 4: Bloc層を理解する

PlaceSearch画面で使用されるBloc層を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | location_bloc.dart | `lib/screens/location/bloc/location_bloc.dart` | SearchPlaceEventの処理 |
| 4-2 | location_event.dart | `lib/screens/location/bloc/location_event.dart` | イベント定義 |
| 4-3 | location_state.dart | `lib/screens/location/bloc/location_state.dart` | ステート定義 |

### プログラム呼び出し階層図

```
LocationScreen (location_screen.dart)
    │
    ├─ initState()
    │      ├─ address設定（widget.addressから）
    │      └─ getCurrentLocation()
    │             ├─ locationFromAddress() (住所指定時)
    │             └─ currentLocation.getLocation() (現在地取得)
    │
    ├─ _buildUI()
    │      ├─ GoogleMap
    │      │      ├─ onCameraMove → position更新
    │      │      └─ onCameraIdle → getLocation()
    │      │
    │      ├─ 戻るボタン → Navigator.pop()
    │      │
    │      ├─ 検索バー → PlaceSearch画面へ遷移
    │      │      └─ 戻り値(LatLng) → placeSearch()
    │      │
    │      ├─ 現在地ボタン → getCurrentLocation()
    │      │
    │      └─ 住所エリア → Navigator.pop(context, addressMap)
    │
    ├─ getCurrentLocation()
    │      └─ _controller.animateCamera()
    │
    ├─ placeSearch(LatLng)
    │      ├─ latitude/longitude更新
    │      ├─ _controller.animateCamera()
    │      └─ getLocation()
    │
    └─ getLocation(LatLng)
           └─ placemarkFromCoordinates()
                  └─ addressMap構築
```

### データフロー図

```
[入力]                      [処理]                              [出力]

widget.address        ───▶ initState()                      ───▶ 地図初期位置
(初期住所)                      │
                               ▼
                    locationFromAddress() または
                    currentLocation.getLocation()
                               │
                               ▼
                    latitude/longitude取得              ───▶ GoogleMap表示

地図ドラッグ          ───▶ onCameraMove                    ───▶ position更新
                               │
                               ▼
                         onCameraIdle
                               │
                               ▼
                         getLocation()
                               │
                               ▼
                    placemarkFromCoordinates()
                               │
                               ▼
                    Placemark                            ───▶ addressMap構築
                     ├─ street                                  │
                     ├─ thoroughfare                            ▼
                     ├─ subLocality                       address文字列表示
                     ├─ locality
                     ├─ administrativeArea
                     ├─ postalCode
                     ├─ country
                     └─ isoCountryCode

住所エリアタップ      ───▶ Navigator.pop(addressMap)        ───▶ 呼び出し元に返却
                                                                 │
                                                                 ▼
                                                          住所フォームに設定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| location_screen.dart | `lib/screens/location/view/location_screen.dart` | ソース | 画面本体のStatefulWidget |
| place_search.dart | `lib/screens/location/view/place_search.dart` | ソース | 住所検索画面 |
| location_bloc.dart | `lib/screens/location/bloc/location_bloc.dart` | ソース | 状態管理Bloc（PlaceSearch用） |
| location_event.dart | `lib/screens/location/bloc/location_event.dart` | ソース | Blocイベント定義 |
| location_state.dart | `lib/screens/location/bloc/location_state.dart` | ソース | Blocステート定義 |
| location_repo.dart | `lib/screens/location/bloc/location_repo.dart` | ソース | Place API通信リポジトリ |
| index.dart | `lib/screens/location/utils/index.dart` | ソース | 共通インポートファイル |
