diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a6c0e54..f2c05be 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + diff --git a/android/app/src/main/kotlin/com/dvox/gifunavi/LocationService.kt b/android/app/src/main/kotlin/com/dvox/gifunavi/LocationService.kt index 6feb4f7..febf16c 100644 --- a/android/app/src/main/kotlin/com/dvox/gifunavi/LocationService.kt +++ b/android/app/src/main/kotlin/com/dvox/gifunavi/LocationService.kt @@ -64,6 +64,7 @@ class LocationService : Service() { override fun onCreate() { super.onCreate() + Log.d("LocationService", "Android: onCreate.") fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) gpsDatabaseHelper = GpsDatabaseHelper.getInstance(applicationContext) @@ -71,6 +72,8 @@ class LocationService : Service() { // 位置情報の権限チェックとGPS有効化の確認を行う if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.FOREGROUND_SERVICE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + Log.d("LocationService", "Android: onCreate : 位置情報の権限チェックとGPS有効化の確認") + val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { val locationRequest = LocationRequest.create().apply { diff --git a/android/app/src/main/kotlin/com/dvox/gifunavi/MainActivity.kt b/android/app/src/main/kotlin/com/dvox/gifunavi/MainActivity.kt index 5ce79ec..1fb59b2 100644 --- a/android/app/src/main/kotlin/com/dvox/gifunavi/MainActivity.kt +++ b/android/app/src/main/kotlin/com/dvox/gifunavi/MainActivity.kt @@ -52,12 +52,14 @@ class MainActivity: FlutterActivity() { super.onCreate(savedInstanceState) Log.d("MainActivity", "Android: onCreate.") - // 位置情報の権限をリクエストする + // 位置情報の権限をリクエストする==> main() の前にコールされるので除外 2024-7-19 + /* if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_CODE) } else { // startLocationService() // アプリ起動時にLocationServiceを開始する ==> main.dartで制御する。 } + */ } diff --git a/lib/main.dart b/lib/main.dart index d1d9a43..4fe0403 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,7 +3,7 @@ import 'dart:io'; //import 'dart:convert'; //import 'dart:developer'; import 'package:rogapp/model/gps_data.dart'; -import 'package:rogapp/pages/home/home_page.dart'; +//import 'package:rogapp/pages/home/home_page.dart'; import 'package:rogapp/utils/database_gps.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; @@ -141,6 +141,7 @@ void main() async { // startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810 Get.put(SettingsController()); // これを追加 + /* runZonedGuarded(() { runApp(const ProviderScope(child: MyApp())); @@ -149,6 +150,8 @@ void main() async { }); */ + + runApp(const ProviderScope(child: MyApp())); //runApp(HomePage()); // MyApp()からHomePage()に変更 //runApp(const MyApp()); @@ -324,7 +327,7 @@ Future addGPStoDB(double la, double ln) async { is_checkin: 0, created_at: DateTime.now().millisecondsSinceEpoch); var res = await db.insertGps(gps_data); - //debugPrint("バックグラウンドでのGPS保存:"); + debugPrint("バックグラウンドでのGPS保存:"); } catch (err) { print("errr ready gps ${err}"); return; @@ -367,52 +370,39 @@ class _MyAppState extends State with WidgetsBindingObserver { } WidgetsBinding.instance.addObserver(this); - // Add to clear + // ウィジェットが構築された後に権限をチェック WidgetsBinding.instance.addPostFrameCallback((_) { - showLocationDisclosure(context); + PermissionController.checkAndRequestPermissions(); }); - /* - WidgetsBinding.instance.addPostFrameCallback((_) async { - await PermissionController.checkAndRequestPermissions(); - }); - */ - debugPrint("Start MyAppState..."); } - void showLocationDisclosure(BuildContext context) { +/* + void showPermissionRequiredDialog() { showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( - title: Text('位置情報の使用について'), - content: const SingleChildScrollView( - child: ListBody( - children: [ - Text('このアプリでは、以下の目的で位置情報を使用します:'), - Text('• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'), - Text('• 移動履歴の記録(バックグラウンドでも継続)'), - Text('• 現在地周辺の情報表示'), - Text('\nバックグラウンドでも位置情報を継続的に取得します。'), - Text('これにより、バッテリーの消費が増加する可能性があります。'), - ], - ), - ), + title: Text('権限が必要です'), + content: Text('このアプリは機能するために位置情報の権限が必要です。設定で権限を許可してください。'), actions: [ TextButton( - child: const Text('同意しない'), + child: Text('設定を開く'), onPressed: () { + openAppSettings(); Navigator.of(context).pop(); - // アプリを終了するなどの処理 }, ), TextButton( - child: const Text('同意する'), + child: Text('アプリを終了'), onPressed: () { + // アプリを終了 Navigator.of(context).pop(); - requestLocationPermission(); + // よりクリーンな終了のために 'flutter_exit_app' のようなプラグインを使用することをお勧めします + // 今回は単にすべてのルートをポップします + Navigator.of(context).popUntil((route) => false); }, ), ], @@ -421,6 +411,9 @@ class _MyAppState extends State with WidgetsBindingObserver { ); } + */ + + @override void dispose() { WidgetsBinding.instance.removeObserver(this); diff --git a/lib/pages/index/index_controller.dart b/lib/pages/index/index_controller.dart index a6edacd..48c20a4 100644 --- a/lib/pages/index/index_controller.dart +++ b/lib/pages/index/index_controller.dart @@ -417,6 +417,7 @@ class IndexController extends GetxController with WidgetsBindingObserver { void register(String email, String password, BuildContext context) { AuthService.register(email, password).then((value) { if (value.isNotEmpty) { + debugPrint("ユーザー登録成功:${email}, ${password}"); logManager.addOperationLog("User tried to register new account : ${email} , ${password} ."); currentUser.clear(); @@ -425,16 +426,17 @@ class IndexController extends GetxController with WidgetsBindingObserver { Navigator.pop(context); Get.toNamed(AppPages.INDEX); } else { + debugPrint("ユーザー登録失敗:${email}, ${password}"); logManager.addOperationLog("User failed to register new account : ${email} , ${password} ."); isLoading.value = false; Get.snackbar( - 'failed'.tr, - 'user_registration_failed_please_try_again'.tr, + 'failed'.tr, // 失敗 + 'user_registration_failed_please_try_again'.tr, // ユーザー登録に失敗しました。 backgroundColor: Colors.red, colorText: Colors.white, icon: const Icon(Icons.error, size: 40.0, color: Colors.blue), snackPosition: SnackPosition.TOP, - duration: const Duration(milliseconds: 800), + duration: const Duration(seconds: 3), //backgroundColor: Colors.yellow, //icon:Image(image:AssetImage("assets/images/dora.png")) ); diff --git a/lib/pages/permission/permission.dart b/lib/pages/permission/permission.dart index 190689f..3294a83 100644 --- a/lib/pages/permission/permission.dart +++ b/lib/pages/permission/permission.dart @@ -4,21 +4,174 @@ import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:rogapp/services/location_service.dart'; import 'dart:developer' as developer; +import 'dart:async'; class PermissionController { - /* - static Future checkLocationPermissions() async { - debugPrint("(gifunavi)== checkLocationPermissions =="); - final alwaysPermission = await Permission.locationAlways.status; - final whenInUsePermission = await Permission.locationWhenInUse.status; - final locationPermission = await Permission.location.status; + static bool _isRequestingPermission = false; + static Completer? _permissionCompleter; - return (alwaysPermission == PermissionStatus.granted || whenInUsePermission == PermissionStatus.granted) && - (locationPermission == PermissionStatus.granted); + static Future checkLocationPermissions() async { + final locationPermission = await Permission.location.status; + final whenInUsePermission = await Permission.locationWhenInUse.status; + final alwaysPermission = await Permission.locationAlways.status; + + return locationPermission == PermissionStatus.granted && + (whenInUsePermission == PermissionStatus.granted || alwaysPermission == PermissionStatus.granted); } - */ + + static Future checkAndRequestPermissions() async { + if (_isRequestingPermission) { + return _permissionCompleter!.future; + } + + _isRequestingPermission = true; + _permissionCompleter = Completer(); + + bool hasPermissions = await checkLocationPermissions(); + if (!hasPermissions) { + bool userAgreed = await showLocationDisclosure(); + if (userAgreed) { + try { + await requestAllLocationPermissions(); + hasPermissions = await checkLocationPermissions(); + } catch (e) { + print('Error requesting location permissions: $e'); + hasPermissions = false; + } + } else { + print('User did not agree to location usage'); + hasPermissions = false; + // アプリを終了 + SystemNavigator.pop(); + } + } + + _isRequestingPermission = false; + _permissionCompleter!.complete(hasPermissions); + return _permissionCompleter!.future; + } + + static Future requestAllLocationPermissions() async { + await Permission.location.request(); + await Permission.locationWhenInUse.request(); + await Permission.locationAlways.request(); + + if (await Permission.locationAlways.isGranted) { + const platform = MethodChannel('location'); + try { + await platform.invokeMethod('startLocationService'); + } on PlatformException catch (e) { + debugPrint("Failed to start location service: '${e.message}'."); + } + } + } + + static Future showLocationDisclosure() async { + return await Get.dialog( + AlertDialog( + title: Text('位置情報の使用について'), + content: const SingleChildScrollView( + child: ListBody( + children: [ + Text('このアプリでは、以下の目的で位置情報を使用します:'), + Text('• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'), + Text('• 移動履歴の記録(バックグラウンドでも継続)'), + Text('• 現在地周辺の情報表示'), + Text('\nバックグラウンドでも位置情報を継続的に取得します。'), + Text('これにより、バッテリーの消費が増加する可能性があります。'), + Text('同意しない場合には、アプリは終了します。'), + ], + ), + ), + actions: [ + TextButton( + child: const Text('同意しない'), + onPressed: () => Get.back(result: false), + ), + TextButton( + child: const Text('同意する'), + onPressed: () => Get.back(result: true), + ), + ], + ), + barrierDismissible: false, + ) ?? false; + } + + static void showPermissionDeniedDialog(String title,String message) { + Get.dialog( + AlertDialog( + //title: Text('location_permission_needed_title'.tr), + title: Text(title.tr), + // 位置情報への許可が必要です + //content: Text('location_permission_needed_main'.tr), + content: Text(message.tr), + // 岐阜ロゲでは、位置情報を使用してスタート・チェックイン・ゴール等の通過照明及び移動手段の記録のために、位置情報のトラッキングを行なっています。このためバックグラウンドでもトラッキングができるように位置情報の権限が必要です。 + // 設定画面で、「岐阜ナビ」に対して、常に位置情報を許可するように設定してください。 + actions: [ + TextButton( + child: Text('キャンセル'), + onPressed: () => Get.back(), + ), + TextButton( + child: Text('設定'), + onPressed: () { + Get.back(); + openAppSettings(); + }, + ), + ], + ), + ); + } + + + + + +/* + static Future requestLocationPermissions(BuildContext context) async { + if (_isRequestingPermission) { + // If a request is already in progress, wait for it to complete + return _permissionCompleter!.future; + } + + _isRequestingPermission = true; + _permissionCompleter = Completer(); + + bool userAgreed = await showLocationDisclosure(context); + if (userAgreed) { + try { + final locationStatus = await Permission.location.request(); + final whenInUseStatus = await Permission.locationWhenInUse.request(); + final alwaysStatus = await Permission.locationAlways.request(); + + if (locationStatus == PermissionStatus.granted && + (whenInUseStatus == PermissionStatus.granted || alwaysStatus == PermissionStatus.granted)) { + _permissionCompleter!.complete(true); + } else { + showPermissionDeniedDialog('location_permission_needed_title', 'location_permission_needed_main'); + _permissionCompleter!.complete(false); + } + } catch (e) { + print('Error requesting location permission: $e'); + _permissionCompleter!.complete(false); + } + } else { + print('User did not agree to location usage'); + _permissionCompleter!.complete(false); + // Exit the app + SystemNavigator.pop(); + } + + _isRequestingPermission = false; + return _permissionCompleter!.future; + } +*/ + + static Future checkStoragePermission() async { //debugPrint("(gifunavi)== checkStoragePermission =="); @@ -42,6 +195,7 @@ class PermissionController { } + /* static Future checkLocationBasicPermission() async { //debugPrint("(gifunavi)== checkLocationBasicPermission =="); final locationPermission = await Permission.location.status; @@ -152,31 +306,8 @@ class PermissionController { } } - static void showPermissionDeniedDialog(String title,String message) { - Get.dialog( - AlertDialog( - //title: Text('location_permission_needed_title'.tr), - title: Text(title.tr), - // 位置情報への許可が必要です - //content: Text('location_permission_needed_main'.tr), - content: Text(message.tr), - // 岐阜ロゲでは、位置情報を使用してスタート・チェックイン・ゴール等の通過照明及び移動手段の記録のために、位置情報のトラッキングを行なっています。このためバックグラウンドでもトラッキングができるように位置情報の権限が必要です。 - // 設定画面で、「岐阜ナビ」に対して、常に位置情報を許可するように設定してください。 - actions: [ - TextButton( - child: Text('キャンセル'), - onPressed: () => Get.back(), - ), - TextButton( - child: Text('設定'), - onPressed: () { - Get.back(); - openAppSettings(); - }, - ), - ], - ), - ); - } + +*/ + } \ No newline at end of file diff --git a/lib/pages/register/register_page.dart b/lib/pages/register/register_page.dart index 21af082..e070c53 100644 --- a/lib/pages/register/register_page.dart +++ b/lib/pages/register/register_page.dart @@ -44,8 +44,8 @@ class RegisterPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( - "sign_up".tr, - style: TextStyle( + "sign_up".tr, // "サインアップ" + style: const TextStyle( fontSize: 30, fontWeight: FontWeight.bold, ), @@ -54,7 +54,7 @@ class RegisterPage extends StatelessWidget { height: 20, ), Text( - "create_account".tr, + "create_account".tr, // アカウントを無料で作成します。 style: TextStyle( fontSize: 15, color: Colors.grey[700], @@ -69,15 +69,15 @@ class RegisterPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 40), child: Column( children: [ - makeInput(label: "email".tr, controller: emailController), + makeInput(label: "email".tr, controller: emailController), // メールアドレス makeInput( label: "password".tr, controller: passwordController, - obsureText: true), + obsureText: true), // パスワード makeInput( label: "confirm_password".tr, controller: confirmPasswordController, - obsureText: true) + obsureText: true) // パスワード再確認 ], ), ), @@ -99,14 +99,14 @@ class RegisterPage extends StatelessWidget { if (passwordController.text != confirmPasswordController.text) { Get.snackbar( - "No match", - "Passwords does not match", + "no_match".tr, + "password_does_not_match".tr, backgroundColor: Colors.red, colorText: Colors.white, icon: const Icon(Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue), snackPosition: SnackPosition.TOP, - duration: const Duration(milliseconds: 800), + duration: const Duration(seconds: 3), // backgroundColor: Colors.yellow, //icon:Image(image:AssetImage("assets/images/dora.png")) ); @@ -121,7 +121,7 @@ class RegisterPage extends StatelessWidget { icon: const Icon(Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue), snackPosition: SnackPosition.TOP, - duration: const Duration(milliseconds: 800), + duration: const Duration(seconds: 3), //backgroundColor: Colors.yellow, //icon:Image(image:AssetImage("assets/images/dora.png")) ); diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 25d1f74..4bb3640 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -129,12 +129,14 @@ class AuthService { return cats; } + // ユーザー登録 + // static Future> register( String email, String password) async { Map cats = {}; String serverUrl = ConstValues.currentServer(); String url = '$serverUrl/api/register/'; - //print('++++++++$url'); + debugPrint('++++++++${url}'); final http.Response response = await http.post( Uri.parse(url), headers: { diff --git a/lib/utils/string_values.dart b/lib/utils/string_values.dart index a064dda..5953e65 100644 --- a/lib/utils/string_values.dart +++ b/lib/utils/string_values.dart @@ -30,7 +30,7 @@ class StringValues extends Translations{ 'visit_history': 'Visit History', 'rog_web': 'rog website', 'no_values': 'No Values', - 'email_and_password_required': 'Email and password required', + 'email_and_password_required': 'Email and password are required to register user', 'rogaining_user_need_tosign_up': "Rogaining participants do need to sign up.", 'add_location': 'Gifu', 'select_travel_mode':'Select your travel mode', @@ -211,6 +211,8 @@ class StringValues extends Translations{ 'reset_message': 'Are you ok to reset all data in this device?', 'reset_done': 'Reset Done.', 'reset_explain': 'All data has been reset. You should tap start rogaining to start game.', + 'no_match': 'No match!', + 'password_does_not_match':'The passwords you entered were not match.', }, 'ja_JP': { 'drawer_title':'ロゲイニング参加者はログイン するとチェックポイントが参照 できます', @@ -241,7 +243,7 @@ class StringValues extends Translations{ 'visit_history': '訪問履歴', 'rog_web': 'ロゲイニングウェブサイト', 'no_values': '値なし', - 'email_and_password_required': 'メールとパスワードが必要です', + 'email_and_password_required': 'メールとパスワードの入力が必要です', 'rogaining_user_need_tosign_up': "ロゲイニング参加者はサインアップの必要はありません。", 'add_location': '岐阜', 'select_travel_mode':'移動モードを選択してください', @@ -258,7 +260,7 @@ class StringValues extends Translations{ 'old_password' : '以前のパスワード', 'new_password' : '新しいパスワード', 'values_required' : '必要な値', - 'failed' : '失敗した', + 'failed' : '失敗', 'password_change_failed_please_try_again' : 'パスワードの変更に失敗しました。もう一度お試しください', 'user_registration_failed_please_try_again' : 'ユーザー登録に失敗しました。もう一度お試しください', 'all': '全て', @@ -424,6 +426,8 @@ class StringValues extends Translations{ 'reset_message': 'これにより、すべてのゲーム データが削除され、すべての状態が削除されます', 'reset_done': 'リセット完了', 'reset_explain': 'すべてリセットされました。ロゲ開始から再開して下さい。', + 'no_match': '不一致', + 'password_does_not_match':'入力したパスワードが一致しません', }, }; } diff --git a/pubspec.yaml b/pubspec.yaml index 9e17268..c1a9057 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.1+481 +version: 4.8.2+483 environment: sdk: ">=3.2.0 <4.0.0"