2024-04-09 01:58:25 +09:00
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
//import 'dart:convert';
|
|
|
|
|
|
//import 'dart:developer';
|
2022-03-14 12:28:57 +05:30
|
|
|
|
import 'package:flutter/material.dart';
|
2023-03-17 11:54:12 +05:30
|
|
|
|
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
2022-03-14 12:28:57 +05:30
|
|
|
|
import 'package:get/get.dart';
|
2024-04-09 01:58:25 +09:00
|
|
|
|
//import 'package:vm_service/vm_service.dart';
|
|
|
|
|
|
//import 'package:dart_vm_info/dart_vm_info.dart';
|
|
|
|
|
|
|
2024-04-26 18:44:22 +09:00
|
|
|
|
import 'package:rogapp/pages/settings/settings_controller.dart';
|
|
|
|
|
|
|
2023-08-16 14:53:32 +05:30
|
|
|
|
import 'package:rogapp/pages/destination/destination_controller.dart';
|
2022-05-12 02:17:08 +05:30
|
|
|
|
import 'package:rogapp/pages/index/index_binding.dart';
|
2024-04-30 17:08:23 +09:00
|
|
|
|
import 'package:rogapp/pages/index/index_controller.dart';
|
2022-03-14 12:28:57 +05:30
|
|
|
|
import 'package:rogapp/routes/app_pages.dart';
|
2024-02-06 15:22:27 +05:30
|
|
|
|
import 'package:rogapp/utils/location_controller.dart';
|
2022-03-14 12:28:57 +05:30
|
|
|
|
import 'package:rogapp/utils/string_values.dart';
|
2023-09-08 21:19:12 +05:30
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
2023-09-04 22:46:53 +05:30
|
|
|
|
// import 'package:is_lock_screen/is_lock_screen.dart';
|
2023-03-17 11:54:12 +05:30
|
|
|
|
|
2024-04-04 21:33:07 +09:00
|
|
|
|
import 'package:rogapp/services/device_info_service.dart';
|
|
|
|
|
|
import 'package:rogapp/services/error_service.dart';
|
|
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
2024-04-09 15:06:41 +09:00
|
|
|
|
//import 'dart:async';
|
|
|
|
|
|
//import 'package:get/get.dart';
|
2024-04-04 21:33:07 +09:00
|
|
|
|
|
|
|
|
|
|
Map<String, dynamic> deviceInfo = {};
|
|
|
|
|
|
|
2024-04-30 17:08:23 +09:00
|
|
|
|
/*
|
2023-09-11 00:45:54 +05:30
|
|
|
|
void saveGameState() async {
|
2023-10-06 16:25:21 +05:30
|
|
|
|
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);
|
2024-01-18 19:58:00 +05:30
|
|
|
|
pref.setBool("ready_for_goal", DestinationController.ready_for_goal);
|
2023-10-06 16:25:21 +05:30
|
|
|
|
}
|
2024-04-30 17:08:23 +09:00
|
|
|
|
*/
|
2023-09-11 00:45:54 +05:30
|
|
|
|
|
2024-04-30 17:08:23 +09:00
|
|
|
|
// 現在のユーザーのIDも一緒に保存するようにします。
|
|
|
|
|
|
void saveGameState() async {
|
|
|
|
|
|
DestinationController destinationController =
|
|
|
|
|
|
Get.find<DestinationController>();
|
|
|
|
|
|
IndexController indexController = Get.find<IndexController>();
|
|
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
|
|
|
|
|
pref.setInt("user_id", indexController.currentUser[0]["user"]["id"]);
|
|
|
|
|
|
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-10-06 16:25:21 +05:30
|
|
|
|
void restoreGame() async {
|
|
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
|
|
|
|
|
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;
|
2024-01-18 19:58:00 +05:30
|
|
|
|
DestinationController.ready_for_goal =
|
|
|
|
|
|
pref.getBool("ready_for_goal") ?? false;
|
2023-11-27 14:57:25 +05:30
|
|
|
|
//print(
|
|
|
|
|
|
// "--restored -- destinationController.isInRog.value ${pref.getBool("is_in_rog")} -- ${pref.getBool("rogaining_counted")}");
|
2023-10-06 16:25:21 +05:30
|
|
|
|
}
|
2024-04-30 17:08:23 +09:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void restoreGame() async {
|
|
|
|
|
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
|
|
|
|
|
IndexController indexController = Get.find<IndexController>();
|
|
|
|
|
|
int? savedUserId = pref.getInt("user_id");
|
|
|
|
|
|
if (indexController.currentUser.isNotEmpty &&
|
|
|
|
|
|
indexController.currentUser[0]["user"]["id"] == savedUserId) {
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-09-11 00:45:54 +05:30
|
|
|
|
|
2023-03-17 11:54:12 +05:30
|
|
|
|
void main() async {
|
|
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
2023-09-04 22:46:53 +05:30
|
|
|
|
await FlutterMapTileCaching.initialise();
|
2024-04-04 21:33:07 +09:00
|
|
|
|
|
2023-03-17 11:54:12 +05:30
|
|
|
|
final StoreDirectory instanceA = FMTC.instance('OpenStreetMap (A)');
|
2023-09-04 22:46:53 +05:30
|
|
|
|
await instanceA.manage.createAsync();
|
|
|
|
|
|
await instanceA.metadata.addAsync(
|
|
|
|
|
|
key: 'sourceURL',
|
|
|
|
|
|
value: 'https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png',
|
|
|
|
|
|
);
|
|
|
|
|
|
await instanceA.metadata.addAsync(
|
|
|
|
|
|
key: 'validDuration',
|
|
|
|
|
|
value: '14',
|
|
|
|
|
|
);
|
|
|
|
|
|
await instanceA.metadata.addAsync(
|
|
|
|
|
|
key: 'behaviour',
|
|
|
|
|
|
value: 'cacheFirst',
|
|
|
|
|
|
);
|
2024-04-04 21:33:07 +09:00
|
|
|
|
|
|
|
|
|
|
deviceInfo = await DeviceInfoService.getDeviceInfo();
|
|
|
|
|
|
|
|
|
|
|
|
FlutterError.onError = (FlutterErrorDetails details) {
|
|
|
|
|
|
FlutterError.presentError(details);
|
2024-04-09 15:06:41 +09:00
|
|
|
|
Get.log('Flutter error: ${details.exception}');
|
|
|
|
|
|
Get.log('Stack trace: ${details.stack}');
|
2024-04-04 21:33:07 +09:00
|
|
|
|
ErrorService.reportError(details.exception, details.stack ?? StackTrace.current, deviceInfo);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-04-09 15:06:41 +09:00
|
|
|
|
//Get.put(LocationController());
|
|
|
|
|
|
|
2024-04-09 01:58:25 +09:00
|
|
|
|
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
|
2024-04-26 18:44:22 +09:00
|
|
|
|
Get.put(SettingsController()); // これを追加
|
2024-04-09 01:58:25 +09:00
|
|
|
|
|
2024-04-04 21:33:07 +09:00
|
|
|
|
runZonedGuarded(() {
|
|
|
|
|
|
runApp(const ProviderScope(child: MyApp()));
|
|
|
|
|
|
}, (error, stackTrace) {
|
|
|
|
|
|
ErrorService.reportError(error, stackTrace, deviceInfo);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//runApp(const MyApp());
|
2022-03-14 12:28:57 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-09 01:58:25 +09:00
|
|
|
|
// メモリ使用量の解説: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,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// 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-08-16 14:53:32 +05:30
|
|
|
|
class MyApp extends StatefulWidget {
|
2023-09-04 22:46:53 +05:30
|
|
|
|
const MyApp({Key? key}) : super(key: key);
|
2023-08-16 14:53:32 +05:30
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
State<MyApp> createState() => _MyAppState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
2022-03-14 12:28:57 +05:30
|
|
|
|
// This widget is the root of your application.
|
2023-08-16 14:53:32 +05:30
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void initState() {
|
|
|
|
|
|
super.initState();
|
2023-11-21 22:43:28 +05:30
|
|
|
|
if (context.mounted) {
|
|
|
|
|
|
restoreGame();
|
|
|
|
|
|
}
|
2023-09-04 22:46:53 +05:30
|
|
|
|
WidgetsBinding.instance.addObserver(this);
|
2023-08-16 14:53:32 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
2023-09-04 22:46:53 +05:30
|
|
|
|
void dispose() {
|
|
|
|
|
|
WidgetsBinding.instance.removeObserver(this);
|
|
|
|
|
|
super.dispose();
|
2023-08-16 14:53:32 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-11 00:45:54 +05:30
|
|
|
|
// 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);
|
|
|
|
|
|
// }
|
2023-09-08 21:19:12 +05:30
|
|
|
|
|
2023-10-06 16:25:21 +05:30
|
|
|
|
@override
|
2023-09-04 22:46:53 +05:30
|
|
|
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
2024-02-06 15:22:27 +05:30
|
|
|
|
LocationController locationController = Get.find<LocationController>();
|
|
|
|
|
|
|
2024-04-09 15:06:41 +09:00
|
|
|
|
//DestinationController destinationController =
|
|
|
|
|
|
// Get.find<DestinationController>();
|
2023-10-06 16:25:21 +05:30
|
|
|
|
switch (state) {
|
|
|
|
|
|
case AppLifecycleState.resumed:
|
2024-02-06 15:22:27 +05:30
|
|
|
|
locationController.resumePositionStream();
|
2023-11-27 14:57:25 +05:30
|
|
|
|
//print("RESUMED");
|
2023-10-06 16:25:21 +05:30
|
|
|
|
restoreGame();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case AppLifecycleState.inactive:
|
2024-02-06 15:22:27 +05:30
|
|
|
|
locationController.resumePositionStream();
|
2023-11-27 14:57:25 +05:30
|
|
|
|
//print("INACTIVE");
|
2023-10-06 16:25:21 +05:30
|
|
|
|
break;
|
|
|
|
|
|
case AppLifecycleState.paused:
|
2024-02-06 15:22:27 +05:30
|
|
|
|
locationController.resumePositionStream();
|
2023-11-27 14:57:25 +05:30
|
|
|
|
//print("PAUSED");
|
2023-10-06 16:25:21 +05:30
|
|
|
|
saveGameState();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case AppLifecycleState.detached:
|
2024-02-06 15:22:27 +05:30
|
|
|
|
locationController.resumePositionStream();
|
2023-11-27 14:57:25 +05:30
|
|
|
|
//print("DETACHED");
|
2023-10-06 16:25:21 +05:30
|
|
|
|
saveGameState();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case AppLifecycleState.hidden:
|
2024-02-06 15:22:27 +05:30
|
|
|
|
locationController.resumePositionStream();
|
2023-11-27 14:57:25 +05:30
|
|
|
|
//print("DETACHED");
|
2023-10-06 16:25:21 +05:30
|
|
|
|
saveGameState();
|
|
|
|
|
|
break;
|
2023-09-04 22:46:53 +05:30
|
|
|
|
}
|
2023-10-06 16:25:21 +05:30
|
|
|
|
}
|
2023-08-16 14:53:32 +05:30
|
|
|
|
|
2022-03-14 12:28:57 +05:30
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
|
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-10-06 16:25:21 +05:30
|
|
|
|
colorScheme: ColorScheme.fromSeed(
|
|
|
|
|
|
seedColor: const Color.fromARGB(255, 36, 135, 221)),
|
2023-09-04 22:46:53 +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),
|
|
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|