2 Commits

18 changed files with 518 additions and 148 deletions

View File

@ -156,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1430; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1430" LastUpgradeVersion = "1510"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -30,6 +30,8 @@ class Destination {
int recipt_times = 0; int recipt_times = 0;
String? tags; String? tags;
bool use_qr_code = false; // QR code を使用するかどうか。default=false
Destination( Destination(
{this.name, {this.name,
this.address, this.address,
@ -57,13 +59,14 @@ class Destination {
this.buypoint_image, this.buypoint_image,
this.forced_checkin = false, this.forced_checkin = false,
this.recipt_times = 0, this.recipt_times = 0,
this.tags}); this.tags,
this.use_qr_code = false});
factory Destination.fromMap(Map<String, dynamic> json) { factory Destination.fromMap(Map<String, dynamic> json) {
bool selec = json['selected'] == 0 ? false : true; bool selec = json['selected'] == 0 ? false : true;
bool checkin = json['checkedin'] == 0 ? false : true; bool checkin = json['checkedin'] == 0 ? false : true;
bool forcedCheckin = json['forced_checkin'] == 0 ? false : true; bool forcedCheckin = json['forced_checkin'] == 0 ? false : true;
bool useQrCode = json['use_qr_code'] == 1 ? true : false;
//print("-----tags model----- ${json}"); //print("-----tags model----- ${json}");
return Destination( return Destination(
@ -93,7 +96,8 @@ class Destination {
buypoint_image: json["buypoint_image"], buypoint_image: json["buypoint_image"],
forced_checkin: forcedCheckin, forced_checkin: forcedCheckin,
recipt_times: json["recipt_times"], recipt_times: json["recipt_times"],
tags: json["tags"]); tags: json["tags"],
use_qr_code: useQrCode);
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
@ -127,7 +131,8 @@ class Destination {
'buypoint_image': buypoint_image, 'buypoint_image': buypoint_image,
'forced_checkin': forcedCheckin, 'forced_checkin': forcedCheckin,
'recipt_times': recipt_times, 'recipt_times': recipt_times,
'tags': tags 'tags': tags,
'use_qr_code': use_qr_code
}; };
} }
} }

View File

@ -8,39 +8,103 @@ import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart'; import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/services/external_service.dart'; import 'package:rogapp/services/external_service.dart';
import 'package:rogapp/utils/const.dart'; import 'package:rogapp/utils/const.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
// 関数 getTagText は、特定の条件に基づいて文字列から特定の部分を抽出し、返却するためのものです。
// 関数は2つのパラメータを受け取り、条件分岐を通じて結果を返します。
//
// この関数は、タグのリスト(空白を含む文字列)を適切に解析し、条件に応じて特定のタグを抽出するために設計されています。
// 異なる種類の空白文字半角、全角で異なる分割を行い、与えられた条件isReceptに応じて適切なタグを選択して返却します。
//
String getTagText(bool isRecept, String? tags) { String getTagText(bool isRecept, String? tags) {
// bool isRecept: 真偽値を受け取り、この値によって処理の分岐が行われます。
// String? tags: オプショナルな文字列null が許容される)。空白文字を含む可能性のあるタグのリストを表します。
// 空のチェック:
// tags が null または空文字列 ("") の場合、何も含まれていないことを意味し、関数はただちに空文字列を返します。
//
if (tags == null || tags.isEmpty) { if (tags == null || tags.isEmpty) {
return ""; return "";
} }
// タグの分割:
// tags が空ではない場合、文字列を空白文字で分割します。
// ここで2種類の空白文字半角 " " と全角 " "に対応するため、2回分割を行っています。
// tts: 半角スペース " " で分割した結果のリスト。
// ttt: 全角スペース " " で分割した結果のリスト。
//
List<String> tts = tags.split(" "); List<String> tts = tags.split(" ");
List<String> ttt = tags.split(" "); List<String> ttt = tags.split(" ");
// 条件分岐:
// isRecept の値によって、処理が分岐します。
//
if (isRecept) { if (isRecept) {
// isRecept が true の場合:
// 全角スペースで分割した結果 (ttt) の長さが半角スペースで分割した結果 (tts) の長さより大きく、
// かつ ttt が1つ以上の要素を持つ場合、ttt[1] 全角スペースで分割後の2番目の要素を返します。
if (ttt.length > tts.length && ttt.length > 1) { if (ttt.length > tts.length && ttt.length > 1) {
return ttt[1]; return ttt[1];
} }
} }
if (!isRecept) { if (!isRecept) {
// isRecept が false の場合:
// 全角スペースで分割したリストが半角スペースで分割したリストよりも長い場合、ttt[0] (全角スペースで分割後の最初の要素)を返します。
// 上記の条件に当てはまらない場合、半角スペースで分割したリストの最初の要素 tts[0] を返します。
//
if (ttt.length > tts.length && ttt.length > 1) { if (ttt.length > tts.length && ttt.length > 1) {
return ttt[0]; return ttt[0];
} }
} }
if (!isRecept) { if (!isRecept) {
// 最終的な返却:
// 上記の条件に何も該当しない場合(主に isRecept が true であり、全角スペースの条件に該当しない場合)、空文字列 "" を返します。
return tts[0]; return tts[0];
} }
return ""; return "";
} }
// 要修正:画像の読み込みエラーが発生した場合のエラーハンドリングが不十分です。エラーメッセージを表示するなどの処理を追加してください。 // 要修正:画像の読み込みエラーが発生した場合のエラーハンドリングが不十分です。エラーメッセージを表示するなどの処理を追加してください。
// getDisplayImage は、Destination オブジェクトを受け取り、特定の条件に基づいて表示する画像を返す機能を持っています。
// Flutterの Image ウィジェットを使用して、適切な画像を表示します。
//
// この関数は、提供された Destination オブジェクトに基づいて適切な画像を動的に選択し、
// その画像を表示するための Image ウィジェットを生成します。
// デフォルトの画像、完全なURL、またはサーバーURLと組み合わされた画像パスを使用して、条件に応じた画像の取得を試みます。
// また、エラー発生時にはデフォルト画像にフォールバックすることでユーザー体験を向上させます。
// //
Image getDisplayImage(Destination destination) { Image getDisplayImage(Destination destination) {
// Destination destination: これは Destination クラスのインスタンスで、
// CheckPointのデータを持っているオブジェクトです。
// このクラスには少なくとも phone と photos というプロパティが含まれている
//
// サーバーURLの取得:
// serverUrl 変数には ConstValues.currentServer() メソッドから現在のサーバーのURLが取得されます。
// これは画像を取得する際の基本URLとして使用される可能性があります。
//
String serverUrl = ConstValues.currentServer(); String serverUrl = ConstValues.currentServer();
// デフォルト画像の設定:
// img 変数にはデフォルトの画像が設定されます。
// これは、アセットから "assets/images/empty_image.png" をロードするための Image.asset コンストラクタを使用しています。
//
Image img = Image.asset("assets/images/empty_image.png"); Image img = Image.asset("assets/images/empty_image.png");
// 電話番号のチェック:
// destination.phone が null の場合、関数は imgデフォルト画像を返します。
// これは、phone プロパティが画像URLの代用として何らかの形で使用されることを示唆していますが、
// それが null であればデフォルト画像を使用するという意味です。
//
if (destination.phone == null) { if (destination.phone == null) {
return img; return img;
} }
// 画像URLの構築と画像の返却:
// destination.photos が http を含む場合、これはすでに完全なURLとして提供されていることを意味します。
// このURLを NetworkImage コンストラクタに渡し、Image ウィジェットを生成して返します。
// そうでない場合は、serverUrl と destination.photos を組み合わせたURLを生成して NetworkImage に渡し、画像を取得します。
//
if (destination.photos!.contains('http')) { if (destination.photos!.contains('http')) {
return Image( return Image(
image: NetworkImage( image: NetworkImage(
@ -64,16 +128,51 @@ Image getDisplayImage(Destination destination) {
} }
} }
// getFinishImage は、ImageProvider 型のオブジェクトを返す関数で、Flutterアプリケーションで使用される画像を提供します。
// この関数は、DestinationController というクラスのインスタンスに依存しており、特定の状態に基づいて適切な画像を返します。
//
// この関数は、アプリケーションの現在の状態に依存して動的に画像を提供します。
// DestinationController の photos リストに基づいて画像を選択し、リストが空の場合はデフォルトの画像を提供します。
// これにより、画像の動的な管理が可能になり、ユーザーインターフェースの柔軟性が向上します。
// また、ImageProvider クラスを使用することで、
// 画像の具体的な取得方法(ファイルからの読み込みやアセットからのロードなど)を抽象化し、
// Flutterの Image ウィジェットで直接使用できる形式で画像を返します。
//
ImageProvider getFinishImage() { ImageProvider getFinishImage() {
// DestinationControllerの取得:
// destinationController は Get.find<DestinationController>() を使用して取得されます。
// これは、GetXというFlutterの状態管理ライブラリの機能を使用して、
// 現在のアプリケーションコンテキストから DestinationController タイプのインスタンスを取得するものです。
// これにより、アプリケーションの他の部分で共有されている DestinationController の現在のインスタンスにアクセスします。
//
DestinationController destinationController = DestinationController destinationController =
Get.find<DestinationController>(); Get.find<DestinationController>();
// 画像の決定:
// destinationController.photos リストが空でないかどうかをチェックします。
// このリストは、ファイルパスまたは画像リソースへの参照を含む可能性があります。
//
if (destinationController.photos.isNotEmpty) { if (destinationController.photos.isNotEmpty) {
// リストが空でない場合、最初の要素 (destinationController.photos[0]) が使用されます。
// FileImage コンストラクタを使用して、このパスから ImageProvider を生成します。
// これは、ローカルファイルシステム上の画像ファイルを参照するためのものです。
//
return FileImage(destinationController.photos[0]); return FileImage(destinationController.photos[0]);
} else { } else {
// destinationController.photos が空の場合、
// AssetImage を使用してアプリケーションのアセットからデフォルトの画像('assets/images/empty_image.png')を
// ロードします。これはビルド時にアプリケーションに組み込まれる静的なリソースです。
//
return const AssetImage('assets/images/empty_image.png'); return const AssetImage('assets/images/empty_image.png');
} }
} }
// getReceiptImage は、ImageProvider 型を返す関数です。
// この関数は DestinationController オブジェクトに依存しており、条件に応じて特定の画像を返します。
// この関数は getFinishImage 関数と非常に似ており、ほぼ同じロジックを使用していますが、返されるデフォルトの画像が異なります。
//
ImageProvider getReceiptImage() { ImageProvider getReceiptImage() {
DestinationController destinationController = DestinationController destinationController =
Get.find<DestinationController>(); Get.find<DestinationController>();
@ -84,12 +183,21 @@ ImageProvider getReceiptImage() {
} }
} }
// CameraPageクラスは、目的地に応じて適切なカメラ機能とアクションボタンを提供します。
// 手動チェックイン、ゴール撮影、購入ポイント撮影など、様々なシナリオに対応しています。
// また、ロゲイニングが開始されていない場合は、StartRogainingウィジェットを表示して、ユーザーにロゲイニングの開始を促します。
// CameraPageクラスは、IndexControllerとDestinationControllerを使用して、
// 現在の状態や目的地の情報を取得し、適切なUIを構築します。
// また、写真の撮影や購入ポイントの処理など、様々な機能を提供しています。
//
class CameraPage extends StatelessWidget { class CameraPage extends StatelessWidget {
bool? manulaCheckin = false; bool? manulaCheckin = false; // 手動チェックインを示すブール値デフォルトはfalse
bool? buyPointPhoto = false; bool? buyPointPhoto = false; // 購入ポイントの写真を示すブール値デフォルトはfalse
Destination destination; Destination destination; // 目的地オブジェクト
Destination? dbDest; Destination? dbDest; // データベースから取得した目的地オブジェクト(オプショナル)
String? initImage; String? initImage; // 初期画像のパス(オプショナル)
bool? buyQrCode = false;
CameraPage( CameraPage(
{Key? key, {Key? key,
required this.destination, required this.destination,
@ -106,11 +214,15 @@ class CameraPage extends StatelessWidget {
Timer? timer; Timer? timer;
// 現在の状態に基づいて、適切なアクションボタンを返します。
// 要修正:エラーハンドリングが不十分です。例外が発生した場合の処理を追加することをお勧めします。 // 要修正:エラーハンドリングが不十分です。例外が発生した場合の処理を追加することをお勧めします。
// //
Widget getAction(BuildContext context) { Widget getAction(BuildContext context) {
//print("----cccheckin is --- ${dbDest?.checkedin} ----"); //print("----cccheckin is --- ${dbDest?.checkedin} ----");
if (manulaCheckin == true) { if (manulaCheckin == true) {
// manulaCheckinがtrueの場合は、撮影ボタンとチェックインボタンを表示します。
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
@ -142,6 +254,7 @@ class CameraPage extends StatelessWidget {
if (destinationController.isAtGoal.value && if (destinationController.isAtGoal.value &&
destinationController.isInRog.value && destinationController.isInRog.value &&
destination.cp == -1) { destination.cp == -1) {
// isAtGoalがtrueで、isInRogがtrue、destination.cpが-1の場合は、ゴール用の撮影ボタンとゴール完了ボタンを表示します。
//goal //goal
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
@ -215,10 +328,12 @@ class CameraPage extends StatelessWidget {
: Container()) : Container())
], ],
); );
} else if (destinationController.isInRog.value && } else if (destinationController.isInRog.value &&
dbDest?.checkedin != null && dbDest?.checkedin != null &&
destination.cp != -1 && destination.cp != -1 &&
dbDest?.checkedin == true) { dbDest?.checkedin == true) {
// isInRogがtrueで、dbDest?.checkedinがtrue、destination.cpが-1以外の場合は、購入ポイントの撮影ボタンと完了ボタンを表示します。
//make buypoint image //make buypoint image
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
@ -245,11 +360,49 @@ class CameraPage extends StatelessWidget {
Get.snackbar("お買い物加点を行いました。", Get.snackbar("お買い物加点を行いました。",
"${destination.sub_loc_id} : ${destination.name}"); "${destination.sub_loc_id} : ${destination.name}");
}, },
child: const Text("レシートの写真を撮")) child: const Text("レシートの写真を撮ってください"))
: Container())
],
);
} else if (destinationController.isInRog.value &&
dbDest?.checkedin != null &&
destination.cp != -1 &&
destination.use_qr_code == true &&
dbDest?.checkedin == true) {
// isInRogがtrueで、dbDest?.checkedinがtrue、destination.cpが-1以外、qrCode == true の場合は、
// QRCode 撮影ボタンを表示
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Obx(() => ElevatedButton(
onPressed: () {
destinationController.openCamera(context, destination);
},
child: destinationController.photos.isNotEmpty
? const Text("再QR読込")
: const Text("QR読込"))),
Obx(() => destinationController.photos.isNotEmpty
? ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () async {
// print(
// "##### current destination ${indexController.currentDestinationFeature[0].sub_loc_id} #######");
await destinationController.makeBuyPoint(
destination, destinationController.photos[0].path);
Get.back();
destinationController.rogainingCounted.value = true;
destinationController.skipGps = false;
destinationController.isPhotoShoot.value = false;
Get.snackbar("お買い物加点を行いました。",
"${destination.sub_loc_id} : ${destination.name}");
},
child: const Text("QRコードを読み取ってください"))
: Container()) : Container())
], ],
); );
} else { } else {
// それ以外の場合は、撮影ボタンとチェックインボタンを表示します。
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
@ -294,9 +447,15 @@ class CameraPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
//print("---- photos ${destination.photos} ----"); //print("---- photos ${destination.photos} ----");
if (buyPointPhoto == true) { if (buyPointPhoto == true) {
// buyPointPhotoがtrueの場合は、BuyPointCameraウィジェットを返します。
//print("--- buy point camera ${destination.toString()}"); //print("--- buy point camera ${destination.toString()}");
return BuyPointCamera(destination: destination); return BuyPointCamera(destination: destination);
}else if(destination.use_qr_code){
return QRCodeScannerPage(destination: destination);
} else if (destinationController.isInRog.value) { } else if (destinationController.isInRog.value) {
// isInRogがtrueの場合は、カメラページのUIを構築します。
// AppBarには、目的地の情報を表示します。
// ボディには、目的地の画像、タグ、アクションボタンを表示します。
//print("-----tags camera page----- ${destination.tags}"); //print("-----tags camera page----- ${destination.tags}");
//print("--- in normal camera ${destination.toString()}"); //print("--- in normal camera ${destination.toString()}");
return Scaffold( return Scaffold(
@ -361,11 +520,15 @@ class CameraPage extends StatelessWidget {
), ),
); );
} else { } else {
// isInRogがfalseの場合は、StartRogainingウィジェットを返します。
return StartRogaining(); return StartRogaining();
} }
} }
} }
// ロゲイニングが開始されていない場合に表示されるウィジェットです。
// "You have not started rogaining yet."というメッセージと、戻るボタンを表示します。
//
class StartRogaining extends StatelessWidget { class StartRogaining extends StatelessWidget {
StartRogaining({Key? key}) : super(key: key); StartRogaining({Key? key}) : super(key: key);
@ -404,6 +567,12 @@ class StartRogaining extends StatelessWidget {
} }
} }
// 購入ポイントの写真撮影用のウィジェットです。
// 目的地の画像、タグ、撮影ボタン、完了ボタン、購入なしボタンを表示します。
// 撮影ボタンをタップすると、カメラが起動します。
// 完了ボタンをタップすると、購入ポイントの処理が行われます。
// 購入なしボタンをタップすると、購入ポイントがキャンセルされます。
//
class BuyPointCamera extends StatelessWidget { class BuyPointCamera extends StatelessWidget {
BuyPointCamera({Key? key, required this.destination}) : super(key: key); BuyPointCamera({Key? key, required this.destination}) : super(key: key);
@ -521,3 +690,41 @@ class BuyPointCamera extends StatelessWidget {
); );
} }
} }
class QRCodeScannerPage extends StatefulWidget {
@override
_QRCodeScannerPageState createState() => _QRCodeScannerPageState();
}
class _QRCodeScannerPageState extends State<QRCodeScannerPage> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
QRViewController? controller;
@override
void dispose() {
controller?.dispose();
super.dispose();
}
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
// QRコードのデータを処理する
debugPrint("scan data = ${scanData}");
String? qrCodeData = scanData.code;
// qrCodeDataを使用してチェックポイントの処理を行う
// 例えば、qrCodeDataからCPのIDと店名を取得し、加点処理を行う
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
),
);
}
}

View File

@ -24,7 +24,7 @@ import 'package:rogapp/services/perfecture_service.dart';
import 'package:rogapp/utils/database_gps.dart'; import 'package:rogapp/utils/database_gps.dart';
import 'package:rogapp/utils/database_helper.dart'; import 'package:rogapp/utils/database_helper.dart';
import 'package:rogapp/utils/location_controller.dart'; import 'package:rogapp/utils/location_controller.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart'; import 'package:rogapp/widgets/bottom_sheet_new.dart';
import 'dart:async'; import 'dart:async';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
@ -201,18 +201,33 @@ class DestinationController extends GetxController {
} }
// 指定された目的地の位置情報に基づいてタイマーを開始する関数です。 // 指定された目的地の位置情報に基づいてタイマーを開始する関数です。
// CP情報(fs)と現在位置からCPまでの距離distance を引数として渡します。
// //
Future<void> startTimerLocation(GeoJSONFeature fs, double distance) async { Future<void> startTimerLocation(GeoJSONFeature fs, double distance) async {
//print("---- in startTimer ----"); //print("---- in startTimer ----");
// print("---- is in rog is $is_in_rog ----"); // print("---- is in rog is $is_in_rog ----");
double checkinRadious = fs.properties!['checkin_radius'] ?? double.infinity; double checkinRadious = fs.properties!['checkin_radius'] ?? double.infinity;
// CPのcheckin_radiusを取得し、checkinRadius に代入。値がなければinfinityとする。
if (checkinRadious >= distance) { if (checkinRadious >= distance) {
// checkinRadious以内に入ったら、
indexController.currentFeature.clear(); indexController.currentFeature.clear();
// indexController.currentFeatureを空にします。
Destination d = festuretoDestination(fs); Destination d = festuretoDestination(fs);
// festuretoDestination(fs)を呼び出し、GeoJSONFeatureオブジェクトfsからDestinationオブジェクトdを作成します。
// print("----- destination lenght is ${destinations.length} -----"); // print("----- destination lenght is ${destinations.length} -----");
indexController.currentFeature.add(fs); indexController.currentFeature.add(fs);
// indexController.currentFeatureにfsを追加します。
//print("---- before calling startTimer ----"); //print("---- before calling startTimer ----");
await startTimer(d, distance); await startTimer(d, distance);
// startTimer(d, distance)を非同期で呼び出し、その完了を待機します。
return; return;
} }
} }
@ -227,43 +242,51 @@ class DestinationController extends GetxController {
// //
// 要検討:エラーが発生した場合のエラーハンドリングを追加し、適切なメッセージを表示することを検討してください。 // 要検討:エラーが発生した場合のエラーハンドリングを追加し、適切なメッセージを表示することを検討してください。
// //
// 引数CPオブジェクトと現在地からCPまでの距離を渡す。
//
Future<void> startTimer(Destination d, double distance) async { Future<void> startTimer(Destination d, double distance) async {
//print("=== passed dest is ${d.location_id} ${d.checkedin} ===="); //print("=== passed dest is ${d.location_id} ${d.checkedin} ====");
skipGps = true; skipGps = true;
//print("---- in startTimer ----"); //debugPrint("---- in startTimer ----");
DatabaseHelper db = DatabaseHelper.instance; DatabaseHelper db = DatabaseHelper.instance;
List<Destination> ds = await db.getDestinationByLatLon(d.lat!, d.lon!); List<Destination> ds = await db.getDestinationByLatLon(d.lat!, d.lon!);
//指定位置のオブジェクトのリストを取得。
Destination? dss; Destination? dss;
if (ds.isNotEmpty) { if (ds.isNotEmpty) {
dss = ds.first; dss = ds.first; // 取得したリストが空でない場合、dss変数に最初の要素を代入します。
} }
double checkinRadious = d.checkin_radious ?? double.infinity; // 変数を計算
bool autoCheckin = d.auto_checkin == 0 ? false : true; double checkinRadious = d.checkin_radious ?? double.infinity; // 反応半径
bool buyPoint = dss != null && dss.buy_point != null && dss.buy_point! > 0 bool autoCheckin = d.auto_checkin == 0 ? false : true; // 自動チェックイン
bool buyPoint = dss != null && dss.buy_point != null && dss.buy_point! > 0 // 買い物ポイント
? true ? true
: false; : false;
bool buyPointImageAdded = bool buyPointImageAdded = // 買い物画像
dss != null && dss.buypoint_image != null ? true : false; dss != null && dss.buypoint_image != null ? true : false;
bool buyPointCanceled = bool buyPointCanceled = // 買い物キャンセル
dss != null && dss.buy_point != null && dss.buy_point == 0 dss != null && dss.buy_point != null && dss.buy_point == 0
? true ? true
: false; : false;
bool locationAlreadyCheckedIn = bool locationAlreadyCheckedIn = // チェックイン済みか
ds.isNotEmpty && ds[0].checkedin == true ? true : false; ds.isNotEmpty && ds[0].checkedin == true ? true : false;
bool isuserLoggedIn = indexController.currentUser.isNotEmpty ? true : false; bool isuserLoggedIn = indexController.currentUser.isNotEmpty ? true : false; // ログイン済みか
//make current destination
// print("---- checkin_radious $checkinRadious ----"); // 初期化。GPS信号が強くても弱くても
// print("---- distance $distance ----"); if (checkinRadious >= distance || checkinRadious == -1) { // 反応半径内か、-1(=距離を無視)
if (checkinRadious >= distance || checkinRadious == -1) {
//currentSelectedDestinations.add(d); //currentSelectedDestinations.add(d);
// 目的地として登録する。
//debugPrint("目的地の初期化");
indexController.currentDestinationFeature.clear(); indexController.currentDestinationFeature.clear();
indexController.currentDestinationFeature.add(d); indexController.currentDestinationFeature.add(d);
// print( // print(
// "---- checked in as ${indexController.currentDestinationFeature[0].checkedin.toString()} ----"); // "---- checked in as ${indexController.currentDestinationFeature[0].checkedin.toString()} ----");
} else { } else {
// ここには来ないのでは?
debugPrint("検出範囲外...");
// GPS信号が弱い場合でも、チェックインやゴールの処理を続行する // GPS信号が弱い場合でも、チェックインやゴールの処理を続行する
// comment out by Akira, 2024-4-5 // comment out by Akira, 2024-4-5
// skipGps = false; // skipGps = false;
@ -282,7 +305,7 @@ class DestinationController extends GetxController {
); );
*/ */
if (checkinRadious >= lastValidDistance || checkinRadious == -1) { if (checkinRadious >= lastValidDistance || checkinRadious == -1) { // 反応半径内か、距離無視CPなら
indexController.currentDestinationFeature.clear(); indexController.currentDestinationFeature.clear();
indexController.currentDestinationFeature.add(d); indexController.currentDestinationFeature.add(d);
} else { } else {
@ -295,11 +318,14 @@ class DestinationController extends GetxController {
} }
} }
if (isPhotoShoot.value == true) { if (isPhotoShoot.value == true) { // 写真撮影するなら ... isPhotoShoot=True にしてる場所がない。
photos.clear(); debugPrint("isPhotoShoot.value == true ... will camera popup");
if (shouldShowBottomSheet) { photos.clear(); // まず既存の写真をクリア
if (shouldShowBottomSheet) { // ボトムシートを使うべきなら
shouldShowBottomSheet = false; shouldShowBottomSheet = false;
if (d.cp == -1) return; if (d.cp == -1) return; // CPは開始点なら戻る。
// カメラページをポップアップ
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
BoxConstraints.loose(Size(Get.width, Get.height * 0.75)), BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
@ -316,21 +342,28 @@ class DestinationController extends GetxController {
return; return;
} }
// 写真撮影モードでない場合
if (ds.isEmpty) { if (ds.isEmpty) {
debugPrint("* 目的地がない場合 ==> 検知半径=-1の場合");
// print("----- in location popup cp - ${d.cp}----"); // print("----- in location popup cp - ${d.cp}----");
if (d.cp == -1 && DateTime.now().difference(lastGoalAt).inHours >= 24) { if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 24) {
debugPrint("**1: 開始CPで、最後にゴールしてから時間経過していれば、");
chekcs = 1; chekcs = 1;
//start //start
// print("~~~~ calling start ~~~~"); // print("~~~~ calling start ~~~~");
// print("---- in start -----"); print("---- in start -----");
chekcs = 1;
chekcs = 1; // スタート地点で前のゴールから24時間経過
isInCheckin.value = true; isInCheckin.value = true;
isAtStart.value = true; isAtStart.value = true;
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; shouldShowBottomSheet = false; // bottom_sheet を起動させない。
if (d.cp == -1||d.cp==-2||d.cp==0) return; Widget bottomSheet = BottomSheetNew(destination: d);
Widget bottomSheet = BottomSheetNormalPoint(destination: d);
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
@ -339,25 +372,30 @@ class DestinationController extends GetxController {
isScrollControlled: true, isScrollControlled: true,
builder: ((context) => bottomSheet) builder: ((context) => bottomSheet)
).whenComplete(() { ).whenComplete(() {
shouldShowBottomSheet = true; shouldShowBottomSheet = true; // bottom_sheet 起動許可
skipGps = false; skipGps = false;
chekcs = 0; chekcs = 0; // ボトムシートモード=1,
isAtStart.value = false; isAtStart.value = false;
isInCheckin.value = false; isInCheckin.value = false;
}); });
} }
return; return;
} else if (isInRog.value == true && } else if (isInRog.value == true &&
indexController.rogMode.value == 1 && indexController.rogMode.value == 1 &&
d.cp != -1) { (locationAlreadyCheckedIn==null || locationAlreadyCheckedIn==false) &&
d.cp != -1 && d.cp != 0 && d.cp != -2) {
debugPrint("**2: 標準CP まだチェックインしていない。");
// print("----- in location popup checkin cp - ${d.cp}----"); // print("----- in location popup checkin cp - ${d.cp}----");
chekcs = 2; chekcs = 2; // 標準CP
isInCheckin.value = true; isInCheckin.value = true;
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; shouldShowBottomSheet = false;
if (d.cp == -1||d.cp==-2||d.cp==0) return; Widget bottomSheet = BottomSheetNew(destination: d);
Widget bottomSheet = BottomSheetNormalPoint(destination: d);
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
@ -376,36 +414,49 @@ class DestinationController extends GetxController {
} }
} }
// 以降、検知範囲にある場合。
//debugPrint("検知範囲にある場合");
// print("---- location checkin radious ${d.checkin_radious} ----"); // print("---- location checkin radious ${d.checkin_radious} ----");
// print("---- already checked in $locationAlreadyCheckedIn ----"); // print("---- already checked in $locationAlreadyCheckedIn ----");
if ((checkinRadious >= distance || checkinRadious == -1) && if ((checkinRadious >= distance || checkinRadious == -1) &&
locationAlreadyCheckedIn == false && locationAlreadyCheckedIn == false &&
isInRog.value == true) { isInRog.value == true) {
if (autoCheckin) {
debugPrint("* 検知範囲または距離無視CPで、ゲーム中でまだチェックインしていない。");
if (autoCheckin) { // 自動チェックインなら
if (!checkingIn) { if (!checkingIn) {
debugPrint("** 自動チェックインの場合");
//print( //print(
// "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ make checkin ${d.sub_loc_id}@@@@@@@@@@@"); // "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ make checkin ${d.sub_loc_id}@@@@@@@@@@@");
makeCheckin(d, true, ""); makeCheckin(d, true, ""); // チェックインして
if (d.cp != -1) { if (d.cp != -1 && d.cp != -2 && d.cp != 0 ) {
rogainingCounted.value = true; rogainingCounted.value = true; // ゴール用チェックイン済み
} }
skipGps = false; skipGps = false;
} }
return; return; // 戻る
} else { } else {
// それ以外
debugPrint("* 自動チェックイン以外の場合");
// print("--- hidden loc ${d.hidden_location} ----"); // print("--- hidden loc ${d.hidden_location} ----");
// ask for checkin // ask for checkin
if (d.hidden_location != null && if (d.hidden_location != null &&
d.hidden_location == 0 && d.hidden_location == 0 && // 隠しCPフラグ==0 ... 通常CP
isInRog.value == true && isInRog.value == true &&
d.cp != -1) { d.cp != -1 && d.cp != -2 && d.cp != 0) {
// 隠しCPの場合、
debugPrint("**3 通常CPの場合");
chekcs = 3; chekcs = 3;
isInCheckin.value = true; isInCheckin.value = true;
photos.clear(); photos.clear();
// print("--- calling checkin ---"); // print("--- calling checkin ---");
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; shouldShowBottomSheet = false;
if (d.cp == -1) return;
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
BoxConstraints.loose(Size(Get.width, Get.height * 0.75)), BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
@ -422,14 +473,20 @@ class DestinationController extends GetxController {
}); });
} }
return; return;
} else if (isInRog.value == true && d.cp != -1) {
} else if (isInRog.value == true &&
(locationAlreadyCheckedIn==null || locationAlreadyCheckedIn==false) &&
d.cp != -1 && d.cp != -2 && d.cp != 0) {
// 通常CP
debugPrint("**4 通常CP以外の場合....どんな場合?");
chekcs = 4; chekcs = 4;
isInCheckin.value = true; isInCheckin.value = true;
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; shouldShowBottomSheet = false;
if (d.cp == -1||d.cp==-2||d.cp==0) return; Widget bottomSheet = BottomSheetNew(destination: d);
Widget bottomSheet = BottomSheetNormalPoint(destination: d);
await showMaterialModalBottomSheet( await showMaterialModalBottomSheet(
expand: true, expand: true,
@ -453,13 +510,18 @@ class DestinationController extends GetxController {
buyPoint == true && buyPoint == true &&
buyPointCanceled == false && buyPointCanceled == false &&
isInRog.value == true) { isInRog.value == true) {
// チェックイン後で買い物ポイントの場合。
debugPrint("**5 チェックイン後で買い物ポイントの場合");
chekcs = 5; chekcs = 5;
isInCheckin.value = true; isInCheckin.value = true;
photos.clear(); photos.clear();
//print("--- open buy point $buyPointImageAdded ${d.buypoint_image} ----"); //print("--- open buy point $buyPointImageAdded ${d.buypoint_image} ----");
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; shouldShowBottomSheet = false;
if (d.cp == -1) return; if (d.cp == -1 && d.cp != -2 && d.cp != 0) return;
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
BoxConstraints.loose(Size(Get.width, Get.height * 0.75)), BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),
@ -486,14 +548,17 @@ class DestinationController extends GetxController {
// print( // print(
// "==== date diff is ${DateTime.now().difference(last_goal_at).inHours} ===="); // "==== date diff is ${DateTime.now().difference(last_goal_at).inHours} ====");
if (isuserLoggedIn && if (isuserLoggedIn &&
d.cp == -1 && (d.cp == -2 || d.cp == 0 ) && // Goal CP
locationAlreadyCheckedIn && locationAlreadyCheckedIn &&
skip_10s == false) { skip_10s == false) {
//check for rogaining //check for rogaining
if (isAtGoal.value == false && rogainingCounted.value) { if (isAtGoal.value == false && rogainingCounted.value) {
//goal //goal
//print("---- in goal -----"); //print("---- in goal -----");
chekcs = 5;
debugPrint("**5 ゴールで時計撮影の場合");
chekcs = 5; // Goal 時計撮影
isAtGoal.value = true; isAtGoal.value = true;
photos.clear(); photos.clear();
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
@ -514,18 +579,23 @@ class DestinationController extends GetxController {
}); });
} }
return; return;
} else if (isInRog.value == false && } else if (isInRog.value == false &&
indexController.rogMode.value == 1 && indexController.rogMode.value == 1 &&
DateTime.now().difference(lastGoalAt).inHours >= 24) { DateTime.now().difference(lastGoalAt).inHours >= 24) {
//start //start
//print("---- in start -----"); //print("---- in start -----");
chekcs = 6;
debugPrint("**5 スタートの場合で最後のゴールから24時間経過している場合");
chekcs = 6; // start point
isAtStart.value = true; isAtStart.value = true;
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; shouldShowBottomSheet = false;
if (d.cp == -1||d.cp==-2||d.cp==0) return; if (d.cp != -1 && d.cp != 0) return;
Widget bottomSheet = BottomSheetNormalPoint(destination: d); Widget bottomSheet = BottomSheetNew(destination: d);
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
@ -546,6 +616,7 @@ class DestinationController extends GetxController {
} }
//print("==== _chekcs $chekcs ===="); //print("==== _chekcs $chekcs ====");
if (chekcs == 0) { if (chekcs == 0) {
//debugPrint("いずれにも当てはまらないので、処理スキップ");
skipGps = false; skipGps = false;
} }
return; return;
@ -639,7 +710,7 @@ class DestinationController extends GetxController {
// //
Future<void> callforCheckin(Destination d) async { Future<void> callforCheckin(Destination d) async {
bool autoCheckin = d.auto_checkin == 0 ? false : true; bool autoCheckin = d.auto_checkin == 0 ? false : true;
//print("---- f- checkin ${d.sub_loc_id} ----"); print("---- f- checkin ${d.sub_loc_id} ----");
if (autoCheckin) { if (autoCheckin) {
if (!checkingIn) { if (!checkingIn) {
makeCheckin(d, true, ""); makeCheckin(d, true, "");
@ -692,7 +763,7 @@ class DestinationController extends GetxController {
rogainingCounted.value = true; rogainingCounted.value = true;
chekcs = 0; chekcs = 0;
isInCheckin.value = false; isInCheckin.value = false;
Get.back(); //Get.back();
}); });
} else { } else {
skipGps = false; skipGps = false;
@ -717,9 +788,10 @@ class DestinationController extends GetxController {
// GPSデータをデータベースに追加する関数です。 // GPSデータをデータベースに追加する関数です。
// //
Future<void> addGPStoDB(double la, double ln, {isCheckin = 0}) async { Future<void> addGPStoDB(double la, double ln, {isCheckin = 0}) async {
//print("in addGPStoDB ${indexController.currentUser}"); //debugPrint("in addGPStoDB ${indexController.currentUser}");
try { try {
GpsDatabaseHelper db = GpsDatabaseHelper.instance; GpsDatabaseHelper db = GpsDatabaseHelper.instance;
if(indexController.currentUser.length>0){
final team_name = indexController.currentUser[0]["user"]['team_name']; final team_name = indexController.currentUser[0]["user"]['team_name'];
final event_code = indexController.currentUser[0]["user"]["event_code"]; final event_code = indexController.currentUser[0]["user"]["event_code"];
GpsData gps_data = GpsData( GpsData gps_data = GpsData(
@ -731,6 +803,7 @@ class DestinationController extends GetxController {
is_checkin: isCheckin, is_checkin: isCheckin,
created_at: DateTime.now().millisecondsSinceEpoch); created_at: DateTime.now().millisecondsSinceEpoch);
var res = await db.insertGps(gps_data); var res = await db.insertGps(gps_data);
}
} catch (err) { } catch (err) {
print("errr ready gps ${err}"); print("errr ready gps ${err}");
return; return;
@ -752,6 +825,8 @@ class DestinationController extends GetxController {
game_started = true; game_started = true;
try { try {
// ここで、エラー
if( indexController.locations.length>0 ) {
indexController.locations[0].features.forEach((fs) async { indexController.locations[0].features.forEach((fs) async {
GeoJSONMultiPoint mp = fs!.geometry as GeoJSONMultiPoint; GeoJSONMultiPoint mp = fs!.geometry as GeoJSONMultiPoint;
LatLng pt = LatLng(mp.coordinates[0][1], mp.coordinates[0][0]); LatLng pt = LatLng(mp.coordinates[0][1], mp.coordinates[0][0]);
@ -772,6 +847,7 @@ class DestinationController extends GetxController {
if (gps_push_started == false) { if (gps_push_started == false) {
unawaited(pushGPStoServer()); unawaited(pushGPStoServer());
} }
}
//print("--- 123 ---- $skip_gps----"); //print("--- 123 ---- $skip_gps----");
} catch (e) { } catch (e) {
print("An error occurred: $e"); print("An error occurred: $e");
@ -987,7 +1063,6 @@ class DestinationController extends GetxController {
currentLat = position.latitude; currentLat = position.latitude;
currentLon = position.longitude; currentLon = position.longitude;
okToUseGPS = true; okToUseGPS = true;
} else { } else {
// 信号強度が低い場合、最後に取得した高いまたは中程度の位置情報を使用 // 信号強度が低い場合、最後に取得した高いまたは中程度の位置情報を使用
// 但し、最初から高精度のものがない場合、どうするか? // 但し、最初から高精度のものがない場合、どうするか?
@ -1025,20 +1100,31 @@ class DestinationController extends GetxController {
LatLng(prevLat, prevLon) LatLng(prevLat, prevLon)
); );
Duration difference = lastGPSCollectedTime.difference(DateTime.now()).abs(); Duration difference = lastGPSCollectedTime.difference(DateTime.now())
.abs();
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過普通に歩くスピード // 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過普通に歩くスピード
if (difference.inSeconds >= 10 || distanceToDest >= 10) { if (difference.inSeconds >= 10 || distanceToDest >= 10) {
// print( // print(
// "^^^^^^^^ GPS data collected ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}, ^^^ ${position.latitude}, ${position.longitude}"); // "^^^^^^^^ GPS data collected ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}, ^^^ ${position.latitude}, ${position.longitude}");
LogManager().addLog( LogManager().addLog(
"GPS : $currentLat, $currentLon - ${DateTime.now().hour}:${DateTime.now().minute}:${DateTime.now().second}:${DateTime.now().microsecond}"); "GPS : $currentLat, $currentLon - ${DateTime
.now()
.hour}:${DateTime
.now()
.minute}:${DateTime
.now()
.second}:${DateTime
.now()
.microsecond}");
if (isInRog.value) { if (isInRog.value) {
await addGPStoDB(position.latitude, position.longitude); await addGPStoDB(position.latitude, position.longitude);
lastGPSCollectedTime = DateTime.now(); lastGPSCollectedTime = DateTime.now();
} }
} }
} }
} catch(e) {
debugPrint("Error: ${e}");
} finally { } finally {
/* Akira , 2024-4-5 /* Akira , 2024-4-5
if (position != null && if (position != null &&

View File

@ -12,10 +12,10 @@ import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart'; import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/utils/text_util.dart'; import 'package:rogapp/utils/text_util.dart';
import 'package:rogapp/widgets/base_layer_widget.dart'; import 'package:rogapp/widgets/base_layer_widget.dart';
//import 'package:rogapp/widgets/bottom_sheet_new.dart'; import 'package:rogapp/widgets/bottom_sheet_new.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart';
// FlutterMapウィジェットを使用して、地図を表示します。 // FlutterMapウィジェットを使用して、地図を表示します。
// IndexControllerから目的地のリストを取得し、マーカーとしてマップ上に表示します。 // IndexControllerから目的地のリストを取得し、マーカーとしてマップ上に表示します。
@ -70,7 +70,8 @@ class DestinationMapPage extends StatelessWidget {
indexController.currentDestinationFeature.add(d); indexController.currentDestinationFeature.add(d);
//indexController.getAction(); //indexController.getAction();
Widget bottomSheet; Widget bottomSheet = BottomSheetNew(destination: d);
/*
if (d.cp == -1 || d.cp == 0) { if (d.cp == -1 || d.cp == 0) {
bottomSheet = BottomSheetStart(destination: d); bottomSheet = BottomSheetStart(destination: d);
} else if (d.cp == -2 || d.cp == 0) { } else if (d.cp == -2 || d.cp == 0) {
@ -78,6 +79,7 @@ class DestinationMapPage extends StatelessWidget {
} else { } else {
bottomSheet = BottomSheetNormalPoint(destination: d); bottomSheet = BottomSheetNormalPoint(destination: d);
} }
*/
showModalBottomSheet( showModalBottomSheet(
context: Get.context!, context: Get.context!,

View File

@ -40,7 +40,7 @@ class _HistoryPageState extends State<HistoryPage> {
} else if (snapshot.hasData) { } else if (snapshot.hasData) {
final dests = snapshot.data; final dests = snapshot.data;
if (dests!.isNotEmpty) { if (dests!.isNotEmpty) {
//print("----- history -----"); debugPrint("----- history -----");
return SizedBox( return SizedBox(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,

View File

@ -109,7 +109,7 @@ class IndexPage extends GetView<IndexController> {
return DropdownButton<String>( return DropdownButton<String>(
value: locationController.getSimulatedSignalStrength(), value: locationController.getSimulatedSignalStrength(),
onChanged: (value) { onChanged: (value) {
debugPrint("DropDown changed!"); //debugPrint("DropDown changed!");
locationController.setSimulatedSignalStrength(value!); locationController.setSimulatedSignalStrength(value!);
}, },
items: ['low', 'medium', 'high', 'real'] items: ['low', 'medium', 'high', 'real']

View File

@ -6,9 +6,10 @@ import 'package:rogapp/model/destination.dart';
import 'package:rogapp/pages/destination/destination_controller.dart'; import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart'; import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/pages/search/search_controller.dart'; import 'package:rogapp/pages/search/search_controller.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart';
import 'package:rogapp/widgets/bottom_sheet_new.dart';
class SearchPage extends StatelessWidget { class SearchPage extends StatelessWidget {
SearchPage({Key? key}) : super(key: key); SearchPage({Key? key}) : super(key: key);
@ -78,7 +79,8 @@ class SearchPage extends StatelessWidget {
destinationController.festuretoDestination(suggestion); destinationController.festuretoDestination(suggestion);
Get.back(); Get.back();
Widget bottomSheet; Widget bottomSheet = BottomSheetNew(destination: des);
/*
if (des.cp == -1 || des.cp == 0) { if (des.cp == -1 || des.cp == 0) {
bottomSheet = BottomSheetStart(destination: des); bottomSheet = BottomSheetStart(destination: des);
} else if (des.cp == -2 || des.cp == 0) { } else if (des.cp == -2 || des.cp == 0) {
@ -86,6 +88,7 @@ class SearchPage extends StatelessWidget {
} else { } else {
bottomSheet = BottomSheetNormalPoint(destination: des); bottomSheet = BottomSheetNormalPoint(destination: des);
} }
*/
showModalBottomSheet( showModalBottomSheet(
constraints: constraints:
BoxConstraints.loose(Size(Get.width, Get.height * 0.75)), BoxConstraints.loose(Size(Get.width, Get.height * 0.75)),

View File

@ -9,6 +9,7 @@ class SubPerfPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("SubPerfPage ---->");
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("Select Sub Perfecture"), title: const Text("Select Sub Perfecture"),

View File

@ -5,6 +5,7 @@ import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
//import 'package:rogapp/widgets/debug_widget.dart'; //import 'package:rogapp/widgets/debug_widget.dart';
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart'; import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
import 'package:rogapp/pages/destination/destination_controller.dart';
// LocationControllerクラスは、GetxControllerを継承したクラスであり、位置情報の管理を担当しています。 // LocationControllerクラスは、GetxControllerを継承したクラスであり、位置情報の管理を担当しています。
// LocationControllerは以下の機能を提供しています。 // LocationControllerは以下の機能を提供しています。
@ -66,7 +67,7 @@ class LocationController extends GetxController {
// シミュレートされた信号強度を取得するための関数 // シミュレートされた信号強度を取得するための関数
String getSimulatedSignalStrength() { String getSimulatedSignalStrength() {
debugPrint("strength : ${_simulatedSignalStrength.value}"); //debugPrint("strength : ${_simulatedSignalStrength.value}");
return _simulatedSignalStrength.value; return _simulatedSignalStrength.value;
} }
@ -269,6 +270,11 @@ class LocationController extends GetxController {
isGpsSignalWeak = false; isGpsSignalWeak = false;
} }
final DestinationController destinationController = Get.find<DestinationController>();
// ロゲ開始前、終了後、GPS=low の場合は更新しない。
//
if (destinationController.isInRog.value && isGpsSignalWeak == false) {
final adjustedLocation = adjustCurrentLocation(position); final adjustedLocation = adjustCurrentLocation(position);
if (adjustedLocation != null) { if (adjustedLocation != null) {
final locationMarkerPosition = LocationMarkerPosition( final locationMarkerPosition = LocationMarkerPosition(
@ -285,6 +291,10 @@ class LocationController extends GetxController {
//forceUpdateLocation(Position? position); //forceUpdateLocation(Position? position);
} }
//}else{
// debugPrint("GPS処理対象外");
}
}, },
onError: (e) { onError: (e) {
// エラーが発生した場合、locationMarkerPositionStreamControllerにエラーを追加します。 // エラーが発生した場合、locationMarkerPositionStreamControllerにエラーを追加します。
@ -335,6 +345,7 @@ class LocationController extends GetxController {
void handleLocationUpdate(LocationMarkerPosition? position) async { void handleLocationUpdate(LocationMarkerPosition? position) async {
if (position != null) { if (position != null) {
//debugPrint("position = ${position}");
/* /*
currentPosition.value = position; currentPosition.value = position;
final locationMarkerPosition = LocationMarkerPosition( final locationMarkerPosition = LocationMarkerPosition(

View File

@ -128,14 +128,13 @@ class BottomSheetNew extends GetView<BottomSheetController> {
// ボタンがタップされたときの処理も含まれています。 // ボタンがタップされたときの処理も含まれています。
// //
Widget getActionButton(BuildContext context, Destination destination) { Widget getActionButton(BuildContext context, Destination destination) {
assert(() { /*
print("getActionButton ${destinationController.rogainingCounted.value}"); debugPrint("getActionButton ${destinationController.rogainingCounted.value}");
print("getActionButton ${destinationController.distanceToStart()}"); debugPrint("getActionButton ${destinationController.distanceToStart()}");
print("getActionButton ${destination.cp}"); debugPrint("getActionButton ${destination.cp}");
print("getActionButton ${DestinationController.ready_for_goal}"); debugPrint("getActionButton ${DestinationController.ready_for_goal}");
return true;
}());
// ...2024-04-03 Akira デバッグモードのみ出力するようにした。 // ...2024-04-03 Akira デバッグモードのみ出力するようにした。
*/
Destination cdest = destinationController Destination cdest = destinationController
.festuretoDestination(indexController.currentFeature[0]); .festuretoDestination(indexController.currentFeature[0]);
@ -176,7 +175,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
} }
: null, : null,
child: const Text( child: const Text(
"ロゲイニングを終える", "ロゲゴール",
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
)); ));
} else if (distanceToDest <= } else if (distanceToDest <=
@ -186,7 +185,26 @@ class BottomSheetNew extends GetView<BottomSheetController> {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.secondary, backgroundColor: Theme.of(context).colorScheme.secondary,
), ),
onPressed: () async { onPressed: isAlreadyCheckedIn == true
? null
: () async {
try{
Get.back();
await destinationController.callforCheckin(destination);
} catch (e) {
// エラーハンドリング
Get.snackbar(
'Error',
'An error occurred while processing check-in.',
backgroundColor: Colors.red,
colorText: Colors.white,
duration: Duration(seconds: 3),
);
// 必要に応じてエラーログを記録
print('Error processing check-in: $e');
}
},
/*
// Check conditions to show confirmation dialog // Check conditions to show confirmation dialog
if (destinationController.isInRog.value == false && if (destinationController.isInRog.value == false &&
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5 (destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
@ -239,6 +257,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
return; return;
} }
}, },
*/
child: Text( child: Text(
destination.cp == -1 && destination.cp == -1 &&
destinationController.isInRog.value == false && destinationController.isInRog.value == false &&
@ -251,7 +270,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
? "ゲーム中" ? "ゲーム中"
: destinationController.isInRog.value == true : destinationController.isInRog.value == true
? "チェックイン" ? "チェックイン"
: "始まっていない", : "ロゲは始まっていません",
style: TextStyle(color: Theme.of(context).colorScheme.onSecondary), style: TextStyle(color: Theme.of(context).colorScheme.onSecondary),
), ),
); );

View File

@ -5,9 +5,10 @@ import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart'; import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/utils/const.dart'; import 'package:rogapp/utils/const.dart';
import 'package:rogapp/utils/database_helper.dart'; import 'package:rogapp/utils/database_helper.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart';
import 'package:rogapp/widgets/bottom_sheet_new.dart';
import 'package:timeline_tile/timeline_tile.dart'; import 'package:timeline_tile/timeline_tile.dart';
class DestinationWidget extends StatelessWidget { class DestinationWidget extends StatelessWidget {
@ -147,8 +148,8 @@ class DestinationWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
//print( print(
// "------ destination widget------ ${destinationController.destinationCount.value} ----------"); "------ destination widget------ ${destinationController.destinationCount.value} ----------");
return Obx(() => Stack( return Obx(() => Stack(
children: [ children: [
@ -194,7 +195,8 @@ class DestinationWidget extends StatelessWidget {
// "--- ndexController.currentDestinationFeature ----- ${indexController.currentDestinationFeature[0].name} ----"); // "--- ndexController.currentDestinationFeature ----- ${indexController.currentDestinationFeature[0].name} ----");
//indexController.getAction(); //indexController.getAction();
Widget bottomSheet; Widget bottomSheet = BottomSheetNew(destination: fs);
/*
if (fs.cp == -1 || fs.cp == 0) { if (fs.cp == -1 || fs.cp == 0) {
bottomSheet = BottomSheetStart(destination: fs); bottomSheet = BottomSheetStart(destination: fs);
} else if (fs.cp == -2 || fs.cp == 0) { } else if (fs.cp == -2 || fs.cp == 0) {
@ -202,6 +204,7 @@ class DestinationWidget extends StatelessWidget {
} else { } else {
bottomSheet = BottomSheetNormalPoint(destination: fs); bottomSheet = BottomSheetNormalPoint(destination: fs);
} }
*/
showModalBottomSheet( showModalBottomSheet(
constraints: BoxConstraints.loose( constraints: BoxConstraints.loose(

View File

@ -20,7 +20,7 @@ class GpsSignalStrengthIndicator extends StatelessWidget {
// final LocationController locationController = Get.find<LocationController>(); // final LocationController locationController = Get.find<LocationController>();
return Obx(() { return Obx(() {
String signalStrength = locationController.latestSignalStrength.value; String signalStrength = locationController.latestSignalStrength.value;
debugPrint("GpsSignalStrengthIndicator : signalStrength=${signalStrength}"); //debugPrint("GpsSignalStrengthIndicator : signalStrength=${signalStrength}");
IconData iconData; IconData iconData;
Color backgroundColor; Color backgroundColor;
String text; String text;

View File

@ -6,9 +6,10 @@ import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart'; import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/services/maxtrix_service.dart'; import 'package:rogapp/services/maxtrix_service.dart';
import 'package:rogapp/utils/const.dart'; import 'package:rogapp/utils/const.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_start.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_goal.dart';
import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart'; //import 'package:rogapp/widgets/bottom_sheets/bottom_sheet_normal_point.dart';
import 'package:rogapp/widgets/bottom_sheet_new.dart';
class ListWidget extends StatefulWidget { class ListWidget extends StatefulWidget {
const ListWidget({Key? key}) : super(key: key); const ListWidget({Key? key}) : super(key: key);
@ -102,6 +103,7 @@ class _ListWidgetState extends State<ListWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("_ListWidgetState");
return Obx( return Obx(
() => indexController.locations.isNotEmpty () => indexController.locations.isNotEmpty
? RefreshIndicator( ? RefreshIndicator(
@ -130,7 +132,8 @@ class _ListWidgetState extends State<ListWidget> {
destinationController.festuretoDestination(gf); destinationController.festuretoDestination(gf);
changeCurrentFeature(gf); changeCurrentFeature(gf);
Widget bottomSheet; Widget bottomSheet = BottomSheetNew(destination: des);
/*
if (des.cp == -1 || des.cp == 0) { if (des.cp == -1 || des.cp == 0) {
bottomSheet = BottomSheetStart(destination: des); bottomSheet = BottomSheetStart(destination: des);
} else if (des.cp == -2 || des.cp == 0) { } else if (des.cp == -2 || des.cp == 0) {
@ -138,6 +141,7 @@ class _ListWidgetState extends State<ListWidget> {
} else { } else {
bottomSheet = BottomSheetNormalPoint(destination: des); bottomSheet = BottomSheetNormalPoint(destination: des);
} }
*/
showModalBottomSheet( showModalBottomSheet(
constraints: BoxConstraints.loose( constraints: BoxConstraints.loose(

View File

@ -25,7 +25,8 @@ class MapWidget extends StatefulWidget {
State<MapWidget> createState() => _MapWidgetState(); State<MapWidget> createState() => _MapWidgetState();
} }
class _MapWidgetState extends State<MapWidget> { class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
//class _MapWidgetState extends State<MapWidget> {
final IndexController indexController = Get.find<IndexController>(); final IndexController indexController = Get.find<IndexController>();
final DestinationController destinationController = final DestinationController destinationController =
Get.find<DestinationController>(); Get.find<DestinationController>();
@ -46,6 +47,11 @@ class _MapWidgetState extends State<MapWidget> {
_startIdleTimer(); _startIdleTimer();
mapController = MapController(); mapController = MapController();
indexController.mapController = mapController; indexController.mapController = mapController;
// added by Akira
WidgetsBinding.instance.addObserver(this);
_startIdleTimer();
//_initMarkers(); //_initMarkers();
// indexController.mapController = MapController(initCompleter: mapControllerCompleter); // indexController.mapController = MapController(initCompleter: mapControllerCompleter);
@ -54,23 +60,38 @@ class _MapWidgetState extends State<MapWidget> {
@override @override
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); // added
mapController?.dispose(); mapController?.dispose();
_timer?.cancel(); _timer?.cancel();
super.dispose(); super.dispose();
} }
// added by Akira
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_resetTimer();
}
}
// _centerMapOnUser を10秒間でコール
void _startIdleTimer() { void _startIdleTimer() {
_timer = Timer(const Duration(milliseconds: (1000 * 10)), _centerMapOnUser); _timer = Timer(const Duration(milliseconds: (1000 * 10)), _centerMapOnUser);
} }
// タイマーをリセットして_startIdleTimer をコール
void _resetTimer() { void _resetTimer() {
_timer?.cancel(); _timer?.cancel();
_startIdleTimer(); _startIdleTimer();
} }
// マッぷを現在位置を中心にする。
void _centerMapOnUser() { void _centerMapOnUser() {
if (mounted) {
destinationController.centerMapToCurrentLocation(); destinationController.centerMapToCurrentLocation();
} }
}
Future<void> _initMarkers() async { Future<void> _initMarkers() async {
List<Marker> markers = await _getMarkers(); List<Marker> markers = await _getMarkers();
@ -172,8 +193,7 @@ class _MapWidgetState extends State<MapWidget> {
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
isDismissible: true, isDismissible: true,
builder: ((context) => BottomSheetNew( builder: ((context) => BottomSheetNew(destination: des, isAlreadyCheckedIn: value.isNotEmpty)),
destination: des, isAlreadyCheckedIn: value.isNotEmpty)),
).whenComplete(() { ).whenComplete(() {
destinationController.shouldShowBottomSheet = true; destinationController.shouldShowBottomSheet = true;
destinationController.skipGps = false; destinationController.skipGps = false;
@ -378,7 +398,7 @@ class _MapWidgetState extends State<MapWidget> {
stream: locationController.locationMarkerPositionStream, stream: locationController.locationMarkerPositionStream,
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
print("====== Not display current marker"); debugPrint("====== Not display current marker");
} }
return Container(); return Container();
}, },

View File

@ -1056,6 +1056,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.1" version: "6.1.1"
qr_code_scanner:
dependency: "direct main"
description:
name: qr_code_scanner
sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd
url: "https://pub.dev"
source: hosted
version: "1.0.1"
queue: queue:
dependency: transitive dependency: transitive
description: description:

View File

@ -86,6 +86,7 @@ dependencies:
image_gallery_saver: ^2.0.3 image_gallery_saver: ^2.0.3
flutter_riverpod: ^2.5.1 flutter_riverpod: ^2.5.1
http: ^1.1.0 http: ^1.1.0
qr_code_scanner: ^1.0.1
flutter_icons: flutter_icons:
android: true android: true