2024-08-22 14:35:09 +09:00
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
//import 'dart:convert';
|
|
|
|
|
|
//import 'dart:developer';
|
|
|
|
|
|
import 'package:gifunavi/model/gps_data.dart';
|
|
|
|
|
|
//import 'package:gifunavi/pages/home/home_page.dart';
|
|
|
|
|
|
import 'package:gifunavi/utils/database_gps.dart';
|
2022-03-14 12:28:57 +05:30
|
|
|
|
import 'package:flutter/material.dart';
|
2024-08-22 14:35:09 +09:00
|
|
|
|
//import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
|
|
|
|
|
import 'package:geolocator/geolocator.dart';
|
2022-03-14 12:28:57 +05:30
|
|
|
|
import 'package:get/get.dart';
|
2024-08-22 14:35:09 +09:00
|
|
|
|
//import 'package:vm_service/vm_service.dart';
|
|
|
|
|
|
//import 'package:dart_vm_info/dart_vm_info.dart';
|
|
|
|
|
|
import 'package:timezone/data/latest.dart' as tz;
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:gifunavi/pages/settings/settings_controller.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:gifunavi/pages/destination/destination_controller.dart';
|
|
|
|
|
|
import 'package:gifunavi/pages/index/index_binding.dart';
|
|
|
|
|
|
import 'package:gifunavi/pages/index/index_controller.dart';
|
|
|
|
|
|
import 'package:gifunavi/routes/app_pages.dart';
|
|
|
|
|
|
import 'package:gifunavi/utils/location_controller.dart';
|
|
|
|
|
|
import 'package:gifunavi/utils/string_values.dart';
|
|
|
|
|
|
import 'package:gifunavi/widgets/debug_widget.dart';
|
2023-03-17 11:54:12 +05:30
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// import 'package:is_lock_screen/is_lock_screen.dart';
|
|
|
|
|
|
|
|
|
|
|
|
//import 'package:gifunavi/services/device_info_service.dart';
|
|
|
|
|
|
import 'package:gifunavi/services/error_service.dart';
|
|
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
|
|
//import 'dart:async';
|
|
|
|
|
|
//import 'package:get/get.dart';
|
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'pages/permission/permission.dart';
|
|
|
|
|
|
import 'package:gifunavi/services/api_service.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:gifunavi/provider/cached_tile_provider.dart';
|
2024-09-02 21:25:19 +09:00
|
|
|
|
//import 'package:gifunavi/pages/entry/entry_controller.dart';
|
|
|
|
|
|
//import 'package:gifunavi/pages/team/team_controller.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:timezone/timezone.dart' as tz;
|
2023-09-03 23:37:41 +05:30
|
|
|
|
|
2024-09-03 22:17:09 +09:00
|
|
|
|
import 'package:gifunavi/services/motion_service.dart';
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Map<String, dynamic> deviceInfo = {};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
void saveGameState() async {
|
|
|
|
|
|
DestinationController destinationController =
|
|
|
|
|
|
Get.find<DestinationController>();
|
|
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
|
|
|
|
|
pref.setBool("is_in_rog", destinationController.isInRog.value);
|
|
|
|
|
|
pref.setBool(
|
|
|
|
|
|
"rogaining_counted", destinationController.rogainingCounted.value);
|
|
|
|
|
|
pref.setBool("ready_for_goal", DestinationController.ready_for_goal);
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// 現在のユーザーのIDも一緒に保存するようにします。
|
2024-09-02 21:25:19 +09:00
|
|
|
|
Future<void> saveGameState() async {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
DestinationController destinationController =
|
|
|
|
|
|
Get.find<DestinationController>();
|
|
|
|
|
|
IndexController indexController = Get.find<IndexController>();
|
|
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
debugPrint("ゲームステータス保存 = ${indexController.currentUser}");
|
2024-08-22 14:35:09 +09:00
|
|
|
|
if(indexController.currentUser.isNotEmpty) {
|
|
|
|
|
|
pref.setInt("user_id", indexController.currentUser[0]["user"]["id"]);
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
|
|
|
|
|
if(indexController.currentUser[0]["user"]["event_date"]!=null) {
|
|
|
|
|
|
final date = indexController.currentUser[0]["user"]["event_date"];
|
|
|
|
|
|
pref.setString('eventDate', date.toIso8601String());
|
2024-09-03 22:17:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
debugPrint("Saved date is ${date} => ${date.toIso8601String()}");
|
2024-09-03 22:17:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
pref.setString('eventCode', indexController.currentUser[0]["user"]["event_code"]);
|
|
|
|
|
|
pref.setString('teamName', indexController.currentUser[0]["user"]["team_name"]);
|
|
|
|
|
|
pref.setString('group', indexController.currentUser[0]["user"]["group"]);
|
|
|
|
|
|
//final zekken = indexController.currentUser[0]["user"]["zekken_number"];
|
|
|
|
|
|
pref.setInt('zekkenNumber', indexController.currentUser[0]["user"]["zekken_number"]);
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}else{
|
|
|
|
|
|
debugPrint("User is empty....");
|
|
|
|
|
|
}
|
|
|
|
|
|
pref.setBool("is_in_rog", destinationController.isInRog.value);
|
|
|
|
|
|
pref.setBool(
|
|
|
|
|
|
"rogaining_counted", destinationController.rogainingCounted.value);
|
|
|
|
|
|
pref.setBool("ready_for_goal", DestinationController.ready_for_goal);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-03 23:37:41 +05:30
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
|
|
|
|
|
// _indexController.currentUser[0]["user"]["event_date"] = entryDate; // 追加2024-8-9
|
|
|
|
|
|
// _indexController.currentUser[0]["user"]["event_code"] = entry.event.eventName;
|
|
|
|
|
|
// _indexController.currentUser[0]["user"]["team_name"] = entry.team.teamName;
|
|
|
|
|
|
// _indexController.currentUser[0]["user"]["group"] = entry.team.category.categoryName;
|
|
|
|
|
|
// _indexController.currentUser[0]["user"]["zekken_number"] = entry.zekkenNumber;
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> restoreGame() async {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
IndexController indexController = Get.find<IndexController>();
|
|
|
|
|
|
int? savedUserId = pref.getInt("user_id");
|
|
|
|
|
|
//int? currUserId = indexController.currentUser[0]['user']['id'];
|
2024-09-02 21:25:19 +09:00
|
|
|
|
debugPrint("ゲームステータス再現 savedUserId=${savedUserId}");
|
2024-08-22 14:35:09 +09:00
|
|
|
|
if (indexController.currentUser.isNotEmpty &&
|
|
|
|
|
|
indexController.currentUser[0]["user"]["id"] == savedUserId) {
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
|
|
|
|
|
final dateString = pref.getString('eventDate');
|
|
|
|
|
|
if (dateString != null) {
|
|
|
|
|
|
final parsedDate = DateTime.parse(dateString);
|
|
|
|
|
|
final jstDate = tz.TZDateTime.from(parsedDate, tz.getLocation('Asia/Tokyo'));
|
|
|
|
|
|
debugPrint("restore date is ${dateString} => ${jstDate}");
|
|
|
|
|
|
indexController.currentUser[0]["user"]["event_date"] = jstDate;
|
|
|
|
|
|
//indexController.currentUser[0]["user"]["event_date"] = DateTime.parse(dateString);
|
|
|
|
|
|
}
|
|
|
|
|
|
//debugPrint("restore date is ${dateString?} => ${DateTime.parse(dateString)}");
|
|
|
|
|
|
|
|
|
|
|
|
indexController.currentUser[0]["user"]["event_code"] = pref.getString('eventCode');
|
|
|
|
|
|
indexController.currentUser[0]["user"]["team_name"] = pref.getString('teamName');
|
|
|
|
|
|
indexController.currentUser[0]["user"]["group"] = pref.getString('group');
|
|
|
|
|
|
indexController.currentUser[0]["user"]["zekken_number"] = pref.getInt('zekkenNumber');
|
|
|
|
|
|
|
|
|
|
|
|
debugPrint("user = ${indexController.currentUser[0]["user"]}");
|
|
|
|
|
|
|
|
|
|
|
|
DestinationController destinationController = Get.find<DestinationController>();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
destinationController.skipGps = false;
|
|
|
|
|
|
destinationController.isInRog.value = pref.getBool("is_in_rog") ?? false;
|
2024-09-02 21:25:19 +09:00
|
|
|
|
destinationController.rogainingCounted.value = pref.getBool("rogaining_counted") ?? false;
|
|
|
|
|
|
DestinationController.ready_for_goal = pref.getBool("ready_for_goal") ?? false;
|
|
|
|
|
|
//await Get.putAsync(() => ApiService().init());
|
2023-03-17 11:54:12 +05:30
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if (indexController.currentUser[0]["user"]["event_code"] != null) {
|
|
|
|
|
|
indexController.setSelectedEventName(indexController.currentUser[0]["user"]["event_code"]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
indexController.setSelectedEventName('未参加');
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
}else{
|
|
|
|
|
|
indexController.setSelectedEventName('未参加');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
/*
|
|
|
|
|
|
void restoreGame_new() async {
|
|
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
|
|
|
|
|
IndexController indexController = Get.find<IndexController>();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
DestinationController destinationController = Get.find<DestinationController>();
|
|
|
|
|
|
destinationController.skipGps = false;
|
|
|
|
|
|
destinationController.isInRog.value = pref.getBool("is_in_rog") ?? false;
|
|
|
|
|
|
destinationController.rogainingCounted.value = pref.getBool("rogaining_counted") ?? false;
|
|
|
|
|
|
DestinationController.ready_for_goal = pref.getBool("ready_for_goal") ?? false;
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
int? savedUserId = pref.getInt("user_id");
|
|
|
|
|
|
if (indexController.currentUser.isNotEmpty && indexController.currentUser[0]["user"]["id"] == savedUserId) {
|
|
|
|
|
|
final dateString = pref.getString('eventDate');
|
|
|
|
|
|
if (dateString != null) {
|
|
|
|
|
|
indexController.currentUser[0]["user"]["event_date"] = DateTime.parse(dateString);
|
|
|
|
|
|
}
|
|
|
|
|
|
indexController.currentUser[0]["user"]["event_code"] = pref.getString('eventCode');
|
|
|
|
|
|
indexController.currentUser[0]["user"]["team_name"] = pref.getString('teamName');
|
|
|
|
|
|
indexController.currentUser[0]["user"]["group"] = pref.getString('group');
|
|
|
|
|
|
indexController.currentUser[0]["user"]["zekken_number"] = pref.getInt('zekkenNumber');
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if (indexController.currentUser[0]["user"]["event_code"] != null) {
|
|
|
|
|
|
indexController.setSelectedEventName(indexController.currentUser[0]["user"]["event_code"]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
indexController.setSelectedEventName('未参加');
|
|
|
|
|
|
_showEventSelectionWarning();
|
|
|
|
|
|
Get.toNamed(AppPages.EVENT_ENTRY);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
indexController.setSelectedEventName('未参加');
|
|
|
|
|
|
_showEventSelectionWarning();
|
|
|
|
|
|
Get.toNamed(AppPages.EVENT_ENTRY);
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
await Get.putAsync(() => ApiService().init());
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
*/
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
void _showEventSelectionWarning() {
|
|
|
|
|
|
Get.dialog(
|
|
|
|
|
|
AlertDialog(
|
|
|
|
|
|
title: Text('警告'),
|
|
|
|
|
|
content: Text('イベントを選択してください。'),
|
|
|
|
|
|
actions: [
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: Text('OK'),
|
|
|
|
|
|
onPressed: () => Get.back(),
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
void main() async {
|
|
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-03 22:17:09 +09:00
|
|
|
|
if (Platform.isIOS) {
|
|
|
|
|
|
// アプリの起動時にモーション更新を開始
|
|
|
|
|
|
await MotionService.startMotionUpdates();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
final IndexController _indexController;
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
|
|
|
|
|
FlutterError.onError = (FlutterErrorDetails details) {
|
|
|
|
|
|
FlutterError.presentError(details);
|
2024-09-02 21:25:19 +09:00
|
|
|
|
Get.log('Flutter error: ${details.exception}');
|
|
|
|
|
|
Get.log('Stack trace: ${details.stack}');
|
|
|
|
|
|
ErrorService.reportError(details.exception, details.stack ?? StackTrace.current, deviceInfo, LogManager().operationLogs);
|
2024-08-22 14:35:09 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
await initServices();
|
|
|
|
|
|
runApp(const ProviderScope(child: MyApp()));
|
|
|
|
|
|
}catch(e, stackTrace){
|
|
|
|
|
|
print('Error during initialization: $e');
|
|
|
|
|
|
print('Stack trace: $stackTrace');
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
|
|
|
|
|
// エラーが発生した場合、エラー画面を表示
|
|
|
|
|
|
runApp(ErrorApp(error: e.toString()));
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> initServices() async {
|
|
|
|
|
|
print('Starting services ...');
|
|
|
|
|
|
try {
|
2024-09-03 22:17:09 +09:00
|
|
|
|
//await Get.putAsync(() => ApiService().init());
|
|
|
|
|
|
await _initApiService();
|
|
|
|
|
|
debugPrint("1: start ApiService");
|
|
|
|
|
|
|
|
|
|
|
|
// コントローラーを初期化
|
|
|
|
|
|
Get.put(IndexController(apiService: Get.find<ApiService>()), permanent: true);
|
|
|
|
|
|
Get.put(SettingsController(), permanent: true);
|
|
|
|
|
|
Get.put(DestinationController(), permanent: true);
|
|
|
|
|
|
Get.put(LocationController(), permanent: true);
|
|
|
|
|
|
|
|
|
|
|
|
debugPrint("2: Controllers initialized");
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
|
|
|
|
|
// 非同期処理を並列実行
|
|
|
|
|
|
await Future.wait([
|
|
|
|
|
|
_initTimeZone(),
|
|
|
|
|
|
_initCacheProvider(),
|
|
|
|
|
|
]);
|
2024-09-03 22:17:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
print('=== 5. Initialized TimeZone...');
|
|
|
|
|
|
print('=== 6. CacheProvider started...');
|
|
|
|
|
|
|
|
|
|
|
|
Get.put(PermissionController());
|
|
|
|
|
|
await _checkPermissions();
|
|
|
|
|
|
debugPrint("7: start PermissionController");
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}catch(e){
|
2024-09-02 21:25:19 +09:00
|
|
|
|
print('Error initializing : $e');
|
2024-09-10 08:12:33 +09:00
|
|
|
|
rethrow;
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
2024-09-02 21:25:19 +09:00
|
|
|
|
print('All services started...');
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _initLocationController() async {
|
|
|
|
|
|
if (!Get.isRegistered<LocationController>()) {
|
|
|
|
|
|
Get.put(LocationController());
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
2024-09-02 21:25:19 +09:00
|
|
|
|
print('=== 1. LocationController started...');
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
Future<void> _initTimeZone() async {
|
|
|
|
|
|
tz.initializeTimeZones();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _initCacheProvider() async {
|
|
|
|
|
|
await CacheProvider.initialize();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _checkPermissions() async {
|
|
|
|
|
|
await PermissionController.checkAndRequestPermissions();
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
Future<void> _initApiService() async {
|
|
|
|
|
|
await Get.putAsync(() => ApiService().init());
|
|
|
|
|
|
//Get.lazyPut(() => ApiService());
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
class ErrorApp extends StatelessWidget {
|
|
|
|
|
|
final String error;
|
|
|
|
|
|
|
|
|
|
|
|
const ErrorApp({super.key, required this.error});
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
|
return MaterialApp(
|
|
|
|
|
|
home: Scaffold(
|
|
|
|
|
|
body: Center(
|
|
|
|
|
|
child: Text('アプリの起動中にエラーが発生しました: $error'),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Future<void> requestLocationPermission() async {
|
|
|
|
|
|
try {
|
|
|
|
|
|
final status = await Permission.locationAlways.request();
|
|
|
|
|
|
if (status == PermissionStatus.granted) {
|
|
|
|
|
|
print('Location permission granted');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
print('Location permission denied');
|
|
|
|
|
|
//await showLocationPermissionDeniedDialog(); // 追加
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
print('Error requesting location permission: $e');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// メモリ使用量の解説:https://qiita.com/hukusuke1007/items/e4e987836412e9bc73b9
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
// 2024-4-8 Akira: メモリ使用量のチェックのため追加 See #2810
|
|
|
|
|
|
// startMemoryMonitoring関数が5分ごとに呼び出され、メモリ使用量をチェックします。
|
|
|
|
|
|
// メモリ使用量が閾値(ここでは500MB)を超えた場合、エラーメッセージとスタックトレースをレポートします。
|
|
|
|
|
|
//
|
|
|
|
|
|
void startMemoryMonitoring() {
|
|
|
|
|
|
const threshold = 500 * 1024 * 1024; // 500MB
|
|
|
|
|
|
|
|
|
|
|
|
// メモリ使用量情報を取得
|
|
|
|
|
|
final memoryUsage = MemoryUsage.fromJson(DartVMInfo.getAllocationProfile());
|
|
|
|
|
|
|
|
|
|
|
|
if (memoryUsage.heapUsage > threshold) {
|
|
|
|
|
|
final now = DateTime.now().toIso8601String();
|
|
|
|
|
|
final message = 'High memory usage detected at $now: ${memoryUsage.heapUsage} bytes';
|
|
|
|
|
|
print(message);
|
|
|
|
|
|
reportError(message, StackTrace.current);
|
|
|
|
|
|
showMemoryWarningDialog();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Timer(const Duration(minutes: 5), startMemoryMonitoring);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class MemoryUsage {
|
|
|
|
|
|
final int heapUsage;
|
|
|
|
|
|
|
|
|
|
|
|
MemoryUsage({required this.heapUsage});
|
|
|
|
|
|
|
|
|
|
|
|
factory MemoryUsage.fromJson(Map<String, dynamic> json) {
|
|
|
|
|
|
return MemoryUsage(
|
|
|
|
|
|
heapUsage: json['heapUsage'] as int,
|
2023-03-17 11:54:12 +05:30
|
|
|
|
);
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// 2024-4-8 Akira: メモリ使用量のチェックのため追加 See #2810
|
|
|
|
|
|
// reportError関数でエラーレポートを送信します。具体的な実装は、利用するエラー報告サービスによって異なります。
|
|
|
|
|
|
void reportError(String message, StackTrace stackTrace) async {
|
|
|
|
|
|
// エラーレポートの送信処理を実装
|
|
|
|
|
|
// 例: SentryやFirebase Crashlyticsなどのエラー報告サービスを利用
|
|
|
|
|
|
print("ReportError : $message . stacktrace : $stackTrace");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2024-4-8 Akira: メモリ使用量のチェックのため追加 See #2810
|
|
|
|
|
|
// showMemoryWarningDialog関数で、メモリ使用量が高い場合にユーザーに警告ダイアログを表示します。
|
|
|
|
|
|
//
|
|
|
|
|
|
void showMemoryWarningDialog() {
|
|
|
|
|
|
if (Get.context != null) {
|
|
|
|
|
|
showDialog(
|
|
|
|
|
|
context: Get.context!,
|
|
|
|
|
|
builder: (context) => AlertDialog(
|
|
|
|
|
|
title: const Text('メモリ使用量の警告'),
|
|
|
|
|
|
content: const Text('アプリのメモリ使用量が高くなっています。アプリを再起動することをお勧めします。'),
|
|
|
|
|
|
actions: [
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
|
|
|
|
child: const Text('OK'),
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
2023-03-17 11:54:12 +05:30
|
|
|
|
);
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
StreamSubscription<Position>? positionStream;
|
|
|
|
|
|
bool background=false;
|
|
|
|
|
|
DateTime lastGPSCollectedTime=DateTime.now();
|
|
|
|
|
|
String team_name="";
|
|
|
|
|
|
String event_code="";
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> startBackgroundTracking() async {
|
2024-09-02 21:25:19 +09:00
|
|
|
|
try {
|
|
|
|
|
|
if (Platform.isIOS && background == false) {
|
|
|
|
|
|
final IndexController indexController = Get.find<IndexController>();
|
|
|
|
|
|
if (indexController.currentUser.isNotEmpty &&
|
|
|
|
|
|
indexController.currentUser[0]["user"]['team_name'] != null) {
|
|
|
|
|
|
team_name = indexController.currentUser[0]["user"]['team_name'];
|
|
|
|
|
|
event_code = indexController.currentUser[0]["user"]["event_code"];
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
background = true;
|
2024-09-02 21:25:19 +09:00
|
|
|
|
debugPrint("バックグラウンド処理を開始しました。");
|
|
|
|
|
|
const LocationSettings locationSettings = LocationSettings(
|
|
|
|
|
|
accuracy: LocationAccuracy.high,
|
|
|
|
|
|
distanceFilter: 100,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
positionStream =
|
|
|
|
|
|
Geolocator.getPositionStream(locationSettings: locationSettings)
|
|
|
|
|
|
.listen((Position? position) async {
|
|
|
|
|
|
if (position != null) {
|
|
|
|
|
|
final lat = position.latitude;
|
|
|
|
|
|
final lng = position.longitude;
|
|
|
|
|
|
//final timestamp = DateTime.now();
|
|
|
|
|
|
final accuracy = position.accuracy;
|
|
|
|
|
|
|
|
|
|
|
|
// GPS信号強度がlowの場合はスキップ
|
|
|
|
|
|
if (accuracy > 100) {
|
|
|
|
|
|
debugPrint(
|
|
|
|
|
|
"GPS signal strength is low. Skipping data saving.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Duration difference = lastGPSCollectedTime.difference(
|
|
|
|
|
|
DateTime.now())
|
|
|
|
|
|
.abs();
|
|
|
|
|
|
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過(普通に歩くスピード)
|
|
|
|
|
|
//debugPrint("時間差:${difference}");
|
|
|
|
|
|
if (difference.inSeconds >= 10) {
|
|
|
|
|
|
debugPrint(
|
|
|
|
|
|
"バックグラウンドでのGPS取得時の処理(10secおき) count=${difference
|
|
|
|
|
|
.inSeconds}, time=${DateTime.now()}");
|
|
|
|
|
|
|
|
|
|
|
|
// DBにGPSデータを保存 pages/destination/destination_controller.dart
|
|
|
|
|
|
await addGPStoDB(lat, lng);
|
|
|
|
|
|
|
|
|
|
|
|
lastGPSCollectedTime = DateTime.now();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, onError: (error) {
|
|
|
|
|
|
if (error is LocationServiceDisabledException) {
|
|
|
|
|
|
print('Location services are disabled');
|
|
|
|
|
|
} else if (error is PermissionDeniedException) {
|
|
|
|
|
|
print('Location permissions are denied');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
print('Location Error: $error');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
print('Error starting background tracking: $e');
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (Platform.isAndroid && background == false) {
|
|
|
|
|
|
background = true;
|
|
|
|
|
|
debugPrint("バックグラウンド処理を開始しました。");
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
try {
|
|
|
|
|
|
// 位置情報の権限が許可されているかを確認
|
|
|
|
|
|
await PermissionController.checkAndRequestPermissions();
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
print('Error starting background tracking: $e');
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
2024-09-02 21:25:19 +09:00
|
|
|
|
} catch (e) {
|
|
|
|
|
|
print('Error starting background tracking: $e');
|
|
|
|
|
|
// 再試行するか、エラーを適切に処理
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> addGPStoDB(double la, double ln) async {
|
|
|
|
|
|
//debugPrint("in addGPStoDB ${indexController.currentUser}");
|
|
|
|
|
|
GpsDatabaseHelper db = GpsDatabaseHelper.instance;
|
|
|
|
|
|
try {
|
|
|
|
|
|
GpsData gpsData = GpsData(
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
team_name: team_name,
|
|
|
|
|
|
event_code: event_code,
|
|
|
|
|
|
lat: la,
|
|
|
|
|
|
lon: ln,
|
|
|
|
|
|
is_checkin: 0,
|
|
|
|
|
|
created_at: DateTime.now().millisecondsSinceEpoch);
|
|
|
|
|
|
var res = await db.insertGps(gpsData);
|
|
|
|
|
|
debugPrint("バックグラウンドでのGPS保存:");
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
print("errr ready gps $err");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> stopBackgroundTracking() async {
|
2024-09-02 21:25:19 +09:00
|
|
|
|
try {
|
|
|
|
|
|
if (Platform.isIOS && background == true) {
|
|
|
|
|
|
background = false;
|
|
|
|
|
|
debugPrint("バックグラウンド処理:停止しました。");
|
|
|
|
|
|
await positionStream?.cancel();
|
|
|
|
|
|
positionStream = null;
|
|
|
|
|
|
} else if (Platform.isAndroid && background == true) {
|
|
|
|
|
|
background = false;
|
|
|
|
|
|
debugPrint("バックグラウンド処理:停止しました。");
|
|
|
|
|
|
const platform = MethodChannel('location');
|
|
|
|
|
|
try {
|
|
|
|
|
|
await platform.invokeMethod('stopLocationService');
|
|
|
|
|
|
} on PlatformException catch (e) {
|
|
|
|
|
|
print("Failed to stop location service: '${e.message}'.");
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
2024-09-02 21:25:19 +09:00
|
|
|
|
} catch(e){
|
|
|
|
|
|
print('Error stopping background tracking: $e');
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
2022-03-14 12:28:57 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
class MyApp extends StatefulWidget {
|
|
|
|
|
|
const MyApp({super.key});
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
State<MyApp> createState() => _MyAppState();
|
|
|
|
|
|
}
|
2023-09-03 23:37:41 +05:30
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
2022-03-14 12:28:57 +05:30
|
|
|
|
// This widget is the root of your application.
|
2024-09-02 21:25:19 +09:00
|
|
|
|
late final LocationController _locationController;
|
|
|
|
|
|
late final IndexController _indexController;
|
|
|
|
|
|
late final DestinationController _destinationController;
|
|
|
|
|
|
late final PermissionController _permissionController;
|
|
|
|
|
|
Timer? _memoryCheckTimer;
|
2024-09-03 22:17:09 +09:00
|
|
|
|
bool _isControllerInitialized = false;
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void initState() {
|
|
|
|
|
|
super.initState();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
_initializeControllers();
|
|
|
|
|
|
WidgetsBinding.instance.addObserver(this);
|
|
|
|
|
|
//_startMemoryMonitoring();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
|
|
|
|
|
if (context.mounted) {
|
2024-09-02 21:25:19 +09:00
|
|
|
|
// _restoreGameAndInitialize();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ウィジェットが構築された後に権限をチェック
|
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
|
|
PermissionController.checkAndRequestPermissions();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
debugPrint("Start MyAppState...");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
Future<void> _restoreGameAndInitialize() async {
|
|
|
|
|
|
await restoreGame();
|
|
|
|
|
|
// ここに他の初期化処理を追加できます
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-03 22:17:09 +09:00
|
|
|
|
Future <void> _initializeControllers() async {
|
|
|
|
|
|
|
|
|
|
|
|
while (!Get.isRegistered<LocationController>() ||
|
|
|
|
|
|
!Get.isRegistered<IndexController>() ||
|
|
|
|
|
|
!Get.isRegistered<DestinationController>() ||
|
|
|
|
|
|
!Get.isRegistered<PermissionController>()) {
|
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!_isControllerInitialized) {
|
|
|
|
|
|
_locationController = Get.find<LocationController>();
|
|
|
|
|
|
_indexController = Get.find<IndexController>();
|
|
|
|
|
|
_destinationController = Get.find<DestinationController>();
|
|
|
|
|
|
_permissionController = Get.find<PermissionController>();
|
|
|
|
|
|
_isControllerInitialized = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
/*
|
2024-09-03 22:17:09 +09:00
|
|
|
|
while (true) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
_locationController = Get.find<LocationController>();
|
|
|
|
|
|
break; // DestinationControllerが見つかったらループを抜ける
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// DestinationControllerがまだ利用可能でない場合は少し待ってから再試行
|
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
|
|
|
if (!Get.isRegistered<LocationController>()) {
|
2024-09-02 21:25:19 +09:00
|
|
|
|
_locationController = Get.put(LocationController(), permanent: true);
|
|
|
|
|
|
}
|
2024-09-03 22:17:09 +09:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
_indexController = Get.find<IndexController>();
|
|
|
|
|
|
break; // DestinationControllerが見つかったらループを抜ける
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// DestinationControllerがまだ利用可能でない場合は少し待ってから再試行
|
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
/*
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if (!Get.isRegistered<IndexController>()) {
|
|
|
|
|
|
_indexController = Get.put(IndexController(apiService: Get.find<ApiService>()), permanent: true);
|
|
|
|
|
|
}
|
2024-09-03 22:17:09 +09:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
_destinationController = Get.find<DestinationController>();
|
|
|
|
|
|
break; // DestinationControllerが見つかったらループを抜ける
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// DestinationControllerがまだ利用可能でない場合は少し待ってから再試行
|
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
/*
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if (!Get.isRegistered<DestinationController>()) {
|
|
|
|
|
|
_destinationController =
|
|
|
|
|
|
Get.put(DestinationController(), permanent: true);
|
|
|
|
|
|
}
|
2024-09-03 22:17:09 +09:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
_permissionController = Get.find<PermissionController>();
|
|
|
|
|
|
break; // DestinationControllerが見つかったらループを抜ける
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// DestinationControllerがまだ利用可能でない場合は少し待ってから再試行
|
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
/*
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if (!Get.isRegistered<PermissionController>()) {
|
|
|
|
|
|
_permissionController = Get.put(PermissionController());
|
|
|
|
|
|
}
|
2024-09-03 22:17:09 +09:00
|
|
|
|
*/
|
2024-09-02 21:25:19 +09:00
|
|
|
|
// 他の必要なコントローラーの初期化
|
|
|
|
|
|
|
2024-09-03 22:17:09 +09:00
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _startMemoryMonitoring() {
|
|
|
|
|
|
/*
|
|
|
|
|
|
_memoryCheckTimer = Timer.periodic(const Duration(seconds: 10), (timer) {
|
|
|
|
|
|
_checkMemoryUsage();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _checkMemoryUsage() async {
|
2024-09-10 08:12:33 +09:00
|
|
|
|
/*
|
2024-09-02 21:25:19 +09:00
|
|
|
|
final memoryInfo = await _getMemoryInfo();
|
|
|
|
|
|
//debugPrint('Current memory usage: ${memoryInfo['used']} MB');
|
|
|
|
|
|
if (memoryInfo['used']! > 100) { // 100MB以上使用している場合
|
|
|
|
|
|
_performMemoryCleanup();
|
|
|
|
|
|
}
|
2024-09-10 08:12:33 +09:00
|
|
|
|
|
|
|
|
|
|
*/
|
2024-09-02 21:25:19 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<Map<String, int>> _getMemoryInfo() async {
|
|
|
|
|
|
// プラットフォーム固有のメモリ情報取得ロジックを実装
|
|
|
|
|
|
// この例では仮の値を返しています
|
|
|
|
|
|
return {'total': 1024, 'used': 512};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _performMemoryCleanup() {
|
|
|
|
|
|
/*
|
|
|
|
|
|
debugPrint('Performing memory cleanup');
|
|
|
|
|
|
// キャッシュのクリア
|
|
|
|
|
|
|
|
|
|
|
|
Get.deleteAll(force: false); // 永続的なコントローラーを除外してキャッシュをクリア
|
|
|
|
|
|
imageCache.clear();
|
|
|
|
|
|
imageCache.clearLiveImages();
|
|
|
|
|
|
|
|
|
|
|
|
// 大きなオブジェクトの解放
|
|
|
|
|
|
_clearLargeObjects();
|
|
|
|
|
|
|
|
|
|
|
|
// 未使用のリソースの解放
|
|
|
|
|
|
_releaseUnusedResources();
|
|
|
|
|
|
|
|
|
|
|
|
// ガベージコレクションの促進
|
|
|
|
|
|
_forceGarbageCollection();
|
|
|
|
|
|
debugPrint('Performing memory cleanup');
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _clearLargeObjects() {
|
|
|
|
|
|
// 大きなリストやマップをクリア
|
|
|
|
|
|
// 例: myLargeList.clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _releaseUnusedResources() {
|
|
|
|
|
|
// 使用していないストリームのクローズ
|
|
|
|
|
|
// 例: myStream?.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _forceGarbageCollection() {
|
|
|
|
|
|
/*
|
|
|
|
|
|
Timer(const Duration(seconds: 1), () {
|
|
|
|
|
|
debugPrint('Forcing garbage collection');
|
|
|
|
|
|
// ignore: dead_code
|
|
|
|
|
|
bool didRun = false;
|
|
|
|
|
|
assert(() {
|
|
|
|
|
|
didRun = true;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}());
|
|
|
|
|
|
if (didRun) {
|
|
|
|
|
|
debugPrint('Garbage collection forced in debug mode');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
/*
|
|
|
|
|
|
void showPermissionRequiredDialog() {
|
|
|
|
|
|
showDialog(
|
|
|
|
|
|
context: context,
|
|
|
|
|
|
barrierDismissible: false,
|
|
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
|
|
return AlertDialog(
|
|
|
|
|
|
title: Text('権限が必要です'),
|
|
|
|
|
|
content: Text('このアプリは機能するために位置情報の権限が必要です。設定で権限を許可してください。'),
|
|
|
|
|
|
actions: <Widget>[
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: Text('設定を開く'),
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
openAppSettings();
|
|
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: Text('アプリを終了'),
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
// アプリを終了
|
|
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
|
// よりクリーンな終了のために 'flutter_exit_app' のようなプラグインを使用することをお勧めします
|
|
|
|
|
|
// 今回は単にすべてのルートをポップします
|
|
|
|
|
|
Navigator.of(context).popUntil((route) => false);
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void dispose() {
|
2024-09-03 22:17:09 +09:00
|
|
|
|
_isControllerInitialized = false;
|
2024-08-22 14:35:09 +09:00
|
|
|
|
WidgetsBinding.instance.removeObserver(this);
|
2024-09-02 21:25:19 +09:00
|
|
|
|
_memoryCheckTimer?.cancel();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
super.dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// void saveGameState() async {
|
|
|
|
|
|
// DestinationController destinationController = Get.find<DestinationController>();
|
|
|
|
|
|
// SharedPreferences pref = await SharedPreferences.getInstance();
|
|
|
|
|
|
// pref.setBool("is_in_rog", destinationController.is_in_rog.value);
|
|
|
|
|
|
// pref.setBool("rogaining_counted", destinationController.rogaining_counted.value);
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
|
|
|
|
|
|
try {
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if (!Get.isRegistered<IndexController>()) {
|
|
|
|
|
|
_indexController = Get.find<IndexController>();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!Get.isRegistered<LocationController>()) {
|
|
|
|
|
|
_locationController = Get.find<LocationController>();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!Get.isRegistered<DestinationController>()) {
|
|
|
|
|
|
_destinationController = Get.find<DestinationController>();
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
|
case AppLifecycleState.resumed:
|
2024-09-03 22:17:09 +09:00
|
|
|
|
if (Platform.isIOS) {
|
|
|
|
|
|
MotionService.startMotionUpdates();
|
|
|
|
|
|
}
|
2024-09-02 21:25:19 +09:00
|
|
|
|
//await _onResumed();
|
|
|
|
|
|
await _onResumed();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
break;
|
|
|
|
|
|
case AppLifecycleState.inactive:
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
// アプリが非アクティブになったときに発生します。
|
|
|
|
|
|
await _onInactive();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
break;
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
case AppLifecycleState.paused:
|
2024-09-03 22:17:09 +09:00
|
|
|
|
MotionService.stopMotionUpdates();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// バックグラウンドに移行したときの処理
|
|
|
|
|
|
//locationController.resumePositionStream();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
await _onPaused();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
break;
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
case AppLifecycleState.detached:
|
|
|
|
|
|
// アプリが終了する直前に発生します。この状態では、アプリはメモリから解放される予定です。
|
|
|
|
|
|
//locationController.resumePositionStream();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
await _onDetached();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
break;
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
case AppLifecycleState.hidden:
|
|
|
|
|
|
// Web用の特殊な状態で、モバイルアプリでは発生しません。
|
|
|
|
|
|
//locationController.resumePositionStream();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
await _onHidden();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}catch(e){
|
2024-09-02 21:25:19 +09:00
|
|
|
|
print('Error finding didChangeAppLifecycleState: $e');
|
|
|
|
|
|
_initializeControllers();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _onResumed() async {
|
|
|
|
|
|
debugPrint("==(Status Changed)==> RESUMED");
|
|
|
|
|
|
try {
|
2024-09-03 22:17:09 +09:00
|
|
|
|
if (!_isControllerInitialized) {
|
|
|
|
|
|
await _initializeControllers();
|
|
|
|
|
|
}
|
2024-09-02 21:25:19 +09:00
|
|
|
|
|
|
|
|
|
|
await stopBackgroundTracking();
|
|
|
|
|
|
_destinationController.restartGPS();
|
|
|
|
|
|
|
|
|
|
|
|
if (Platform.isIOS && _destinationController.isRunningBackgroundGPS) {
|
|
|
|
|
|
_locationController.resumePositionStream();
|
|
|
|
|
|
await restoreGame();
|
|
|
|
|
|
_destinationController.isRunningBackgroundGPS = false;
|
|
|
|
|
|
} else if (Platform.isAndroid) {
|
|
|
|
|
|
if (_destinationController.isRunningBackgroundGPS) {
|
|
|
|
|
|
const platform = MethodChannel('location');
|
|
|
|
|
|
await platform.invokeMethod('stopLocationService');
|
|
|
|
|
|
_destinationController.isRunningBackgroundGPS = false;
|
|
|
|
|
|
_destinationController.restartGPS();
|
|
|
|
|
|
}
|
|
|
|
|
|
_locationController.resumePositionStream();
|
|
|
|
|
|
await restoreGame();
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch(e) {
|
|
|
|
|
|
print('Error in _onResumed: $e');
|
|
|
|
|
|
// 必要に応じて再試行またはエラー処理
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
Future<void> _onInactive() async {
|
|
|
|
|
|
debugPrint("==(Status Changed)==> INACTIVE");
|
|
|
|
|
|
if (Platform.isIOS && !_destinationController.isRunningBackgroundGPS) {
|
|
|
|
|
|
debugPrint(" ==(Status Changed)==> INACTIVE. 非アクティブ処理。");
|
|
|
|
|
|
_locationController.stopPositionStream();
|
|
|
|
|
|
_destinationController.isRunningBackgroundGPS = true;
|
|
|
|
|
|
await startBackgroundTracking();
|
|
|
|
|
|
} else if (Platform.isAndroid && !_destinationController.isRunningBackgroundGPS) {
|
|
|
|
|
|
// Android特有の処理があれば追加
|
|
|
|
|
|
debugPrint(" ==(Status Changed)==> INACTIVE. 非アクティブ処理。");
|
|
|
|
|
|
}else{
|
|
|
|
|
|
debugPrint("==(Status Changed)==> INACTIVE 不明状態");
|
|
|
|
|
|
}
|
|
|
|
|
|
await saveGameState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _onPaused() async {
|
|
|
|
|
|
debugPrint(" ==(Status Changed)==> PAUSED. バックグラウンド処理。");
|
|
|
|
|
|
if (Platform.isAndroid && !_destinationController.isRunningBackgroundGPS) {
|
|
|
|
|
|
debugPrint(" ==(Status Changed)==> PAUSED. Android バックグラウンド処理。");
|
|
|
|
|
|
_locationController.stopPositionStream();
|
|
|
|
|
|
const platform = MethodChannel('location');
|
|
|
|
|
|
await platform.invokeMethod('startLocationService');
|
|
|
|
|
|
_destinationController.isRunningBackgroundGPS = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
await saveGameState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _onDetached() async {
|
|
|
|
|
|
debugPrint(" ==(Status Changed)==> DETACHED アプリは終了します。");
|
|
|
|
|
|
await saveGameState();
|
|
|
|
|
|
// アプリ終了時の追加処理
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _onHidden() async {
|
|
|
|
|
|
debugPrint(" ==(Status Changed)==> Hidden アプリが隠れた");
|
|
|
|
|
|
await saveGameState();
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2022-03-14 12:28:57 +05:30
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context) {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
2022-03-14 12:28:57 +05:30
|
|
|
|
return GetMaterialApp(
|
|
|
|
|
|
translations: StringValues(),
|
|
|
|
|
|
locale: const Locale('ja', 'JP'),
|
2022-10-30 21:43:29 +05:30
|
|
|
|
//locale: const Locale('en', 'US'),
|
2022-03-14 12:28:57 +05:30
|
|
|
|
fallbackLocale: const Locale('en', 'US'),
|
|
|
|
|
|
title: 'ROGAINING',
|
|
|
|
|
|
theme: ThemeData(
|
2023-09-03 23:37:41 +05:30
|
|
|
|
colorScheme: ColorScheme.fromSeed(
|
2024-08-22 14:35:09 +09:00
|
|
|
|
seedColor: const Color.fromARGB(255, 36, 135, 221)),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
useMaterial3: true,
|
2022-03-14 12:28:57 +05:30
|
|
|
|
),
|
|
|
|
|
|
debugShowCheckedModeBanner: false,
|
|
|
|
|
|
defaultTransition: Transition.cupertino,
|
|
|
|
|
|
opaqueRoute: Get.isOpaqueRouteDefault,
|
|
|
|
|
|
popGesture: Get.isPopGestureEnable,
|
2022-04-17 11:45:21 +05:30
|
|
|
|
transitionDuration: const Duration(milliseconds: 230),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
initialBinding: IndexBinding(), //HomeBinding(),
|
2022-07-20 15:57:40 +05:30
|
|
|
|
initialRoute: AppPages.PERMISSION,
|
2022-03-14 12:28:57 +05:30
|
|
|
|
getPages: AppPages.routes,
|
2022-07-09 22:51:34 +05:30
|
|
|
|
enableLog: true,
|
2022-03-14 12:28:57 +05:30
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-07-20 15:57:40 +05:30
|
|
|
|
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}
|