Newer
Older
MiniTias / lib / screens / capture_screen.dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'package:mini_tias/providers/camera_provider.dart';
import 'package:mini_tias/widgets/camera_preview.dart';
import 'package:mini_tias/widgets/shutter_button.dart';

/// 撮影画面.カメラプレビューとシャッターボタンを表示する.
class CaptureScreen extends StatefulWidget {
  const CaptureScreen({super.key});

  @override
  State<CaptureScreen> createState() => _CaptureScreenState();
}

class _CaptureScreenState extends State<CaptureScreen>
    with WidgetsBindingObserver {
  String? _previousFileName;
  bool _timerEnabled = false;
  int? _countdown;
  Timer? _countdownTimer;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      context.read<CameraProvider>().initialize();
    });
  }

  @override
  void dispose() {
    _countdownTimer?.cancel();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    final cameraProvider = context.read<CameraProvider>();
    if (state == AppLifecycleState.paused) {
      _cancelCountdown();
      cameraProvider.disposeCamera();
    } else if (state == AppLifecycleState.resumed) {
      cameraProvider.initialize();
    }
  }

  void _onShutterPressed() {
    final cameraProvider = context.read<CameraProvider>();
    if (cameraProvider.isSaving || _countdown != null) return;

    if (_timerEnabled) {
      _startCountdown();
    } else {
      cameraProvider.takePicture();
    }
  }

  void _startCountdown() {
    setState(() => _countdown = 3);
    _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (_countdown == null) {
        timer.cancel();
        return;
      }
      if (_countdown! <= 1) {
        timer.cancel();
        setState(() => _countdown = null);
        context.read<CameraProvider>().takePicture();
      } else {
        setState(() => _countdown = _countdown! - 1);
      }
    });
  }

  void _cancelCountdown() {
    _countdownTimer?.cancel();
    _countdownTimer = null;
    if (mounted) {
      setState(() => _countdown = null);
    }
  }

  void _showSaveResult(CameraProvider cameraProvider) {
    final fileName = cameraProvider.lastSavedFileName;
    if (fileName != null && fileName != _previousFileName) {
      _previousFileName = fileName;
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('保存しました: $fileName'),
            duration: const Duration(seconds: 2),
            behavior: SnackBarBehavior.floating,
            margin: EdgeInsets.only(
              bottom: MediaQuery.of(context).size.height / 2,
              left: 16,
              right: 16,
            ),
          ),
        );
      });
    }

    final error = cameraProvider.errorMessage;
    if (error != null && !cameraProvider.isInitialized) return;
    if (error != null && !cameraProvider.isSaving) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text(error), backgroundColor: Colors.red),
        );
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    final cameraProvider = context.watch<CameraProvider>();

    _showSaveResult(cameraProvider);

    if (cameraProvider.permissionDenied) {
      return _buildPermissionDenied(cameraProvider);
    }

    if (cameraProvider.errorMessage != null && !cameraProvider.isInitialized) {
      return Center(child: Text(cameraProvider.errorMessage!));
    }

    if (!cameraProvider.isInitialized) {
      return const Center(child: CircularProgressIndicator());
    }

    return Stack(
      children: [
        Positioned.fill(
          child: CameraPreviewWidget(controller: cameraProvider.controller!),
        ),
        // 保存中インジケーター
        if (cameraProvider.isSaving)
          const Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                CircularProgressIndicator(color: Colors.white),
                SizedBox(height: 12),
                Text(
                  '保存中...',
                  style: TextStyle(color: Colors.white, fontSize: 16),
                ),
              ],
            ),
          ),
        // カウントダウン表示
        if (_countdown != null)
          Center(
            child: Stack(
              children: [
                // 黒い縁取り
                Text(
                  '$_countdown',
                  style: TextStyle(
                    fontSize: 96,
                    fontWeight: FontWeight.bold,
                    foreground: Paint()
                      ..style = PaintingStyle.stroke
                      ..strokeWidth = 6
                      ..color = Colors.black,
                  ),
                ),
                // 白いテキスト本体
                Text(
                  '$_countdown',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 96,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ],
            ),
          ),
        // タイマー切り替えボタン(左側)
        Positioned(
          left: 24,
          bottom: 36,
          child: GestureDetector(
            onTap: () {
              _cancelCountdown();
              setState(() => _timerEnabled = !_timerEnabled);
            },
            child: Stack(
              alignment: Alignment.center,
              children: [
                Icon(
                  _timerEnabled ? Icons.timer : Icons.timer_off,
                  color: Colors.black,
                  size: 40,
                ),
                Icon(
                  _timerEnabled ? Icons.timer : Icons.timer_off,
                  color: _timerEnabled ? Colors.yellow : Colors.grey,
                  size: 32,
                ),
              ],
            ),
          ),
        ),
        // シャッターボタン(中央)
        Positioned(
          left: 0,
          right: 0,
          bottom: 24,
          child: Center(
            child: ShutterButton(
              onPressed: cameraProvider.isSaving || _countdown != null
                  ? () {}
                  : _onShutterPressed,
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildPermissionDenied(CameraProvider cameraProvider) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(cameraProvider.errorMessage ?? 'カメラの権限が必要です'),
          const SizedBox(height: 16),
          if (cameraProvider.permissionPermanentlyDenied)
            ElevatedButton(
              onPressed: () => cameraProvider.openSettings(),
              child: const Text('設定画面を開く'),
            )
          else
            ElevatedButton(
              onPressed: () => cameraProvider.initialize(),
              child: const Text('権限を許可する'),
            ),
        ],
      ),
    );
  }
}