import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:rogapp/pages/destination/destination_controller.dart'; import 'package:rogapp/pages/index/index_controller.dart'; import 'package:rogapp/routes/app_pages.dart'; import 'package:rogapp/services/auth_service.dart'; import 'package:rogapp/utils/database_helper.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:rogapp/pages/WebView/WebView_page.dart'; // SafeAreaウィジェットを使用して、画面の安全領域内にメニューを表示しています。 // Columnウィジェットを使用して、メニューアイテムを縦に並べています。 // class DrawerPage extends StatelessWidget { DrawerPage({Key? key}) : super(key: key); final IndexController indexController = Get.find(); // 要検討:URLの起動に失敗した場合のエラーハンドリングが不十分です。適切なエラーメッセージを表示するなどの処理を追加してください。 // /* void _launchURL(url) async { if (!await launchUrl(url)) throw 'Could not launch $url'; } */ void _launchURL(BuildContext context,String urlString) async { try { Uri url = Uri.parse(urlString); if (await canLaunchUrl(url)) { await launchUrl(url); } else { // URLを開けない場合のフォールバック動作 // 例えば、WebViewを使用してアプリ内でURLを開く Navigator.push( context, MaterialPageRoute( builder: (context) => WebViewPage(url: urlString), ), ); } }catch(e){ // エラーメッセージを表示する ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('URLを開けませんでした: $e')), ); } } @override Widget build(BuildContext context) { return SafeArea( child: Drawer( // Add a ListView to the drawer. This ensures the user can scroll // through the options in the drawer if there isn't enough vertical // space to fit everything. child: Column( children: [ // 最初のアイテムは、ユーザーのログイン状態に応じて表示が変わります。 // ユーザーがログインしていない場合は、"drawer_title".trというテキストを表示します。 // ユーザーがログインしている場合は、ユーザーのメールアドレスを表示します。 Container( height: 100, color: Colors.amber, child: Obx(() => Center( child: Padding( padding: const EdgeInsets.all(8.0), child: indexController.currentUser.isEmpty ? Flexible( child: Text( "drawer_title".tr, style: const TextStyle( color: Colors.black, fontSize: 20), )) : Text( indexController.currentUser[0]['user']['email'], style: const TextStyle( color: Colors.black, fontSize: 20), ), ), )), ), // 次に、IndexControllerのcurrentUserリストが空かどうかに応じて、ログインまたはログアウトのアイテムを表示します。 // currentUserリストが空の場合は、"login".trというテキストのログインアイテムを表示し、タップするとAppPages.LOGINにナビゲートします。 // currentUserリストが空でない場合は、"logout".trというテキストのログアウトアイテムを表示し、タップするとindexController.logout()を呼び出してログアウトし、AppPages.LOGINにナビゲートします。 Obx(() => indexController.currentUser.isEmpty ? ListTile( leading: const Icon(Icons.login), title: Text("login".tr), onTap: () { Get.toNamed(AppPages.LOGIN); }, ) : ListTile( leading: const Icon(Icons.login), title: Text("logout".tr), onTap: () { indexController.logout(); Get.toNamed(AppPages.LOGIN); }, )), // パスワード変更のアイテムは、ユーザーがログインしている場合にのみ表示されます。 // "change_password".trというテキストを表示し、タップするとAppPages.CHANGE_PASSWORDにナビゲートします。 indexController.currentUser.isNotEmpty ? ListTile( leading: const Icon(Icons.password), title: Text("change_password".tr), onTap: () { Get.toNamed(AppPages.CHANGE_PASSWORD); }, ) : const SizedBox( width: 0, height: 0, ), // サインアップのアイテムは、ユーザーがログインしていない場合にのみ表示されます。 // "sign_up".trというテキストを表示し、タップするとAppPages.REGISTERにナビゲートします。 indexController.currentUser.isEmpty ? ListTile( leading: const Icon(Icons.person), title: Text("sign_up".tr), onTap: () { Get.toNamed(AppPages.REGISTER); }, ) : const SizedBox( width: 0, height: 0, ), // リセットのアイテムは、ユーザーがログインしている場合にのみ表示されます。 // タップすると、確認ダイアログを表示し、ユーザーがリセットを確認するとDestinationControllerのresetRogaining()メソッドを呼び出してゲームデータをリセットします。 indexController.currentUser.isNotEmpty ? ListTile( leading: const Icon(Icons.password), title: const Text("リセット"), onTap: () { // 要検討:リセット操作の確認メッセージをローカライズすることを検討してください。 // Get.defaultDialog( title: "リセットしますがよろしいですか?", middleText: "これにより、すべてのゲーム データが削除され、すべての状態が削除されます", textConfirm: "確認する", textCancel: "キャンセルする", onCancel: () => Get.back(), onConfirm: () async { DestinationController destinationController = Get.find(); DatabaseHelper databaseHelper = DatabaseHelper.instance; // ゲーム中のデータを削除 await databaseHelper.deleteAllRogaining(); await databaseHelper.deleteAllDestinations(); destinationController.resetRogaining(); //destinationController.resetRogaining(); //destinationController.deleteDBDestinations(); Get.back(); Get.snackbar( "リセット完了", "すべてリセットされました。ロゲ開始から再開して下さい。", backgroundColor: Colors.green, colorText: Colors.white, duration: const Duration(seconds: 3), ); }, ); }, ) : const SizedBox( width: 0, height: 0, ), // アカウント削除のアイテムは、ユーザーがログインしている場合にのみ表示されます。 // "delete_account".trというテキストを表示し、タップするとAuthService.deleteUser()を呼び出してアカウントを削除し、AppPages.TRAVELにナビゲートします。 indexController.currentUser.isNotEmpty ? ListTile( leading: const Icon(Icons.delete_forever), title: Text("delete_account".tr), onTap: () { Get.defaultDialog( title: "アカウントを削除しますがよろしいですか?", middleText: "これにより、アカウント情報とすべてのゲーム データが削除され、すべての状態が削除されます", textConfirm: "確認する", textCancel: "キャンセルする", onCancel: () => Get.back(), onConfirm: () { String token = indexController.currentUser[0]['token']; AuthService.deleteUser(token).then((value) { if (value.isNotEmpty) { indexController.logout(); Get.toNamed(AppPages.TRAVEL); Get.snackbar("accounted_deleted".tr, "account_deleted_message".tr, backgroundColor: Colors.green, colorText: Colors.white ); } }); }, ); }, ) : const SizedBox( width: 0, height: 0, ), /* // ユーザーデータ削除のアイテムは、ユーザーがログインしている場合にのみ表示されます。 // タップすると、AuthService.deleteUser()を呼び出してユーザーデータを削除します。 indexController.currentUser.isNotEmpty ? ListTile( // 要検討:アカウント削除のリクエストが失敗した場合のエラーハンドリングを追加することをお勧めします。 // leading: const Icon(Icons.delete_forever), title: Text("ユーザーデータを削除する".tr), onTap: () { Get.defaultDialog( title: "アカウントを削除しますがよろしいですか?", middleText: "これにより、アカウント情報とすべてのゲーム データが削除され、すべての状態が削除されます", textConfirm: "確認する", textCancel: "キャンセルする", onCancel: () => Get.back(), onConfirm: () { String token = indexController.currentUser[0]['token']; AuthService.deleteUser(token).then((value) { Get.snackbar("ユーザーデータを削除する", "データを削除するためにユーザーの同意が設定されています アプリとサーバーでユーザーデータが削除されました"); }); }); }, ) : const SizedBox( width: 0, height: 0, ), // ListTile( // leading: const Icon(Icons.person), // title: Text("profile".tr), // onTap: (){}, // ), // ListTile( // leading: const Icon(Icons.route), // title: Text("recommended_route".tr), // onTap: (){}, // ), // ListTile( // leading: const Icon(Icons.favorite_rounded), // title: Text("point_rank".tr), // onTap: (){}, // ), */ // "rog_web".trというテキストのアイテムは、ユーザーがログインしている場合にのみ表示されます。 // タップすると、_launchURL()メソッドを呼び出して外部のウェブサイトを開きます。 indexController.currentUser.isNotEmpty ? ListTile( leading: const Icon(Icons.featured_video), title: Text("rog_web".tr), onTap: () { _launchURL(context, "https://www.gifuai.net/?page_id=60043"); }, ) : const SizedBox( width: 0, height: 0, ), // "privacy".trというテキストのアイテムは、常に表示されます。 // タップすると、_launchURL()メソッドを呼び出してプライバシーポリシーのURLを開きます。 ListTile( leading: const Icon(Icons.privacy_tip), title: Text("privacy".tr), onTap: () { _launchURL(context, "https://rogaining.sumasen.net/api/privacy/"); }, ), ListTile( leading: const Icon(Icons.settings), title: const Text('設定'), onTap: () { Get.back(); // ドロワーを閉じる Get.toNamed(Routes.SETTINGS); }, ), ListTile( leading: const Icon(Icons.developer_mode), title: const Text('開発者メニュー'), onTap: () { Get.back(); // ドロワーを閉じる Get.toNamed('/debug'); // デバッグ画面に遷移 }, ), // ListTile( // leading: const Icon(Icons.router), // title: Text("my_route".tr), // onTap: (){}, // ), // ListTile( // leading: const Icon(Icons.history_sharp), // title: Text("visit_history".tr), // onTap: (){}, // ), ], ), ), ); } }