本ドキュメントでは,MiniTIAS アプリの画面設計,画面遷移,カメラ制御,ファイル管理,およびアーキテクチャを定義する.
| ID | 画面名 | 概要 |
| S-01 | 撮影画面 | インカメラのライブプレビューを表示し,撮影を行う |
| S-02 | 一覧画面 | 撮影済み画像のサムネイル一覧を表示し,確認・削除を行う |
※ 初期バージョンでは 2 画面構成とする.
[アプリ起動]
│
▼
┌──────────┐ BottomNavigationBar ┌──────────┐
│ S-01 │ ◄──────────────────────────────► │ S-02 │
│ 撮影画面 │ タブ切り替え │ 一覧画面 │
└──────────┘ └──────────┘
│
│ サムネイルタップ
▼
┌──────────┐
│ 拡大表示 │
│ (ダイアログ) │
└──────────┘
- アプリ起動時のデフォルト画面は 撮影画面(S-01) とする
- 画面切り替えには
BottomNavigationBar を使用する(タブ 2 つ: 撮影 / 一覧)
- 画像の拡大表示はダイアログ(
showDialog)で実装し,独立画面としない
┌─────────────────────────┐
│ BottomNavBar │ ← 画面下部(通常位置)
├─────────────────────────┤
│ │
│ │
│ カメラプレビュー │ ← 上下反転表示(180°回転)
│ (画面全体) │
│ │
│ │
├─────────────────────────┤
│ [シャッターボタン] │ ← 画面上部(端末を逆さに置くため)
└─────────────────────────┘
※ 端末を逆さに置いて使用するため,UI 全体を 180° 回転する.操作者から見ると通常の上下配置に見える.
| 要素 | 仕様 |
| カメラプレビュー | インカメラ(前面カメラ)のライブ映像.UI 全体を 180° 回転して表示 |
| シャッターボタン | 丸型ボタン.タップで撮影実行.連続タップ可(連写対応) |
| BottomNavigationBar | 撮影タブ(アクティブ)/ 一覧タブ |
- 起動時: カメラの初期化を行い,プレビューを開始する
- 撮影: シャッターボタンタップで静止画をキャプチャし,PNG 形式で保存する
- 連続撮影: 前回の保存完了を待たずに次の撮影が可能.撮影中はシャッターボタンの操作を受け付ける
- フィードバック: 撮影成功時にスナックバーで「保存しました: ファイル名」を表示する
- エラー時: カメラ初期化失敗やストレージ書き込み失敗時は,エラーメッセージをスナックバーで表示する
┌─────────────────────────┐
│ BottomNavBar │
├─────────────────────────┤
│ ┌─────┐ ┌─────┐ ┌─────┐│
│ │ │ │ │ │ ││
│ │ img │ │ img │ │ img ││
│ │ │ │ │ │ ││
│ └─────┘ └─────┘ └─────┘│
│ ┌─────┐ ┌─────┐ ┌─────┐│
│ │ │ │ │ │ ││
│ │ img │ │ img │ │ img ││
│ │ │ │ │ │ ││
│ └─────┘ └─────┘ └─────┘│
│ ... │
├─────────────────────────┤
│ [画面上部エリア] │ ← 逆さ配置のため上部が操作側
└─────────────────────────┘
※ 撮影画面と同様に UI 全体を 180° 回転して表示する.
| 要素 | 仕様 |
| サムネイルグリッド | 3 列のグリッド表示.新しい画像が先頭(降順) |
| サムネイル | 正方形クロップ.タップで拡大表示 |
| ファイル名ラベル | 各サムネイル下部にファイル名を表示 |
| BottomNavigationBar | 撮影タブ / 一覧タブ(アクティブ) |
| 要素 | 仕様 |
| 画像 | 元画像をフル解像度で表示.ピンチ操作でズーム可能 |
| ファイル名 | ダイアログ上部にファイル名を表示 |
| 削除ボタン | ダイアログ内に配置.タップで削除確認ダイアログを表示 |
| 閉じるボタン | ダイアログ外タップまたは閉じるボタンで閉じる |
- 画面表示時:
Pictures/MiniTIAS/ ディレクトリ内の PNG ファイルを走査し,一覧を構築する
- リフレッシュ: 撮影画面から戻った際に一覧を再取得する
- 削除: 削除確認ダイアログで「削除」を選択すると,ファイルをストレージから削除し,一覧から除去する
- 空状態: 画像が 0 件の場合は「撮影した画像がありません」のメッセージを表示する
| 項目 | 値 |
| 使用カメラ | フロントカメラ(インカメラ) |
| 解像度 | ResolutionPreset.max(カメラが対応する最大解像度) |
| フォーカス | オートフォーカス(デフォルト動作) |
| フラッシュ | OFF(LED ライトはアタッチメント側で制御) |
| 画像フォーマット | カメラ出力は JPEG → アプリ内で PNG に変換して保存 |
camera パッケージの CameraPreview ウィジェットを使用する
- UI 全体を
Transform.rotate(angle: pi) で 180° 回転する
- プレビューのアスペクト比はカメラのネイティブ比率を維持する
シャッターボタンタップ
│
▼
CameraController.takePicture()
│
▼
一時ファイル(XFile)取得
│
▼
PNG エンコード(image パッケージ)
│
▼
ファイル名生成(命名規則に従う)
│
▼
Pictures/MiniTIAS/ に保存
│
▼
MediaStore 通知(ギャラリーアプリへの反映)
│
▼
スナックバーで保存完了を通知
WidgetsBindingObserver を使用し,アプリのライフサイクルを監視する
- バックグラウンド遷移時(
paused): カメラリソースを解放する(CameraController.dispose())
- フォアグラウンド復帰時(
resumed): カメラを再初期化する
- 画面遷移でカメラを使用しない画面に移動した場合もカメラリソースを解放する
- パス:
Pictures/MiniTIAS/(Android 共有ストレージ)
- Android 10 以上では MediaStore API を使用する(
saver_gallery パッケージで抽象化)
- ディレクトリが存在しない場合は自動作成する
- 基本形式:
MiniTIAS_YYYYMMDD_HHmmss.png
- 同秒重複時:
MiniTIAS_YYYYMMDD_HHmmss_1.png,MiniTIAS_YYYYMMDD_HHmmss_2.png,...
- タイムスタンプはデバイスのローカル時刻を使用する
ファイル名候補 = "MiniTIAS_{timestamp}.png"
IF ファイル名候補が存在しない:
RETURN ファイル名候補
suffix = 1
WHILE "MiniTIAS_{timestamp}_{suffix}.png" が存在する:
suffix += 1
RETURN "MiniTIAS_{timestamp}_{suffix}.png"
- 一覧画面の拡大表示ダイアログから削除を実行する
- 削除前に確認ダイアログを表示する(「この画像を削除しますか?」)
- ファイルシステムから物理削除する(ゴミ箱機能なし)
- 削除後,MediaStore からも当該エントリを除去する
| パーミッション | 用途 | 対象 API レベル |
CAMERA | カメラプレビュー・撮影 | 全バージョン |
WRITE_EXTERNAL_STORAGE | 画像保存 | API 28 以下 |
READ_EXTERNAL_STORAGE | 画像一覧取得 | API 28 以下 |
READ_MEDIA_IMAGES | 画像一覧取得 | API 33 以上 |
※ API 29〜32 では Scoped Storage により,アプリが MediaStore 経由で保存したファイルは追加権限なしでアクセス可能.
アプリ起動
│
▼
カメラ権限を確認
│
├── 許可済み → カメラプレビュー開始
│
└── 未許可 → 権限リクエストダイアログ表示
│
├── 許可 → カメラプレビュー開始
│
└── 拒否 → 「カメラの権限が必要です」メッセージ表示
+ 設定画面への誘導ボタン
- ストレージ権限は撮影時・一覧表示時にそれぞれ確認する
permission_handler パッケージを使用する
provider パッケージを使用する
- 画面ごとに ChangeNotifier を作成し,ビジネスロジックを UI から分離する
| Provider | 責務 |
CameraProvider | カメラの初期化・プレビュー制御・撮影実行・ライフサイクル管理 |
GalleryProvider | 画像一覧の取得・キャッシュ・削除操作 |
lib/
├── main.dart # アプリエントリポイント,Provider 登録
├── app.dart # MaterialApp 定義,テーマ設定
├── providers/
│ ├── camera_provider.dart # カメラ制御の状態管理
│ └── gallery_provider.dart # 画像一覧の状態管理
├── screens/
│ ├── capture_screen.dart # 撮影画面 (S-01)
│ └── gallery_screen.dart # 一覧画面 (S-02)
├── widgets/
│ ├── camera_preview.dart # カメラプレビューウィジェット
│ ├── shutter_button.dart # シャッターボタン
│ ├── image_grid.dart # サムネイルグリッド
│ └── image_detail_dialog.dart # 拡大表示ダイアログ
└── services/
├── file_service.dart # ファイル保存・命名・削除
└── permission_service.dart # パーミッション管理
┌─────────────────────────────────┐
│ Screens(画面) │ UI 層: ウィジェット構築のみ
├─────────────────────────────────┤
│ Widgets(部品) │ 再利用可能な UI コンポーネント
├─────────────────────────────────┤
│ Providers(状態管理) │ ビジネスロジック・状態保持
├─────────────────────────────────┤
│ Services(サービス) │ 外部リソースとのインタフェース
└─────────────────────────────────┘
- Screens は Provider を
context.watch / context.read で参照し,直接 Service を呼ばない
- Providers は Service を呼び出し,結果を状態として保持する
- Services はプラットフォーム API やファイルシステムとの橋渡しを行う
- 撮影から保存完了まで 2 秒以内を目標とする
- 一覧画面のサムネイル読み込みは非同期で行い,画面表示をブロックしない
- 撮影データは端末ローカルにのみ保存する(クラウド同期なし)
- PNG(非圧縮)形式で保存し,画質劣化を防ぐ
- 試験端末: AQUOS sense3(SH-02M,Android 9)
- minSdkVersion: 21(Android 5.0)
- targetSdkVersion: Flutter デフォルト(最新安定版に追従)