2024-09-02 ほぼOK

This commit is contained in:
2024-09-02 21:25:19 +09:00
parent dc58dc0584
commit fe46d46ab6
59 changed files with 2006 additions and 677 deletions

View File

@ -14,8 +14,11 @@ import 'package:gifunavi/services/external_service.dart';
import 'package:gifunavi/utils/const.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
import 'package:http/http.dart' as http; // この行を追加
import 'package:http/http.dart' as http;
import '../../routes/app_pages.dart'; // この行を追加
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
// 関数 getTagText は、特定の条件に基づいて文字列から特定の部分を抽出し、返却するためのものです。
// 関数は2つのパラメータを受け取り、条件分岐を通じて結果を返します。
@ -220,10 +223,67 @@ class CameraPage extends StatelessWidget {
Timer? timer;
bool isValidEventParticipation() {
final eventCode = indexController.currentUser[0]["user"]["event_code"];
final teamName = indexController.currentUser[0]["user"]["team_name"];
final dateString = indexController.currentUser[0]["user"]["event_date"];
//final parsedDate = DateTime.parse(dateString);
//final eventDate = tz.TZDateTime.from(parsedDate, tz.getLocation('Asia/Tokyo'));
//final today = DateTime.now();
return eventCode != null &&
teamName != null &&
dateString != null ;
// isSameDay(eventDate, today);
}
bool isSameDay(DateTime date1, DateTime date2) {
return date1.year == date2.year &&
date1.month == date2.month &&
date1.day == date2.day;
}
void showEventParticipationWarning(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("警告"),
content: const Text("今日のイベントにまず参加しないと事前チェックインはできません。サブメニューからイベント参加をタップして今日のイベントに参加してください。"),
actions: <Widget>[
TextButton(
child: const Text("キャンセル"),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text("参加する"),
onPressed: () {
Navigator.of(context).pop();
Get.toNamed(AppPages.EVENT_ENTRY);
},
),
],
);
},
);
}
// 現在の状態に基づいて、適切なアクションボタンを返します。
// 要修正:エラーハンドリングが不十分です。例外が発生した場合の処理を追加することをお勧めします。
//
Widget getAction(BuildContext context) {
if (!isValidEventParticipation()) {
return ElevatedButton(
onPressed: () => showEventParticipationWarning(context),
child: const Text("チェックイン"),
);
}
if (manulaCheckin == true) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
@ -253,7 +313,9 @@ class CameraPage extends StatelessWidget {
onPressed: () async {
await destinationController.makeCheckin(destination, true,
destinationController.photos[0].path);
destinationController.rogainingCounted.value = true;
if( destinationController.isInRog.value==true ) {
destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可
}
destinationController.skipGps = false;
destinationController.isPhotoShoot.value = false;
@ -387,7 +449,9 @@ class CameraPage extends StatelessWidget {
await destinationController.makeBuyPoint(
destination, destinationController.photos[0].path);
Get.back();
destinationController.rogainingCounted.value = true;
if( destinationController.isInRog.value==true ) {
destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可
}
destinationController.skipGps = false;
destinationController.isPhotoShoot.value = false;
Get.snackbar("お買い物加点を行いました。",
@ -428,7 +492,9 @@ class CameraPage extends StatelessWidget {
await destinationController.makeBuyPoint(
destination, destinationController.photos[0].path);
Get.back();
destinationController.rogainingCounted.value = true;
if( destinationController.isInRog.value==true ) {
destinationController.rogainingCounted.value = true; //ロゲ開始後のみ許可
}
destinationController.skipGps = false;
destinationController.isPhotoShoot.value = false;
Get.snackbar("お買い物加点を行いました。",
@ -465,7 +531,9 @@ class CameraPage extends StatelessWidget {
true,
destinationController.photos[0].path);
//Get.back();
destinationController.rogainingCounted.value = true;
if( destinationController.isInRog.value==true ) {
destinationController.rogainingCounted.value = true; //ロゲ開始後のみ許可
}
destinationController.skipGps = false;
destinationController.isPhotoShoot.value = false;
@ -496,6 +564,7 @@ class CameraPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//print("---- photos ${destination.photos} ----");
if (buyPointPhoto == true) {
// buyPointPhotoがtrueの場合は、BuyPointCameraウィジェットを返します。
@ -780,7 +849,9 @@ class BuyPointCamera extends StatelessWidget {
onPressed: () async {
await destinationController.cancelBuyPoint(destination);
Navigator.of(Get.context!).pop();
destinationController.rogainingCounted.value = true;
if( destinationController.isInRog.value==true ) {
destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可
}
destinationController.skipGps = false;
destinationController.isPhotoShoot.value = false;
},

View File

@ -1,6 +1,8 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:gifunavi/model/destination.dart';
@ -8,8 +10,17 @@ import 'package:gifunavi/model/destination.dart';
class CustomCameraView extends StatefulWidget {
final Function(String) onImageCaptured;
final Destination? destination;
final Function(bool) onCameraStatusChanged;
//const CustomCameraView({super.key, required this.onImageCaptured, required this.destination});
const CustomCameraView({
Key? key,
required this.onImageCaptured,
required this.destination,
required this.onCameraStatusChanged, // 新しいコールバック
}) : super(key: key);
const CustomCameraView({super.key, required this.onImageCaptured, required this.destination});
@override
_CustomCameraViewState createState() => _CustomCameraViewState();
@ -17,6 +28,8 @@ class CustomCameraView extends StatefulWidget {
class _CustomCameraViewState extends State<CustomCameraView> {
CameraController? _controller;
bool _isCameraAvailable = true;
late List<CameraDescription> _cameras;
int _selectedCameraIndex = 0;
double _currentScale = 1.0;
@ -31,10 +44,25 @@ class _CustomCameraViewState extends State<CustomCameraView> {
}
Future<void> _initializeCamera() async {
_cameras = await availableCameras();
_controller = CameraController(_cameras[_selectedCameraIndex], ResolutionPreset.medium);
await _controller!.initialize();
setState(() {});
try {
_cameras = await availableCameras();
if (_cameras.isNotEmpty) {
_controller = CameraController(
_cameras[_selectedCameraIndex], ResolutionPreset.medium);
await _controller!.initialize();
setState(() {
_isCameraAvailable = true;
});
} else {
throw Exception('Camera is not available');
}
}catch(err){
print("Error initializing camera: $err");
setState(() {
_isCameraAvailable = false;
});
}
widget.onCameraStatusChanged(_isCameraAvailable);
}
@override
@ -82,20 +110,46 @@ class _CustomCameraViewState extends State<CustomCameraView> {
}
void _captureImage() async {
if (_controller!.value.isInitialized) {
final Directory appDirectory = await getApplicationDocumentsDirectory();
final String imagePath = path.join(appDirectory.path, '${DateTime.now()}.jpg');
if (_isCameraAvailable) {
if (_controller!.value.isInitialized) {
final Directory appDirectory = await getApplicationDocumentsDirectory();
final String imagePath = path.join(
appDirectory.path, '${DateTime.now()}.jpg');
final XFile imageFile = await _controller!.takePicture();
await imageFile.saveTo(imagePath);
final XFile imageFile = await _controller!.takePicture();
await imageFile.saveTo(imagePath);
widget.onImageCaptured(imagePath);
Navigator.pop(context);
}
}else{
// ダミー画像を使用
final String imagePath = await _saveDummyImage();
widget.onImageCaptured(imagePath);
Navigator.pop(context);
}
}
Future<String> _saveDummyImage() async {
final Directory appDirectory = await getApplicationDocumentsDirectory();
final String imagePath = path.join(appDirectory.path, 'dummy_${DateTime.now()}.png');
// アセットからダミー画像を読み込む
ByteData data = await rootBundle.load('assets/images/dummy_camera_image.png');
List<int> bytes = data.buffer.asUint8List();
// ダミー画像をファイルとして保存
await File(imagePath).writeAsBytes(bytes);
return imagePath;
}
@override
Widget build(BuildContext context) {
if (!_isCameraAvailable) {
return _buildDummyCameraView();
}
if (_controller == null || !_controller!.value.isInitialized) {
return Container();
}
@ -182,4 +236,64 @@ class _CustomCameraViewState extends State<CustomCameraView> {
],
);
}
Widget _buildDummyCameraView() {
return Stack(
children: [
Container(
color: Colors.black,
child: const Center(
child: Text(
'カメラを利用できません',
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
),
Positioned(
bottom: 16.0,
left: 16.0,
right: 16.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.flash_off, color: Colors.white),
iconSize: 32,
),
GestureDetector(
onTap: _captureEmulatedImage,
child: Container(
height: 80,
width: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
border: Border.all(color: Colors.red, width: 4),
),
child: const Icon(Icons.camera_alt, color: Colors.red, size: 40),
),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.flip_camera_ios, color: Colors.white),
iconSize: 32,
),
],
),
),
],
);
}
void _captureEmulatedImage() async {
final Directory appDirectory = await getApplicationDocumentsDirectory();
final String imagePath = path.join(appDirectory.path, '${DateTime.now()}.jpg');
// ダミーの画像ファイルを作成
await File(imagePath).writeAsBytes(Uint8List(0));
widget.onImageCaptured(imagePath);
Navigator.pop(context);
}
}