diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 6266644..58379ca 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,13 +1,58 @@ import Flutter import UIKit +import CoreMotion @main @objc class AppDelegate: FlutterAppDelegate { + private let motionManager = CMMotionManager() + override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + //GeneratedPluginRegistrant.register(with: self) + //return super.application(application, didFinishLaunchingWithOptions: launchOptions) + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + let motionChannel = FlutterMethodChannel(name: "com.yourcompany.app/motion", + binaryMessenger: controller.binaryMessenger) + motionChannel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + guard let self = self else { return } + + switch call.method { + case "startMotionUpdates": + self.startMotionUpdates(result: result) + case "stopMotionUpdates": + self.stopMotionUpdates(result: result) + default: + result(FlutterMethodNotImplemented) + } + }) + GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + private func startMotionUpdates(result: @escaping FlutterResult) { + if motionManager.isDeviceMotionAvailable { + motionManager.deviceMotionUpdateInterval = 0.1 + motionManager.startDeviceMotionUpdates(to: .main) { (motion, error) in + DispatchQueue.main.async { + // ここでUIの更新や状態の取得を行う + let appState = UIApplication.shared.applicationState + // 必要な処理を行う + } + } + result(nil) + } else { + result(FlutterError(code: "UNAVAILABLE", + message: "Device motion is not available.", + details: nil)) + } + } + + private func stopMotionUpdates(result: @escaping FlutterResult) { + motionManager.stopDeviceMotionUpdates() + result(nil) + } } diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fa..2541a97 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1,122 @@ { "images" : [ { - "size" : "20x20", + "filename" : "Icon-App-20x20@2x 1.png", "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { - "size" : "20x20", - "idiom" : "iphone", "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" }, { - "size" : "29x29", + "filename" : "Icon-App-29x29@1x 1.png", "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" + "scale" : "1x", + "size" : "29x29" }, { - "size" : "29x29", + "filename" : "Icon-App-29x29@2x 1.png", "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { - "size" : "29x29", - "idiom" : "iphone", "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" }, { - "size" : "40x40", + "filename" : "Icon-App-40x40@2x 1.png", "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" }, { - "size" : "40x40", - "idiom" : "iphone", "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" }, { - "size" : "60x60", - "idiom" : "iphone", "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" }, { - "size" : "20x20", - "idiom" : "ipad", "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" }, { - "size" : "20x20", - "idiom" : "ipad", "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" }, { - "size" : "29x29", - "idiom" : "ipad", "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" }, { - "size" : "29x29", - "idiom" : "ipad", "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" }, { - "size" : "40x40", - "idiom" : "ipad", "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" }, { - "size" : "40x40", - "idiom" : "ipad", "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" }, { - "size" : "76x76", - "idiom" : "ipad", "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" }, { - "size" : "76x76", - "idiom" : "ipad", "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-83.5x83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" }, { - "size" : "1024x1024", - "idiom" : "ios-marketing", "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } } diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index dc9ada4..e25381f 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 7353c41..3641719 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x 1.png new file mode 100644 index 0000000..683703e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x 1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 797d452..683703e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 6ed2d93..33f79d9 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x 1.png new file mode 100644 index 0000000..cc4b3ac Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x 1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cd7b00..cc4b3ac 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x 1.png new file mode 100644 index 0000000..c1b47e2 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x 1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index fe73094..c1b47e2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 321773c..c1e2731 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 797d452..683703e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x 1.png new file mode 100644 index 0000000..8a55696 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x 1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 502f463..8a55696 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 0ec3034..a14e94b 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 0ec3034..a14e94b 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index e9f5fea..1599df8 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 84ac32a..39ec196 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 8953cba..8106b9a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 0467bf1..a964c5e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json index 0bedcf2..29dd05f 100644 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { + "filename" : "Icon-App-1024x1024@1x 2.png", "idiom" : "universal", - "filename" : "LaunchImage.png", "scale" : "1x" }, { + "filename" : "Icon-App-1024x1024@1x 1.png", "idiom" : "universal", - "filename" : "LaunchImage@2x.png", "scale" : "2x" }, { + "filename" : "Icon-App-1024x1024@1x.png", "idiom" : "universal", - "filename" : "LaunchImage@3x.png", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } } diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x 1.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x 1.png new file mode 100644 index 0000000..e25381f Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x 1.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x 2.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x 2.png new file mode 100644 index 0000000..e25381f Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x 2.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..e25381f Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard index f2e259c..2662bd6 100644 --- a/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -14,24 +16,37 @@ + - + + + + + - - - - - + - + diff --git a/ios_setup/Info.plist b/ios_setup/Info.plist new file mode 100644 index 0000000..5d91f6a --- /dev/null +++ b/ios_setup/Info.plist @@ -0,0 +1,65 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + 岐阜ナビ + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + 岐阜ナビ + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSCameraUsageDescription + 岐阜ナビはチェックポイントで撮影した写真を写真ライブラリに保存し、通過記録を保持し、競技結果として提出することができます。 + NSLocationAlwaysAndWhenInUseUsageDescription + 岐阜ナビはアプリが閉じられているときでも位置情報へのアクセスが必要です。これにより、走行履歴の記録ができ、レビュー時の参考にすることができます。 + NSLocationAlwaysUsageDescription + このアプリではバックグラウンドで位置情報にアクセスします。 + NSLocationWhenInUseUsageDescription + このアプリはチェックポイントへのチェックインや走行履歴を記録するために、位置情報にアクセスします。 + NSMicrophoneUsageDescription + このアプリではカメラは使用しますが、マイクの使用は当面行いません。 + NSPhotoLibraryAddUsageDescription + 撮影した写真はデバイスのアルバムに保存されます。これにより、不具合時の通過記録を安全に担保することができます。 + NSPhotoLibraryUsageDescription + 撮影した写真はデバイスのアルバムに保存されます。これにより、不具合時の通過記録を安全に担保することができます。 + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + LSApplicationCategoryType + + + diff --git a/ios_setup/Runner/AppDelegate.swift b/ios_setup/Runner/AppDelegate.swift new file mode 100644 index 0000000..bf27570 --- /dev/null +++ b/ios_setup/Runner/AppDelegate.swift @@ -0,0 +1,56 @@ +import UIKit +import Flutter +import CoreMotion + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + private let motionManager = CMMotionManager() + + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + let motionChannel = FlutterMethodChannel(name: "com.yourcompany.app/motion", + binaryMessenger: controller.binaryMessenger) + motionChannel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + guard let self = self else { return } + + switch call.method { + case "startMotionUpdates": + self.startMotionUpdates(result: result) + case "stopMotionUpdates": + self.stopMotionUpdates(result: result) + default: + result(FlutterMethodNotImplemented) + } + }) + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + private func startMotionUpdates(result: @escaping FlutterResult) { + if motionManager.isDeviceMotionAvailable { + motionManager.deviceMotionUpdateInterval = 0.1 + motionManager.startDeviceMotionUpdates(to: .main) { (motion, error) in + DispatchQueue.main.async { + // ここでUIの更新や状態の取得を行う + let appState = UIApplication.shared.applicationState + // 必要な処理を行う + } + } + result(nil) + } else { + result(FlutterError(code: "UNAVAILABLE", + message: "Device motion is not available.", + details: nil)) + } + } + + private func stopMotionUpdates(result: @escaping FlutterResult) { + motionManager.stopDeviceMotionUpdates() + result(nil) + } +} diff --git a/ios_setup/services/main.dart b/ios_setup/services/main.dart new file mode 100644 index 0000000..4ae9d47 --- /dev/null +++ b/ios_setup/services/main.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:your_app/services/motion_service.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + // アプリの起動時にモーション更新を開始 + await MotionService.startMotionUpdates(); + + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + // ... アプリの設定 + ); + } +} + +// アプリケーションの状態が変わったときにモーション更新を停止/再開する +@override +void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.paused) { + MotionService.stopMotionUpdates(); + } else if (state == AppLifecycleState.resumed) { + MotionService.startMotionUpdates(); + } +} diff --git a/ios_setup/services/motion_service.dart b/ios_setup/services/motion_service.dart new file mode 100644 index 0000000..1817c2d --- /dev/null +++ b/ios_setup/services/motion_service.dart @@ -0,0 +1,21 @@ +import 'package:flutter/services.dart'; + +class MotionService { + static const MethodChannel _channel = MethodChannel('com.yourcompany.app/motion'); + + static Future startMotionUpdates() async { + try { + await _channel.invokeMethod('startMotionUpdates'); + } on PlatformException catch (e) { + print("Failed to start motion updates: '${e.message}'."); + } + } + + static Future stopMotionUpdates() async { + try { + await _channel.invokeMethod('stopMotionUpdates'); + } on PlatformException catch (e) { + print("Failed to stop motion updates: '${e.message}'."); + } + } +} diff --git a/lib/main.dart b/lib/main.dart index 61d31df..154e1ef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -43,6 +43,8 @@ import 'package:gifunavi/provider/cached_tile_provider.dart'; import 'package:timezone/timezone.dart' as tz; +import 'package:gifunavi/services/motion_service.dart'; + Map deviceInfo = {}; /* @@ -70,7 +72,9 @@ Future saveGameState() async { if(indexController.currentUser[0]["user"]["event_date"]!=null) { final date = indexController.currentUser[0]["user"]["event_date"]; pref.setString('eventDate', date.toIso8601String()); + debugPrint("Saved date is ${date} => ${date.toIso8601String()}"); + 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"]); @@ -197,6 +201,11 @@ void _showEventSelectionWarning() { void main() async { WidgetsFlutterBinding.ensureInitialized(); + if (Platform.isIOS) { + // アプリの起動時にモーション更新を開始 + await MotionService.startMotionUpdates(); + } + final IndexController _indexController; FlutterError.onError = (FlutterErrorDetails details) { @@ -207,20 +216,7 @@ void main() async { }; try { - //await Get.putAsync(() => ApiService().init()); - await _initApiService(); - debugPrint("1: start ApiService"); - // すべてのコントローラーとサービスを非同期で初期化 - Get.lazyPut(() => IndexController(apiService: Get.find())); - debugPrint("2: start IndexController"); - - - // その他のコントローラーを遅延初期化 - Get.lazyPut(() => SettingsController()); - debugPrint("2: start SettingsController"); - Get.lazyPut(() => DestinationController()); - debugPrint("3: start DestinationController"); await initServices(); @@ -237,12 +233,37 @@ void main() async { Future initServices() async { print('Starting services ...'); try { + //await Get.putAsync(() => ApiService().init()); + await _initApiService(); + debugPrint("1: start ApiService"); + + // コントローラーを初期化 + Get.put(IndexController(apiService: Get.find()), permanent: true); + Get.put(SettingsController(), permanent: true); + Get.put(DestinationController(), permanent: true); + Get.put(LocationController(), permanent: true); + + debugPrint("2: Controllers initialized"); + /* + // すべてのコントローラーとサービスを非同期で初期化 + Get.lazyPut(() => IndexController(apiService: Get.find())); + debugPrint("2: start IndexController"); + + // その他のコントローラーを遅延初期化 + Get.lazyPut(() => SettingsController()); + debugPrint("2: start SettingsController"); + Get.lazyPut(() => DestinationController()); + debugPrint("3: start DestinationController"); + Get.lazyPut(() => LocationController()); + debugPrint("4: start LocationController"); + */ // 非同期処理を並列実行 await Future.wait([ _initTimeZone(), _initCacheProvider(), ]); + print('=== 5. Initialized TimeZone...'); print('=== 6. CacheProvider started...'); @@ -520,6 +541,7 @@ class _MyAppState extends State with WidgetsBindingObserver { late final DestinationController _destinationController; late final PermissionController _permissionController; Timer? _memoryCheckTimer; + bool _isControllerInitialized = false; @override void initState() { @@ -545,24 +567,94 @@ class _MyAppState extends State with WidgetsBindingObserver { // ここに他の初期化処理を追加できます } - void _initializeControllers() { + Future _initializeControllers() async { + + while (!Get.isRegistered() || + !Get.isRegistered() || + !Get.isRegistered() || + !Get.isRegistered()) { + await Future.delayed(const Duration(milliseconds: 100)); + } + + if (!_isControllerInitialized) { + _locationController = Get.find(); + _indexController = Get.find(); + _destinationController = Get.find(); + _permissionController = Get.find(); + _isControllerInitialized = true; + } + /* - if (!Get.isRegistered()) { + while (true) { + try { + _locationController = Get.find(); + break; // DestinationControllerが見つかったらループを抜ける + } catch (e) { + // DestinationControllerがまだ利用可能でない場合は少し待ってから再試行 + await Future.delayed(const Duration(milliseconds: 100)); + } + } + */ + /* + if (!Get.isRegistered()) { _locationController = Get.put(LocationController(), permanent: true); } + */ + + /* + while (true) { + try { + _indexController = Get.find(); + break; // DestinationControllerが見つかったらループを抜ける + } catch (e) { + // DestinationControllerがまだ利用可能でない場合は少し待ってから再試行 + await Future.delayed(const Duration(milliseconds: 100)); + } + } + */ + /* if (!Get.isRegistered()) { _indexController = Get.put(IndexController(apiService: Get.find()), permanent: true); } + */ + + /* + while (true) { + try { + _destinationController = Get.find(); + break; // DestinationControllerが見つかったらループを抜ける + } catch (e) { + // DestinationControllerがまだ利用可能でない場合は少し待ってから再試行 + await Future.delayed(const Duration(milliseconds: 100)); + } + } + */ + /* if (!Get.isRegistered()) { _destinationController = Get.put(DestinationController(), permanent: true); } + */ + + /* + while (true) { + try { + _permissionController = Get.find(); + break; // DestinationControllerが見つかったらループを抜ける + } catch (e) { + // DestinationControllerがまだ利用可能でない場合は少し待ってから再試行 + await Future.delayed(const Duration(milliseconds: 100)); + } + } + */ + /* if (!Get.isRegistered()) { _permissionController = Get.put(PermissionController()); } + */ // 他の必要なコントローラーの初期化 - */ + } void _startMemoryMonitoring() { @@ -677,6 +769,7 @@ class _MyAppState extends State with WidgetsBindingObserver { @override void dispose() { + _isControllerInitialized = false; WidgetsBinding.instance.removeObserver(this); _memoryCheckTimer?.cancel(); super.dispose(); @@ -704,6 +797,9 @@ class _MyAppState extends State with WidgetsBindingObserver { switch (state) { case AppLifecycleState.resumed: + if (Platform.isIOS) { + MotionService.startMotionUpdates(); + } //await _onResumed(); await _onResumed(); break; @@ -714,6 +810,7 @@ class _MyAppState extends State with WidgetsBindingObserver { break; case AppLifecycleState.paused: + MotionService.stopMotionUpdates(); // バックグラウンドに移行したときの処理 //locationController.resumePositionStream(); await _onPaused(); @@ -740,7 +837,9 @@ class _MyAppState extends State with WidgetsBindingObserver { Future _onResumed() async { debugPrint("==(Status Changed)==> RESUMED"); try { - _initializeControllers(); + if (!_isControllerInitialized) { + await _initializeControllers(); + } await stopBackgroundTracking(); _destinationController.restartGPS(); diff --git a/lib/pages/camera/camera_page.dart b/lib/pages/camera/camera_page.dart index 9c79c2d..4aadbdb 100644 --- a/lib/pages/camera/camera_page.dart +++ b/lib/pages/camera/camera_page.dart @@ -311,7 +311,7 @@ class CameraPage extends StatelessWidget { ? ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () async { - await destinationController.makeCheckin(destination, true, + await destinationController.makeCheckin(destination, true, // チェクインボタン destinationController.photos[0].path); if( destinationController.isInRog.value==true ) { destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可 @@ -526,7 +526,7 @@ class CameraPage extends StatelessWidget { // print( // "##### current destination ${indexController.currentDestinationFeature[0].sub_loc_id} #######"); - await destinationController.makeCheckin( + await destinationController.makeCheckin( // チェックイン確定 indexController.currentDestinationFeature[0], true, destinationController.photos[0].path); @@ -551,7 +551,7 @@ class CameraPage extends StatelessWidget { Navigator.of(context).pop(true); // ここを修正 }, - child: const Text("チェックイン")) + child: const Text("チェックイン確定")) : Container()) ], ); diff --git a/lib/pages/destination/destination_controller.dart b/lib/pages/destination/destination_controller.dart index 259e911..6b8b184 100644 --- a/lib/pages/destination/destination_controller.dart +++ b/lib/pages/destination/destination_controller.dart @@ -526,7 +526,7 @@ class DestinationController extends GetxController { debugPrint("** 自動チェックインの場合"); //print( // "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ make checkin ${d.sub_loc_id}@@@@@@@@@@@"); - makeCheckin(d, true, ""); // チェックインして + makeCheckin(d, true, ""); // 自動チェックイン //if (d.cp != -1 && d.cp != -2 && d.cp != 0 ) { // rogainingCounted.value = true; // ゴール用チェックイン済み //} @@ -750,9 +750,11 @@ class DestinationController extends GetxController { } int? latgoal = await db.latestGoal(); - lastGoalAt = DateTime.fromMicrosecondsSinceEpoch(latgoal!); - debugPrint("===== last goal : $lastGoalAt ====="); + if( latgoal != null ) { + lastGoalAt = DateTime.fromMicrosecondsSinceEpoch(latgoal!); + debugPrint("===== last goal : $lastGoalAt ====="); dbService.updateDatabase(); + } } // すべての目的地を削除する関数です。 @@ -835,7 +837,7 @@ class DestinationController extends GetxController { print("---- f- checkin ${d.sub_loc_id} ----"); if (autoCheckin) { if (!checkingIn) { - makeCheckin(d, true, ""); + makeCheckin(d, true, ""); // callforCheckin if (d.cp != -1 && d.cp != 0 && d.cp != -2) { rogainingCounted.value = true; } @@ -1085,12 +1087,13 @@ class DestinationController extends GetxController { // ロゲイニングにデータを追加する関数です。 // void addToRogaining(double lat, double lon, int destinationId) async { + debugPrint("addToRogaining .... "); DatabaseHelper db = DatabaseHelper.instance; List d = await db.getDestinationById(destinationId); if (d.isEmpty) { Destination df = festuretoDestination(indexController.currentFeature[0]); //print("--- made checkin ${df.location_id} ----"); - makeCheckin(df, true, ""); + makeCheckin(df, true, ""); // addToRogaining } isInRog.value = true; @@ -1138,10 +1141,10 @@ class DestinationController extends GetxController { // ギャラリーにも保存 //await ImageGallerySaver.saveFile(savedImage.path); - await Future.delayed(const Duration(seconds: 3), () async { + await Future.delayed(const Duration(seconds: 5), () async { final result = await ImageGallerySaver.saveFile(savedImage.path); print("Save result: $result"); - }).timeout(const Duration(seconds: 5)); + }).timeout(const Duration(seconds: 7)); debugPrint('Image saved to: ${savedImage.path}'); @@ -1214,14 +1217,16 @@ class DestinationController extends GetxController { // print( // "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ressssss ${destination.sub_loc_id}@@@@@@@@@@@"); DatabaseHelper db = DatabaseHelper.instance; - List ddd = - await db.getDestinationByLatLon(destination.lat!, destination.lon!); + List ddd = await db.getDestinationByLatLon(destination.lat!, destination.lon!); if (ddd.isEmpty) { destination.checkedin = true; + debugPrint("...近くにCPがないのにチェックイン?...makeCheckin imageUrl = $imageurl"); if (imageurl.isNotEmpty) { String? savedImagePath = await _saveImageToGallery(imageurl); destination.checkin_image = savedImagePath ?? imageurl; + }else{ + debugPrint("makeCheckin ... No image..."); } await db.insertDestination(destination); // print("~~~~ inserted into db ~~~~"); @@ -1229,15 +1234,18 @@ class DestinationController extends GetxController { if (imageurl.isEmpty) { if (photos.isNotEmpty) { + debugPrint("imageurlが空の場合は、destinationのcheckin_imageプロパティを使用する"); // imageurlが空の場合は、destinationのcheckin_imageプロパティを使用する - debugPrint("photos = $photos"); - imageurl = photos[0].path; + //debugPrint("photos = $photos"); + //imageurl = photos[0].path; } debugPrint("imageurl = $imageurl"); //await _saveImageFromPath(imageurl!); } if (imageurl.isNotEmpty) { + debugPrint("...これでアルバム保存...makeCheckin imageUrl = $imageurl"); String? savedImagePath = await _saveImageToGallery(imageurl); + debugPrint("イメージのアルバム保存完了!!"); destination.checkin_image = savedImagePath ?? imageurl; } diff --git a/lib/pages/index/index_controller.dart b/lib/pages/index/index_controller.dart index 7b934ae..2241676 100644 --- a/lib/pages/index/index_controller.dart +++ b/lib/pages/index/index_controller.dart @@ -96,6 +96,8 @@ class IndexController extends GetxController with WidgetsBindingObserver { final selectedEventName = 'add_location'.tr.obs; + RxBool isLoadingLocations = true.obs; + void setSelectedEventName(String eventName) { selectedEventName.value = eventName; } @@ -256,6 +258,9 @@ class IndexController extends GetxController with WidgetsBindingObserver { tz.initializeTimeZones(); //teamController = Get.find(); + + loadLocations(); + }catch(e,stacktrace){ print('Error in IndexController.onInit: $e'); print('Stack trace: $stacktrace'); @@ -265,6 +270,20 @@ class IndexController extends GetxController with WidgetsBindingObserver { } } + Future loadLocations() async { + isLoadingLocations.value = true; + try { + await waitForMapControllerReady(); + String eventCode = currentUser.isNotEmpty ? currentUser[0]["user"]["event_code"] ?? "" : ""; + await loadLocationsBound(eventCode); + } catch (e) { + print('Error loading locations: $e'); + // エラーハンドリングを追加(例:スナックバーでユーザーに通知) + } finally { + isLoadingLocations.value = false; + } + } + void _updateConnectionStatus(List results) { final result = results.isNotEmpty ? results.first : ConnectivityResult.none; @@ -873,7 +892,7 @@ class IndexController extends GetxController with WidgetsBindingObserver { // 要検討:Future.delayedを使用して非同期処理を待たずに先に進むようにしていますが、 // これによってメモリリークが発生する可能性があります。非同期処理の結果を適切に処理することを検討してください。 // - void loadLocationsBound(String eventCode) async { + Future loadLocationsBound(String eventCode) async { if (isCustomAreaSelected.value == true) { return; } @@ -881,6 +900,19 @@ class IndexController extends GetxController with WidgetsBindingObserver { // MapControllerの初期化が完了するまで待機 await waitForMapControllerReady(); + // null チェックを追加 + if (mapController.bounds == null) { + print("MapController bounds are null"); + return; + } + + // バウンドが有効かどうかを確認する + LatLngBounds bounds = mapController.bounds!; + if (!_isValidBounds(bounds)) { + print("MapController bounds are not valid"); + return; + } + locations.clear(); String cat = currentCat.isNotEmpty ? currentCat[0] : ""; if (currentCat.isNotEmpty && currentCat[0] == "-all-") { @@ -896,7 +928,7 @@ class IndexController extends GetxController with WidgetsBindingObserver { // */ - LatLngBounds bounds = mapController.bounds!; + //LatLngBounds bounds = mapController.bounds!; currentBound.clear(); currentBound.add(bounds); @@ -987,6 +1019,15 @@ class IndexController extends GetxController with WidgetsBindingObserver { } + // バウンドが有効かどうかを確認するヘルパーメソッド + bool _isValidBounds(LatLngBounds bounds) { + // 緯度と経度が有効な範囲内にあるかチェック + return bounds.southWest.latitude.abs() <= 90 && + bounds.southWest.longitude.abs() <= 180 && + bounds.northEast.latitude.abs() <= 90 && + bounds.northEast.longitude.abs() <= 180 && + bounds.southWest.latitude < bounds.northEast.latitude; + } //===Akira 追加:2024-4-6 #2800 // 要検討:MapControllerの初期化が完了するまで待機していますが、タイムアウトを設定することを検討してください。 diff --git a/lib/pages/index/index_page.dart b/lib/pages/index/index_page.dart index 4813a16..fb2f737 100644 --- a/lib/pages/index/index_page.dart +++ b/lib/pages/index/index_page.dart @@ -8,6 +8,8 @@ import 'package:gifunavi/widgets/list_widget.dart'; import 'package:gifunavi/widgets/map_widget.dart'; import 'package:gifunavi/utils/location_controller.dart'; +import '../permission/permission.dart'; + // index_page.dartファイルの主な内容です。 // このファイルは、アプリのメインページのUIを構築し、各機能へのナビゲーションを提供しています。 // また、IndexControllerとDestinationControllerを使用して、状態管理と各種機能の実装を行っています。 @@ -36,12 +38,20 @@ class _IndexPageState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - //checkLoginAndShowDialog(); - //checkEventAndNavigate(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await _ensureControllersAreInitialized(); + await PermissionController.checkAndRequestPermissions(); }); } + Future _ensureControllersAreInitialized() async { + while (!Get.isRegistered() || + !Get.isRegistered() || + !Get.isRegistered()) { + await Future.delayed(const Duration(milliseconds: 100)); + } + } + void checkEventAndNavigate() async { if (indexController.currentUser.isNotEmpty && indexController.currentUser[0]["user"]["event_code"] == null) { diff --git a/lib/pages/permission/permission.dart b/lib/pages/permission/permission.dart index 073b935..cba56a6 100644 --- a/lib/pages/permission/permission.dart +++ b/lib/pages/permission/permission.dart @@ -126,28 +126,27 @@ class PermissionController { _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'); + try { + bool hasPermissions = await _checkLocationPermissions(); + if (!hasPermissions) { + bool userAgreed = await showLocationDisclosure(); + if (userAgreed) { + hasPermissions = await _requestAllLocationPermissions(); + } else { + print('User did not agree to location usage'); hasPermissions = false; + // アプリを終了 + SystemNavigator.pop(); } - } else { - print('User did not agree to location usage'); - hasPermissions = false; - // アプリを終了 - SystemNavigator.pop(); } + + _isRequestingPermission = false; + _permissionCompleter!.complete(hasPermissions); + } catch( e ) { + print('Error in permission request: $e'); + _isRequestingPermission = false; + _permissionCompleter!.complete(false); } - - _isRequestingPermission = false; - _permissionCompleter!.complete(hasPermissions); - debugPrint("Finish checkAndRequestPermissions..."); return _permissionCompleter!.future; } diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 5c18d72..a3f05d5 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -108,7 +108,22 @@ class AuthService { if (response.statusCode == 200) { cats = json.decode(utf8.decode(response.bodyBytes)); } else { + debugPrint('Response body: ${response.body}'); + print('Login failed with status code: ${response.statusCode}'); + var errorMessage = 'ログインに失敗しました。'; + if (response.statusCode == 400) { + var errorBody = json.decode(utf8.decode(response.bodyBytes)); + errorMessage = errorBody['non_field_errors']?[0] ?? 'パスワードが正しくありません。'; + } + Get.snackbar( + "エラー", + errorMessage, + backgroundColor: Colors.red, + colorText: Colors.white, + snackPosition: SnackPosition.TOP, + duration: const Duration(seconds: 3), + ); cats = {}; } } catch( e ){ diff --git a/lib/services/external_service.dart b/lib/services/external_service.dart index 3b5b6ca..a518d96 100644 --- a/lib/services/external_service.dart +++ b/lib/services/external_service.dart @@ -80,7 +80,7 @@ class ExternalService { {'team_name': team, 'event_code': eventCode}), ); - //print("---- start rogianing api status ---- ${response.statusCode}"); + print("---- start rogianing api status ---- ${response.statusCode}"); if (response.statusCode == 200) { res = json.decode(utf8.decode(response.bodyBytes)); diff --git a/lib/services/motion_service.dart b/lib/services/motion_service.dart new file mode 100644 index 0000000..5b40618 --- /dev/null +++ b/lib/services/motion_service.dart @@ -0,0 +1,29 @@ +import 'package:flutter/services.dart'; +import 'dart:io'; + +class MotionService { + static const MethodChannel _channel = MethodChannel('net.sumasen.gifunavi/motion'); + + static Future startMotionUpdates() async { + if (Platform.isIOS) { + try { + await _channel.invokeMethod('startMotionUpdates'); + } on PlatformException catch (e) { + print("Failed to start motion updates: '${e.message}'."); + } + } else{ + // Android の場合は何もしない、またはAndroid向けの代替実装を行う + print("Motion updates not supported on this platform"); + } + } + + static Future stopMotionUpdates() async { + if (Platform.isIOS) { + try { + await _channel.invokeMethod('stopMotionUpdates'); + } on PlatformException catch (e) { + print("Failed to stop motion updates: '${e.message}'."); + } + } + } +} \ No newline at end of file diff --git a/lib/widgets/bottom_sheet_new.dart b/lib/widgets/bottom_sheet_new.dart index ac41767..89bcea5 100644 --- a/lib/widgets/bottom_sheet_new.dart +++ b/lib/widgets/bottom_sheet_new.dart @@ -139,16 +139,23 @@ class BottomSheetNew extends GetView { } Future saveTemporaryImage(Destination destination) async { - final serverUrl = ConstValues.currentServer(); - final imagePath = '$serverUrl/media/compressed/${destination.photos}'; + try { + final serverUrl = ConstValues.currentServer(); + final imagePath = '$serverUrl/media/compressed/${destination.photos}'; - final tempDir = await getTemporaryDirectory(); - final tempFile = await File('${tempDir.path}/temp_image.jpg').create(recursive: true); - final response = await http.get(Uri.parse(imagePath)); - await tempFile.writeAsBytes(response.bodyBytes); + debugPrint("imagePath = $imagePath"); - destinationController.photos.clear(); - destinationController.photos.add(tempFile); + final tempDir = await getTemporaryDirectory(); + final tempFile = await File('${tempDir.path}/temp_image.jpg').create( + recursive: true); + final response = await http.get(Uri.parse(imagePath)); + await tempFile.writeAsBytes(response.bodyBytes); + + destinationController.photos.clear(); + destinationController.photos.add(tempFile); + } catch( e ) { + debugPrint("saveTemporaryImage error : $e"); + } } // アクションボタン(チェックイン、ゴールなど)を表示するためのメソッドです。 @@ -239,12 +246,8 @@ class BottomSheetNew extends GetView { return; } - - - destinationController.isInRog.value = true; - // Show confirmation dialog Get.dialog( AlertDialog( @@ -270,6 +273,7 @@ class BottomSheetNew extends GetView { // Clear data and start game logic here destinationController.resetRogaining(); + // ここでチェックインもしている。 destinationController.addToRogaining( destinationController.currentLat, destinationController.currentLon, @@ -996,15 +1000,12 @@ class BottomSheetNew extends GetView { Obx((() => indexController.rogMode.value == 1 ? ElevatedButton( onPressed: () async { - Destination dest = - indexController.currentDestinationFeature[0]; - //print("~~~~ before checking button ~~~~"); + Destination dest = indexController.currentDestinationFeature[0]; + print("~~~~ before checking button ~~~~"); //print("------ curent destination is ${dest!.checkedIn}-------"); - destinationController.makeCheckin( - dest, !dest.checkedin!, ""); + destinationController.makeCheckin( dest, !dest.checkedin!, ""); }, - child: indexController - .currentDestinationFeature[0].checkedin == + child: indexController.currentDestinationFeature[0].checkedin == false ? const Text("チェックイン") : const Text("チェックアウト")) diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index b0ede84..c21033f 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -140,12 +140,25 @@ class _MapWidgetState extends State with WidgetsBindingObserver { */ // _centerMapOnUser を10秒間でコール - void _startIdleTimer() { + Future _startIdleTimer() async { //debugPrint("_startIdleTimer ...."); - final settingsController = Get.find(); + SettingsController settingsController; + + // SettingsControllerが利用可能になるまで待機 + while (true) { + try { + settingsController = Get.find(); + break; // SettingsControllerが見つかったらループを抜ける + } catch (e) { + // SettingsControllerがまだ利用可能でない場合は少し待ってから再試行 + await Future.delayed(const Duration(milliseconds: 100)); + } + } + if (!settingsController.autoReturnDisabled.value) { _timer = Timer(settingsController.timerDuration.value, _centerMapOnUser); } + } // タイマーをリセットして_startIdleTimer をコール @@ -173,7 +186,16 @@ class _MapWidgetState extends State with WidgetsBindingObserver { Future> _getMarkers() async { debugPrint('Getting markers...'); - List markers = []; + if (indexController.isLoadingLocations.value) { + await Future.doWhile(() async { + await Future.delayed(const Duration(milliseconds: 100)); + return indexController.isLoadingLocations.value; + }); + } + + debugPrint('Getting markers...'); + + List markers = []; if (indexController.locations.isNotEmpty && indexController.locations[0].features.isNotEmpty) { for (var feature in indexController.locations[0].features) { GeoJSONMultiPoint point = feature!.geometry as GeoJSONMultiPoint;