From bdf6dd3c048c96f434340096c3245850323930ff Mon Sep 17 00:00:00 2001 From: Akira Date: Wed, 7 Aug 2024 21:17:13 +0900 Subject: [PATCH] =?UTF-8?q?Fixed=20Camera=E3=81=A7=E3=82=AF=E3=83=A9?= =?UTF-8?q?=E3=83=83=E3=82=B7=E3=83=A5=E3=80=81=E6=97=A5=E4=BB=98=E3=82=BA?= =?UTF-8?q?=E3=83=AC=E3=80=81=E9=81=A0=E3=81=8F=E3=81=AE=E3=83=81=E3=82=A7?= =?UTF-8?q?=E3=83=83=E3=82=AF=E3=83=9D=E3=82=A4=E3=83=B3=E3=83=88=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=80=81=EF=BC=91=E6=97=A5=EF=BC=91=E5=9B=9E=E3=81=AE?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=83=86=E3=82=AF=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Runner.xcodeproj/project.pbxproj | 26 ++-- .../destination/destination_controller.dart | 6 +- lib/pages/index/index_controller.dart | 64 ++++++++++ lib/services/api_service.dart | 25 ++++ lib/services/location_service.dart | 8 +- lib/widgets/bottom_sheet_new.dart | 117 ++++++++++++++++++ pubspec.yaml | 2 +- 7 files changed, 227 insertions(+), 21 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7477237..3da5346 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -398,11 +398,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 493; + CURRENT_PROJECT_VERSION = 494; DEVELOPMENT_TEAM = UMNEWT25JR; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NAME = 4.8.13; - FLUTTER_BUILD_NUMBER = 493; + FLUTTER_BUILD_NAME = 4.8.14; + FLUTTER_BUILD_NUMBER = 494; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "岐阜ナビ"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.healthcare-fitness"; @@ -411,7 +411,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.8.13; + MARKETING_VERSION = 4.8.14; PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunavi; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -539,11 +539,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 493; + CURRENT_PROJECT_VERSION = 494; DEVELOPMENT_TEAM = UMNEWT25JR; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NAME = 4.8.13; - FLUTTER_BUILD_NUMBER = 493; + FLUTTER_BUILD_NAME = 4.8.14; + FLUTTER_BUILD_NUMBER = 494; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "岐阜ナビ"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.healthcare-fitness"; @@ -552,7 +552,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.8.13; + MARKETING_VERSION = 4.8.14; PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunavi; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -571,11 +571,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 493; + CURRENT_PROJECT_VERSION = 494; DEVELOPMENT_TEAM = UMNEWT25JR; ENABLE_BITCODE = NO; - FLUTTER_BUILD_NAME = 4.8.13; - FLUTTER_BUILD_NUMBER = 493; + FLUTTER_BUILD_NAME = 4.8.14; + FLUTTER_BUILD_NUMBER = 494; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "岐阜ナビ"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.healthcare-fitness"; @@ -584,7 +584,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.8.13; + MARKETING_VERSION = 4.8.14; PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunavi; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/lib/pages/destination/destination_controller.dart b/lib/pages/destination/destination_controller.dart index 76f2317..7345970 100644 --- a/lib/pages/destination/destination_controller.dart +++ b/lib/pages/destination/destination_controller.dart @@ -431,7 +431,7 @@ class DestinationController extends GetxController { debugPrint("* 目的地がない場合 ==> 検知半径=-1の場合"); // print("----- in location popup cp - ${d.cp}----"); - if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 24) { + if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 10) { debugPrint("**1: 開始CPで、最後にゴールしてから24時間経過していれば、"); chekcs = 1; @@ -673,11 +673,11 @@ class DestinationController extends GetxController { } else if (isInRog.value == false && indexController.rogMode.value == 1 && - DateTime.now().difference(lastGoalAt).inHours >= 24) { + DateTime.now().difference(lastGoalAt).inHours >= 10) { //start //print("---- in start -----"); - debugPrint("**5 スタートの場合で最後のゴールから24時間経過している場合"); + debugPrint("**5 スタートの場合で最後のゴールから10時間経過している場合"); chekcs = 6; // start point diff --git a/lib/pages/index/index_controller.dart b/lib/pages/index/index_controller.dart index 2f5afa6..f8ab374 100644 --- a/lib/pages/index/index_controller.dart +++ b/lib/pages/index/index_controller.dart @@ -23,10 +23,14 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:rogapp/services/api_service.dart'; import 'package:rogapp/model/user.dart'; +import 'package:rogapp/model/rog.dart'; + import 'package:rogapp/main.dart'; import 'package:rogapp/widgets/helper_dialog.dart'; +import 'package:timezone/timezone.dart' as tz; +import 'package:timezone/data/latest.dart' as tz; class IndexController extends GetxController with WidgetsBindingObserver { List locations = [].obs; @@ -66,6 +70,7 @@ class IndexController extends GetxController with WidgetsBindingObserver { //late final ApiService _apiService; final ApiService _apiService = Get.find(); + final DatabaseHelper _dbHelper = DatabaseHelper.instance; // mode = 0 is map mode, mode = 1 list mode var mode = 0.obs; @@ -237,6 +242,7 @@ class IndexController extends GetxController with WidgetsBindingObserver { print('IndexController onInit called'); // デバッグ用の出力を追加 + tz.initializeTimeZones(); //teamController = Get.find(); } @@ -562,6 +568,10 @@ class IndexController extends GetxController with WidgetsBindingObserver { saveToDevice(currentUser[0]["token"]); } isLoading.value = false; + + // ユーザーのイベント情報を取得 + await fetchUserEventInfo(); + loadLocationsBound( currentUser[0]["user"]["event_code"]); if (currentUser.isNotEmpty) { rogMode.value = 0; @@ -575,6 +585,58 @@ class IndexController extends GetxController with WidgetsBindingObserver { Get.toNamed(AppPages.INDEX); } + Future fetchUserEventInfo() async { + try { + final List entries = await _apiService.getEntries(); + + if (entries.isNotEmpty) { + final Entry latestEntry = entries.last; + + final tokyo = tz.getLocation('Asia/Tokyo'); + final eventDate = latestEntry.date!.toUtc(); + //final eventDate = tz.TZDateTime.from(utcDate, tokyo); + + final eventDateOnly = tz.TZDateTime(tokyo, eventDate.year, eventDate.month, eventDate.day); + + currentUser[0]['user']['event_date'] = eventDateOnly.toIso8601String().split('T')[0]; + currentUser[0]['user']['event_code'] = latestEntry.event.eventName; + currentUser[0]['user']['team_name'] = latestEntry.team.teamName; + currentUser[0]['user']['group'] = latestEntry.team.category.categoryName; + currentUser[0]['user']['zekken_number'] = latestEntry.zekkenNumber; + + // 最後のゴール日時を取得 + final lastGoalTime = await getLastGoalTime(); + currentUser[0]['user']['last_goal_time'] = lastGoalTime?.toIso8601String(); + + print('Updated user event info: ${currentUser[0]['user']}'); + } else { + print('No entries found for the user'); + _clearUserEventInfo(); + } + } catch (e) { + print('Error fetching user event info: $e'); + _clearUserEventInfo(); + } + } + + Future getLastGoalTime() async { + try { + final userId = currentUser[0]['user']['id']; + return await _apiService.getLastGoalTime(userId); + } catch (e) { + print('Error getting last goal time: $e'); + } + return null; + } + + void _clearUserEventInfo() { + currentUser[0]['user']['event_date'] = null; + currentUser[0]['user']['event_code'] = null; + currentUser[0]['user']['team_name'] = null; + currentUser[0]['user']['group'] = null; + currentUser[0]['user']['zekken_number'] = null; + } + Future fetchTeamData() async { try { Get.put(TeamController()); @@ -589,6 +651,8 @@ class IndexController extends GetxController with WidgetsBindingObserver { } } + + loadUserDetailsForToken(String token) async { AuthService.userForToken(token).then((value) { print("----token val-- $value ------"); diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 63bf91c..1702d90 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -665,4 +665,29 @@ class ApiService extends GetxService{ return false; } } + + Future getLastGoalTime(int userId) async { + try { + final response = await http.get( + Uri.parse('$baseUrl/users/$userId/last-goal/'), + headers: { + 'Authorization': 'Token $token', + 'Content-Type': 'application/json; charset=UTF-8', + }, + ); + + if (response.statusCode == 200) { + final decodedResponse = json.decode(utf8.decode(response.bodyBytes)); + if (decodedResponse['last_goal_time'] != null) { + return DateTime.parse(decodedResponse['last_goal_time']).toLocal(); + } + } else { + print('Failed to get last goal time. Status code: ${response.statusCode}'); + } + } catch (e) { + print('Error in getLastGoalTime: $e'); + } + return null; + } + } \ No newline at end of file diff --git a/lib/services/location_service.dart b/lib/services/location_service.dart index 60f069b..c12712f 100644 --- a/lib/services/location_service.dart +++ b/lib/services/location_service.dart @@ -122,10 +122,10 @@ class LocationService { var grp = event_code; //indexController.currentUser[0]['user']['event_code']; print("Group=$grp"); url = - '$serverUrl/api/inbound?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat'; + '$serverUrl/api/inbound2?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat'; } else { url = - '$serverUrl/api/inbound?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat'; + '$serverUrl/api/inbound2?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat'; } } else { if (indexController.currentUser.isNotEmpty) { @@ -134,10 +134,10 @@ class LocationService { var grp = indexController.currentUser[0]['user']['event_code']; print("-------- requested user group $grp -------------"); url = - '$serverUrl/api/inbound?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4'; + '$serverUrl/api/inbound2?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4'; } else { url = - '$serverUrl/api/inbound?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4'; + '$serverUrl/api/inbound2?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4'; } print('++++++++$url'); final response = await http.get( diff --git a/lib/widgets/bottom_sheet_new.dart b/lib/widgets/bottom_sheet_new.dart index f663d35..e738270 100644 --- a/lib/widgets/bottom_sheet_new.dart +++ b/lib/widgets/bottom_sheet_new.dart @@ -21,6 +21,10 @@ import 'package:rogapp/widgets/bottom_sheet_controller.dart'; import 'package:rogapp/widgets/debug_widget.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:timezone/timezone.dart' as tz; +import 'package:timezone/data/latest.dart' as tz; +import 'package:get/get.dart'; + // BottomSheetNewは、StatelessWidgetを継承したクラスで、目的地の詳細情報を表示するボトムシートのUIを構築します。 // コンストラクタでは、destination(目的地オブジェクト)とisAlreadyCheckedIn(すでにチェックイン済みかどうかのフラグ)を受け取ります。 // buildメソッドでは、detailsSheetメソッドを呼び出して、目的地の詳細情報を表示します。 @@ -38,6 +42,15 @@ class BottomSheetNew extends GetView { final RxBool isButtonDisabled = false.obs; + static bool _timezoneInitialized = false; + + void _initializeTimezone() { + if (!_timezoneInitialized) { + tz.initializeTimeZones(); + _timezoneInitialized = true; + } + } + // 目的地の画像を取得するためのメソッドです。 // indexController.rogModeの値に基づいて、適切な画像を返します。画像が見つからない場合は、デフォルトの画像を返します。 // @@ -146,6 +159,7 @@ class BottomSheetNew extends GetView { // ボタンがタップされたときの処理も含まれています。 // Widget getActionButton(BuildContext context, Destination destination) { + _initializeTimezone(); // タイムゾーンの初期化 /* debugPrint("getActionButton ${destinationController.rogainingCounted.value}"); debugPrint("getActionButton ${destinationController.distanceToStart()}"); @@ -181,6 +195,51 @@ class BottomSheetNew extends GetView { onPressed: destinationController.isInRog.value ? null : () async { + // Check if the event is for today + bool isEventToday = await checkIfEventIsToday(); + if (!isEventToday) { + Get.dialog( + AlertDialog( + title: Text("警告"), + content: Text("参加したエントリーは別日のものですので、ロゲの開始はできません。当日のエントリーを選択するか、エントリーを今日に変更してからロゲ開始を行ってください。"), + actions: [ + TextButton( + child: Text("OK"), + onPressed: () { + Get.back(); // Close the dialog + Get.back(); // Close the bottom sheet + }, + ), + ], + ), + ); + return; + } + + // Check if user has already completed a rogaining event today + bool hasCompletedToday = await checkIfCompletedToday(); + if (hasCompletedToday) { + Get.dialog( + AlertDialog( + title: Text("警告"), + content: Text("すでにロゲの参加を行いゴールをしています。ロゲは1日1回に制限されています。ご了承ください。"), + actions: [ + TextButton( + child: Text("OK"), + onPressed: () { + Get.back(); // Close the dialog + Get.back(); // Close the bottom sheet + }, + ), + ], + ), + ); + return; + } + + + + destinationController.isInRog.value = true; @@ -259,6 +318,8 @@ class BottomSheetNew extends GetView { (destination.cp == 0 || destination.cp == -2|| destination.cp == -1) && DestinationController.ready_for_goal == true ? () async { + + destinationController.isAtGoal.value = true; destinationController.photos.clear(); await showModalBottomSheet( @@ -331,6 +392,62 @@ class BottomSheetNew extends GetView { return Container(); } + // Add these new methods to check event date and completion status + Future checkIfEventIsToday() async { + try { + final now = tz.TZDateTime.now(tz.getLocation('Asia/Tokyo')); + + // Null チェックと安全な操作を追加 + final userEventDate = indexController.currentUser.isNotEmpty && + indexController.currentUser[0] != null && + indexController.currentUser[0]["user"] != null + ? indexController.currentUser[0]["user"]["event_date"] + : null; + + if (userEventDate == null || userEventDate.toString().isEmpty) { + print('Event date is null or empty'); + return false; // イベント日付が設定されていない場合は false を返す + } + + final eventDate = tz.TZDateTime.from( + DateTime.parse(userEventDate.toString()), + tz.getLocation('Asia/Tokyo') + ); + + return eventDate.year == now.year && + eventDate.month == now.month && + eventDate.day == now.day; + } catch (e) { + print('Error in checkIfEventIsToday: $e'); + // エラーが発生した場合はダイアログを表示 + Get.dialog( + AlertDialog( + title: Text('エラー'), + content: Text('イベント日付の確認中にエラーが発生しました。\nアプリを再起動するか、管理者にお問い合わせください。'), + actions: [ + TextButton( + child: Text('OK'), + onPressed: () => Get.back(), + ), + ], + ), + ); + return false; // エラーが発生した場合は false を返す + } + + } + + Future checkIfCompletedToday() async { + final IndexController indexController = Get.find(); + final lastGoalTime = await indexController.getLastGoalTime(); + if (lastGoalTime == null) return false; + + final now = DateTime.now(); + return lastGoalTime.year == now.year && + lastGoalTime.month == now.month && + lastGoalTime.day == now.day; + } + // 継承元のbuild をオーバーライドし、detailsSheetメソッドを呼び出して、目的地の詳細情報を表示します。 @override Widget build(BuildContext context) { diff --git a/pubspec.yaml b/pubspec.yaml index 571fd43..528516a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 4.8.13+493 +version: 4.8.14+494 environment: sdk: ">=3.2.0 <4.0.0"