2024-09-02 ほぼOK
29
.metadata
@ -1,11 +1,11 @@
|
|||||||
# This file tracks properties of this Flutter project.
|
# This file tracks properties of this Flutter project.
|
||||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
#
|
#
|
||||||
# This file should be version controlled.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
|
revision: "5874a72aa4c779a02553007c47dacbefba2374dc"
|
||||||
channel: stable
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
|
|
||||||
@ -13,11 +13,26 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
- platform: android
|
||||||
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
- platform: ios
|
- platform: ios
|
||||||
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
- platform: linux
|
||||||
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
- platform: macos
|
||||||
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
- platform: web
|
||||||
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
- platform: windows
|
||||||
|
create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|||||||
34
README.md
@ -15,6 +15,29 @@ For help getting started with Flutter development, view the
|
|||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
samples, guidance on mobile development, and a full API reference.
|
samples, guidance on mobile development, and a full API reference.
|
||||||
|
|
||||||
|
## iOS のマニュアル更新内容
|
||||||
|
|
||||||
|
* Info.plist
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>岐阜ナビ</string>
|
||||||
|
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>岐阜ナビ</string>
|
||||||
|
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>岐阜ナビはチェックポイントで撮影した写真を写真ライブラリに保存し、通過記録を保持し、競技結果として提出することができます。</string>
|
||||||
|
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||||
|
<string>岐阜ナビはアプリが閉じられているときでも位置情報へのアクセスが必要です。これにより、走行履歴の記録ができ、レビュー時の参考にすることができます。</string>
|
||||||
|
<key>NSLocationAlwaysUsageDescription</key>
|
||||||
|
<string>このアプリではバックグラウンドで位置情報にアクセスします。</string>
|
||||||
|
<key>NSLocationWhenInUseUsageDescription</key>
|
||||||
|
<string>このアプリはチェックポイントへのチェックインや走行履歴を記録するために、位置情報にアクセスします。</string>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>このアプリではカメラは使用しますが、マイクの使用は当面行いません。</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>撮影した写真はデバイスのアルバムに保存されます。これにより、不具合時の通過記録を安全に担保することができます。</string>
|
||||||
|
|
||||||
|
|
||||||
# 更新履歴
|
# 更新履歴
|
||||||
|
|
||||||
0. flutter_compass は pub.dev cache で 34 に変更。キャッシュをクリアしたら修正が必要。
|
0. flutter_compass は pub.dev cache で 34 に変更。キャッシュをクリアしたら修正が必要。
|
||||||
@ -157,4 +180,13 @@ samples, guidance on mobile development, and a full API reference.
|
|||||||
テスト用位置情報:
|
テスト用位置情報:
|
||||||
大垣駅: 35.36701369466119, 136.61783662683948
|
大垣駅: 35.36701369466119, 136.61783662683948
|
||||||
大垣城: 35.36182698266251, 136.61558088722234
|
大垣城: 35.36182698266251, 136.61558088722234
|
||||||
関ケ原駅:35.36365422752628, 136.47061844402452
|
関ケ原駅:35.36365422752628, 136.47061844402452
|
||||||
|
高山駅:36.14130783620718, 137.25050201764944
|
||||||
|
ガソリンスタンド:36.13826570797936, 137.21513450124928
|
||||||
|
|
||||||
|
バグ:
|
||||||
|
履歴の写真:アクセスエラー
|
||||||
|
バックアップをイベントごとに保存・レストア
|
||||||
|
|
||||||
|
ログインした際に、イベントが選択されていなければ、イベントを選択するように促す。
|
||||||
|
事前チェックインした写真が履歴に表示されない。
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.dvox.gifunavi_git
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity()
|
||||||
3
devtools_options.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
||||||
@ -4,6 +4,8 @@ PODS:
|
|||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- device_info_plus (0.0.1):
|
||||||
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_compass (0.0.1):
|
- flutter_compass (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -43,6 +45,7 @@ PODS:
|
|||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||||
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_compass (from `.symlinks/plugins/flutter_compass/ios`)
|
- flutter_compass (from `.symlinks/plugins/flutter_compass/ios`)
|
||||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||||
@ -68,6 +71,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/camera_avfoundation/ios"
|
:path: ".symlinks/plugins/camera_avfoundation/ios"
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
:path: ".symlinks/plugins/connectivity_plus/darwin"
|
:path: ".symlinks/plugins/connectivity_plus/darwin"
|
||||||
|
device_info_plus:
|
||||||
|
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_compass:
|
flutter_compass:
|
||||||
@ -102,6 +107,7 @@ EXTERNAL SOURCES:
|
|||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
camera_avfoundation: dd002b0330f4981e1bbcb46ae9b62829237459a4
|
camera_avfoundation: dd002b0330f4981e1bbcb46ae9b62829237459a4
|
||||||
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
|
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
|
||||||
|
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_compass: cbbd285cea1584c7ac9c4e0c3e1f17cbea55e855
|
flutter_compass: cbbd285cea1584c7ac9c4e0c3e1f17cbea55e855
|
||||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||||
|
|||||||
@ -8,14 +8,14 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
2EAA11F0595B6B1A6B6ADED8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53C8E795FF5969F8C7B6A237 /* Pods_RunnerTests.framework */; };
|
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
712BA8D3720206B23B820A9B /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4E153E327A403FD75830D36 /* Pods_RunnerTests.framework */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
|
8B39E7104A3E3C6F3B501CB2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A39AA3BE6DA0B7B42041019 /* Pods_Runner.framework */; };
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
B6A4962F862B554C98AD7E0A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F31FDD2E828C96A459E4AA85 /* Pods_Runner.framework */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -46,14 +46,16 @@
|
|||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
3592C2DA8DF570D2D07650A8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
53C8E795FF5969F8C7B6A237 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
402073277F0CF7D1DE2A9F29 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
6850CF9EE994EB8682BD460F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
6A39AA3BE6DA0B7B42041019 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
6FFD6A432600780CEB6D6374 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
84738EC4DA98A3780DDAB81F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
86D6A3692EBE5943C3C75411 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
89205C63F97F88BDB459168E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
89EEC485D24E5B1BC0DD7B8E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -61,10 +63,8 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
AC42218FD0A0DB137D157E93 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
9E76BC5648643A00E08CF70B /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
D773E9161AA2211A3E2B94DD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
C4E153E327A403FD75830D36 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DA00EBAA91366A0B5BFDAE96 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
F31FDD2E828C96A459E4AA85 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -72,15 +72,15 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
B6A4962F862B554C98AD7E0A /* Pods_Runner.framework in Frameworks */,
|
8B39E7104A3E3C6F3B501CB2 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
CEDA9491D04A70CE2A58DF32 /* Frameworks */ = {
|
F68F88FFE2DC7D6754431798 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
2EAA11F0595B6B1A6B6ADED8 /* Pods_RunnerTests.framework in Frameworks */,
|
712BA8D3720206B23B820A9B /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -95,11 +95,24 @@
|
|||||||
path = RunnerTests;
|
path = RunnerTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
3806CD679A8B2BB869428B93 /* Frameworks */ = {
|
7F718872327E3605229882F1 /* Pods */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
F31FDD2E828C96A459E4AA85 /* Pods_Runner.framework */,
|
402073277F0CF7D1DE2A9F29 /* Pods-Runner.debug.xcconfig */,
|
||||||
53C8E795FF5969F8C7B6A237 /* Pods_RunnerTests.framework */,
|
3592C2DA8DF570D2D07650A8 /* Pods-Runner.release.xcconfig */,
|
||||||
|
6FFD6A432600780CEB6D6374 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
86D6A3692EBE5943C3C75411 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
6850CF9EE994EB8682BD460F /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
9E76BC5648643A00E08CF70B /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
85F630F9575BB5DDC6F6B3B2 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6A39AA3BE6DA0B7B42041019 /* Pods_Runner.framework */,
|
||||||
|
C4E153E327A403FD75830D36 /* Pods_RunnerTests.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -122,8 +135,8 @@
|
|||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
B9F40AE3939A8E59418B2C25 /* Pods */,
|
7F718872327E3605229882F1 /* Pods */,
|
||||||
3806CD679A8B2BB869428B93 /* Frameworks */,
|
85F630F9575BB5DDC6F6B3B2 /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -151,19 +164,6 @@
|
|||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
B9F40AE3939A8E59418B2C25 /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DA00EBAA91366A0B5BFDAE96 /* Pods-Runner.debug.xcconfig */,
|
|
||||||
D773E9161AA2211A3E2B94DD /* Pods-Runner.release.xcconfig */,
|
|
||||||
84738EC4DA98A3780DDAB81F /* Pods-Runner.profile.xcconfig */,
|
|
||||||
AC42218FD0A0DB137D157E93 /* Pods-RunnerTests.debug.xcconfig */,
|
|
||||||
89205C63F97F88BDB459168E /* Pods-RunnerTests.release.xcconfig */,
|
|
||||||
89EEC485D24E5B1BC0DD7B8E /* Pods-RunnerTests.profile.xcconfig */,
|
|
||||||
);
|
|
||||||
path = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -171,10 +171,10 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
CD76B1A18202CBE77CBE3DCF /* [CP] Check Pods Manifest.lock */,
|
7F66DF627A66DF465C5F63D3 /* [CP] Check Pods Manifest.lock */,
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
CEDA9491D04A70CE2A58DF32 /* Frameworks */,
|
F68F88FFE2DC7D6754431798 /* Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -190,15 +190,15 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
7EC19810B524B833F58A16B8 /* [CP] Check Pods Manifest.lock */,
|
9BC3CC202AEB33DDD6358396 /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
3CF3DF1DB3C3E48099A705D1 /* [CP] Embed Pods Frameworks */,
|
B576B812EBF41188E37C7BA1 /* [CP] Embed Pods Frameworks */,
|
||||||
9D3C0722FFFB9D74548C2A72 /* [CP] Copy Pods Resources */,
|
8EF00F2B7B12B1557BEC9D5A /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -286,24 +286,61 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
3CF3DF1DB3C3E48099A705D1 /* [CP] Embed Pods Frameworks */ = {
|
7F66DF627A66DF465C5F63D3 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
7EC19810B524B833F58A16B8 /* [CP] Check Pods Manifest.lock */ = {
|
8EF00F2B7B12B1557BEC9D5A /* [CP] Copy Pods Resources */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Copy Pods Resources";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run Script";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
|
};
|
||||||
|
9BC3CC202AEB33DDD6358396 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
@ -325,58 +362,21 @@
|
|||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
B576B812EBF41188E37C7BA1 /* [CP] Embed Pods Frameworks */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
alwaysOutOfDate = 1;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Run Script";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
|
||||||
};
|
|
||||||
9D3C0722FFFB9D74548C2A72 /* [CP] Copy Pods Resources */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
CD76B1A18202CBE77CBE3DCF /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
@ -508,14 +508,14 @@
|
|||||||
};
|
};
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = AC42218FD0A0DB137D157E93 /* Pods-RunnerTests.debug.xcconfig */;
|
baseConfigurationReference = 86D6A3692EBE5943C3C75411 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gifunavi.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunaviGit.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@ -526,14 +526,14 @@
|
|||||||
};
|
};
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 89205C63F97F88BDB459168E /* Pods-RunnerTests.release.xcconfig */;
|
baseConfigurationReference = 6850CF9EE994EB8682BD460F /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gifunavi.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunaviGit.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
@ -542,14 +542,14 @@
|
|||||||
};
|
};
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 89EEC485D24E5B1BC0DD7B8E /* Pods-RunnerTests.profile.xcconfig */;
|
baseConfigurationReference = 9E76BC5648643A00E08CF70B /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gifunavi.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunaviGit.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
@ -560,7 +560,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
@ -617,7 +617,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 704 B |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 586 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 762 B |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 1.4 KiB |
@ -24,28 +24,24 @@
|
|||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
|
||||||
<string></string>
|
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>岐阜ナビはチェックポイントで撮影した写真を写真ライブラリに保存し、通過記録を保持し、競技結果として提出することができます。</string>
|
<string>岐阜ナビはチェックポイントで撮影した写真を写真ライブラリに保存し、通過記録を保持し、競技結果として提出することができます。</string>
|
||||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||||
<string>岐阜ナビはアプリが閉じられているときでも位置情報へのアクセスが必要です。これにより、走行履歴の記録ができ、レビュー時の参考にすることができます。</string>
|
<string>岐阜ナビはアプリが閉じられているときでも位置情報へのアクセスが必要です。これにより、走行履歴の記録ができ、レビュー時の参考にすることができます。</string>
|
||||||
<key>NSLocationAlwaysUsageDescription</key>
|
<key>NSLocationAlwaysUsageDescription</key>
|
||||||
<string>このアプリではバックグラウンドで位置情報にアクセスします。</string>
|
<string>このアプリではバックグラウンドで位置情報にアクセスします。</string>
|
||||||
<key>NSLocationWhenInUseUsageDescription</key>
|
<key>NSLocationWhenInUseUsageDescription</key>
|
||||||
<string>このアプリはチェックポイントへのチェックインや走行履歴を記録するために、位置情報にアクセスします。</string>
|
<string>このアプリはチェックポイントへのチェックインや走行履歴を記録するために、位置情報にアクセスします。</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>このアプリではカメラは使用しますが、マイクの使用は当面行いません。</string>
|
<string>このアプリではカメラは使用しますが、マイクの使用は当面行いません。</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>撮影した写真はデバイスのアルバムに保存されます。これにより、不具合時の通過記録を安全に担保することができます。</string>
|
<string>撮影した写真はデバイスのアルバムに保存されます。これにより、不具合時の通過記録を安全に担保することができます。</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>撮影した写真はデバイスのアルバムに保存されます。これにより、不具合時の通過記録を安全に担保することができます。</string>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIBackgroundModes</key>
|
|
||||||
<array>
|
|
||||||
<string>location</string>
|
|
||||||
</array>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
@ -63,9 +59,7 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<false/>
|
<string></string>
|
||||||
<key>io.flutter.embedded_views_preview</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
721
lib/main.dart
@ -38,8 +38,10 @@ import 'pages/permission/permission.dart';
|
|||||||
import 'package:gifunavi/services/api_service.dart';
|
import 'package:gifunavi/services/api_service.dart';
|
||||||
|
|
||||||
import 'package:gifunavi/provider/cached_tile_provider.dart';
|
import 'package:gifunavi/provider/cached_tile_provider.dart';
|
||||||
import 'package:gifunavi/pages/entry/entry_controller.dart';
|
//import 'package:gifunavi/pages/entry/entry_controller.dart';
|
||||||
import 'package:gifunavi/pages/team/team_controller.dart';
|
//import 'package:gifunavi/pages/team/team_controller.dart';
|
||||||
|
|
||||||
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
|
||||||
Map<String, dynamic> deviceInfo = {};
|
Map<String, dynamic> deviceInfo = {};
|
||||||
|
|
||||||
@ -56,14 +58,25 @@ void saveGameState() async {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// 現在のユーザーのIDも一緒に保存するようにします。
|
// 現在のユーザーのIDも一緒に保存するようにします。
|
||||||
void saveGameState() async {
|
Future<void> saveGameState() async {
|
||||||
DestinationController destinationController =
|
DestinationController destinationController =
|
||||||
Get.find<DestinationController>();
|
Get.find<DestinationController>();
|
||||||
IndexController indexController = Get.find<IndexController>();
|
IndexController indexController = Get.find<IndexController>();
|
||||||
SharedPreferences pref = await SharedPreferences.getInstance();
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
||||||
debugPrint("indexController.currentUser = ${indexController.currentUser}");
|
debugPrint("ゲームステータス保存 = ${indexController.currentUser}");
|
||||||
if(indexController.currentUser.isNotEmpty) {
|
if(indexController.currentUser.isNotEmpty) {
|
||||||
pref.setInt("user_id", indexController.currentUser[0]["user"]["id"]);
|
pref.setInt("user_id", indexController.currentUser[0]["user"]["id"]);
|
||||||
|
|
||||||
|
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"]);
|
||||||
|
//final zekken = indexController.currentUser[0]["user"]["zekken_number"];
|
||||||
|
pref.setInt('zekkenNumber', indexController.currentUser[0]["user"]["zekken_number"]);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
debugPrint("User is empty....");
|
debugPrint("User is empty....");
|
||||||
}
|
}
|
||||||
@ -73,75 +86,118 @@ void saveGameState() async {
|
|||||||
pref.setBool("ready_for_goal", DestinationController.ready_for_goal);
|
pref.setBool("ready_for_goal", DestinationController.ready_for_goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
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;
|
|
||||||
DestinationController.ready_for_goal =
|
|
||||||
pref.getBool("ready_for_goal") ?? false;
|
|
||||||
//print(
|
|
||||||
// "--restored -- destinationController.isInRog.value ${pref.getBool("is_in_rog")} -- ${pref.getBool("rogaining_counted")}");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void restoreGame() async {
|
|
||||||
|
// _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 {
|
||||||
SharedPreferences pref = await SharedPreferences.getInstance();
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
IndexController indexController = Get.find<IndexController>();
|
IndexController indexController = Get.find<IndexController>();
|
||||||
int? savedUserId = pref.getInt("user_id");
|
int? savedUserId = pref.getInt("user_id");
|
||||||
//int? currUserId = indexController.currentUser[0]['user']['id'];
|
//int? currUserId = indexController.currentUser[0]['user']['id'];
|
||||||
//debugPrint("savedUserId=${savedUserId}, currentUser=${currUserId}");
|
debugPrint("ゲームステータス再現 savedUserId=${savedUserId}");
|
||||||
if (indexController.currentUser.isNotEmpty &&
|
if (indexController.currentUser.isNotEmpty &&
|
||||||
indexController.currentUser[0]["user"]["id"] == savedUserId) {
|
indexController.currentUser[0]["user"]["id"] == savedUserId) {
|
||||||
DestinationController destinationController =
|
|
||||||
Get.find<DestinationController>();
|
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>();
|
||||||
destinationController.skipGps = false;
|
destinationController.skipGps = false;
|
||||||
destinationController.isInRog.value = pref.getBool("is_in_rog") ?? false;
|
destinationController.isInRog.value = pref.getBool("is_in_rog") ?? false;
|
||||||
destinationController.rogainingCounted.value =
|
destinationController.rogainingCounted.value = pref.getBool("rogaining_counted") ?? false;
|
||||||
pref.getBool("rogaining_counted") ?? false;
|
DestinationController.ready_for_goal = pref.getBool("ready_for_goal") ?? false;
|
||||||
DestinationController.ready_for_goal =
|
//await Get.putAsync(() => ApiService().init());
|
||||||
pref.getBool("ready_for_goal") ?? false;
|
|
||||||
await Get.putAsync(() => ApiService().init());
|
if (indexController.currentUser[0]["user"]["event_code"] != null) {
|
||||||
|
indexController.setSelectedEventName(indexController.currentUser[0]["user"]["event_code"]);
|
||||||
|
} else {
|
||||||
|
indexController.setSelectedEventName('未参加');
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
indexController.setSelectedEventName('未参加');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void restoreGame_new() async {
|
||||||
|
SharedPreferences pref = await SharedPreferences.getInstance();
|
||||||
|
IndexController indexController = Get.find<IndexController>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Get.putAsync(() => ApiService().init());
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _showEventSelectionWarning() {
|
||||||
|
Get.dialog(
|
||||||
|
AlertDialog(
|
||||||
|
title: Text('警告'),
|
||||||
|
content: Text('イベントを選択してください。'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text('OK'),
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
Get.put(LocationController());
|
final IndexController _indexController;
|
||||||
/*
|
|
||||||
Get.put(ApiService());
|
|
||||||
Get.put(TeamController());
|
|
||||||
Get.put(EntryController());
|
|
||||||
Get.put(IndexController());
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
await FlutterMapTileCaching.initialise();
|
|
||||||
|
|
||||||
final StoreDirectory instanceA = FMTC.instance('OpenStreetMap (A)');
|
|
||||||
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',
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
// 新しいキャッシュプロバイダーの初期化
|
|
||||||
await CacheProvider.initialize();
|
|
||||||
|
|
||||||
// 使用不可
|
|
||||||
//deviceInfo = await DeviceInfoService.getDeviceInfo();
|
|
||||||
|
|
||||||
FlutterError.onError = (FlutterErrorDetails details) {
|
FlutterError.onError = (FlutterErrorDetails details) {
|
||||||
FlutterError.presentError(details);
|
FlutterError.presentError(details);
|
||||||
@ -150,67 +206,98 @@ void main() async {
|
|||||||
ErrorService.reportError(details.exception, details.stack ?? StackTrace.current, deviceInfo, LogManager().operationLogs);
|
ErrorService.reportError(details.exception, details.stack ?? StackTrace.current, deviceInfo, LogManager().operationLogs);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Get.put(LocationController());
|
|
||||||
|
|
||||||
//await PermissionController.checkAndRequestPermissions();
|
|
||||||
//requestLocationPermission();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
|
|
||||||
Get.put(SettingsController()); // これを追加
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
runZonedGuarded(() {
|
|
||||||
runApp(const ProviderScope(child: MyApp()));
|
|
||||||
}, (error, stackTrace) {
|
|
||||||
ErrorService.reportError(error, stackTrace, deviceInfo);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
FlutterError.onError = (FlutterErrorDetails details) {
|
|
||||||
FlutterError.presentError(details);
|
|
||||||
debugPrint('Flutter error: ${details.exception}');
|
|
||||||
debugPrint('Stack trace: ${details.stack}');
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
tz.initializeTimeZones();
|
|
||||||
|
|
||||||
// ApiServiceを初期化
|
|
||||||
//await Get.putAsync(() => ApiService().init());
|
//await Get.putAsync(() => ApiService().init());
|
||||||
|
await _initApiService();
|
||||||
|
debugPrint("1: start ApiService");
|
||||||
|
|
||||||
|
// すべてのコントローラーとサービスを非同期で初期化
|
||||||
|
Get.lazyPut(() => IndexController(apiService: Get.find<ApiService>()));
|
||||||
|
debugPrint("2: start IndexController");
|
||||||
|
|
||||||
|
|
||||||
|
// その他のコントローラーを遅延初期化
|
||||||
|
Get.lazyPut(() => SettingsController());
|
||||||
|
debugPrint("2: start SettingsController");
|
||||||
|
Get.lazyPut(() => DestinationController());
|
||||||
|
debugPrint("3: start DestinationController");
|
||||||
|
|
||||||
await initServices();
|
await initServices();
|
||||||
|
|
||||||
runApp(const ProviderScope(child: MyApp()));
|
runApp(const ProviderScope(child: MyApp()));
|
||||||
//runApp(HomePage()); // MyApp()からHomePage()に変更
|
|
||||||
//runApp(const MyApp());
|
|
||||||
}catch(e, stackTrace){
|
}catch(e, stackTrace){
|
||||||
print('Error during initialization: $e');
|
print('Error during initialization: $e');
|
||||||
print('Stack trace: $stackTrace');
|
print('Stack trace: $stackTrace');
|
||||||
|
|
||||||
|
// エラーが発生した場合、エラー画面を表示
|
||||||
|
runApp(ErrorApp(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initServices() async {
|
Future<void> initServices() async {
|
||||||
print('Starting services ...');
|
print('Starting services ...');
|
||||||
try {
|
try {
|
||||||
await Get.putAsync(() => ApiService().init());
|
|
||||||
print('All services started...');
|
// 非同期処理を並列実行
|
||||||
|
await Future.wait([
|
||||||
|
_initTimeZone(),
|
||||||
|
_initCacheProvider(),
|
||||||
|
]);
|
||||||
|
print('=== 5. Initialized TimeZone...');
|
||||||
|
print('=== 6. CacheProvider started...');
|
||||||
|
|
||||||
|
Get.put(PermissionController());
|
||||||
|
await _checkPermissions();
|
||||||
|
debugPrint("7: start PermissionController");
|
||||||
|
|
||||||
}catch(e){
|
}catch(e){
|
||||||
print('Error initializing ApiService: $e');
|
print('Error initializing : $e');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
Get.put(SettingsController());
|
|
||||||
print('SettingsController initialized successfully');
|
|
||||||
} catch (e) {
|
|
||||||
print('Error initializing SettingsController: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
print('All services started...');
|
print('All services started...');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initLocationController() async {
|
||||||
|
if (!Get.isRegistered<LocationController>()) {
|
||||||
|
Get.put(LocationController());
|
||||||
|
}
|
||||||
|
print('=== 1. LocationController started...');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initTimeZone() async {
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initCacheProvider() async {
|
||||||
|
await CacheProvider.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _checkPermissions() async {
|
||||||
|
await PermissionController.checkAndRequestPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initApiService() async {
|
||||||
|
await Get.putAsync(() => ApiService().init());
|
||||||
|
//Get.lazyPut(() => ApiService());
|
||||||
|
}
|
||||||
|
|
||||||
|
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'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> requestLocationPermission() async {
|
Future<void> requestLocationPermission() async {
|
||||||
try {
|
try {
|
||||||
final status = await Permission.locationAlways.request();
|
final status = await Permission.locationAlways.request();
|
||||||
@ -300,70 +387,80 @@ String team_name="";
|
|||||||
String event_code="";
|
String event_code="";
|
||||||
|
|
||||||
Future<void> startBackgroundTracking() async {
|
Future<void> startBackgroundTracking() async {
|
||||||
if (Platform.isIOS && background==false) {
|
try {
|
||||||
|
if (Platform.isIOS && background == false) {
|
||||||
final IndexController indexController = Get.find<IndexController>();
|
final IndexController indexController = Get.find<IndexController>();
|
||||||
if(indexController.currentUser.isNotEmpty) {
|
if (indexController.currentUser.isNotEmpty &&
|
||||||
team_name = indexController.currentUser[0]["user"]['team_name'];
|
indexController.currentUser[0]["user"]['team_name'] != null) {
|
||||||
event_code = indexController.currentUser[0]["user"]["event_code"];
|
team_name = indexController.currentUser[0]["user"]['team_name'];
|
||||||
}
|
event_code = indexController.currentUser[0]["user"]["event_code"];
|
||||||
|
}
|
||||||
background = true;
|
background = true;
|
||||||
debugPrint("バックグラウンド処理を開始しました。");
|
debugPrint("バックグラウンド処理を開始しました。");
|
||||||
const LocationSettings locationSettings = LocationSettings(
|
const LocationSettings locationSettings = LocationSettings(
|
||||||
accuracy: LocationAccuracy.high,
|
accuracy: LocationAccuracy.high,
|
||||||
distanceFilter: 100,
|
distanceFilter: 100,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
positionStream = Geolocator.getPositionStream(locationSettings: locationSettings)
|
positionStream =
|
||||||
.listen((Position? position) async {
|
Geolocator.getPositionStream(locationSettings: locationSettings)
|
||||||
if (position != null) {
|
.listen((Position? position) async {
|
||||||
final lat = position.latitude;
|
if (position != null) {
|
||||||
final lng = position.longitude;
|
final lat = position.latitude;
|
||||||
//final timestamp = DateTime.now();
|
final lng = position.longitude;
|
||||||
final accuracy = position.accuracy;
|
//final timestamp = DateTime.now();
|
||||||
|
final accuracy = position.accuracy;
|
||||||
|
|
||||||
// GPS信号強度がlowの場合はスキップ
|
// GPS信号強度がlowの場合はスキップ
|
||||||
if (accuracy > 100) {
|
if (accuracy > 100) {
|
||||||
debugPrint("GPS signal strength is low. Skipping data saving.");
|
debugPrint(
|
||||||
return;
|
"GPS signal strength is low. Skipping data saving.");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Duration difference = lastGPSCollectedTime.difference(DateTime.now())
|
Duration difference = lastGPSCollectedTime.difference(
|
||||||
.abs();
|
DateTime.now())
|
||||||
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過(普通に歩くスピード)
|
.abs();
|
||||||
//debugPrint("時間差:${difference}");
|
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過(普通に歩くスピード)
|
||||||
if (difference.inSeconds >= 10 ) {
|
//debugPrint("時間差:${difference}");
|
||||||
debugPrint("バックグラウンドでのGPS取得時の処理(10secおき) count=${difference.inSeconds}, time=${DateTime.now()}");
|
if (difference.inSeconds >= 10) {
|
||||||
|
debugPrint(
|
||||||
|
"バックグラウンドでのGPS取得時の処理(10secおき) count=${difference
|
||||||
|
.inSeconds}, time=${DateTime.now()}");
|
||||||
|
|
||||||
// DBにGPSデータを保存 pages/destination/destination_controller.dart
|
// DBにGPSデータを保存 pages/destination/destination_controller.dart
|
||||||
await addGPStoDB(lat, lng);
|
await addGPStoDB(lat, lng);
|
||||||
|
|
||||||
lastGPSCollectedTime = DateTime.now();
|
lastGPSCollectedTime = DateTime.now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, onError: (error) {
|
}, onError: (error) {
|
||||||
if (error is LocationServiceDisabledException) {
|
if (error is LocationServiceDisabledException) {
|
||||||
print('Location services are disabled');
|
print('Location services are disabled');
|
||||||
} else if (error is PermissionDeniedException) {
|
} else if (error is PermissionDeniedException) {
|
||||||
print('Location permissions are denied');
|
print('Location permissions are denied');
|
||||||
} else {
|
} else {
|
||||||
print('Location Error: $error');
|
print('Location Error: $error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error starting background tracking: $e');
|
print('Error starting background tracking: $e');
|
||||||
}
|
}
|
||||||
}else if (Platform.isAndroid && background == false) {
|
} else if (Platform.isAndroid && background == false) {
|
||||||
background = true;
|
background = true;
|
||||||
debugPrint("バックグラウンド処理を開始しました。");
|
debugPrint("バックグラウンド処理を開始しました。");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 位置情報の権限が許可されているかを確認
|
// 位置情報の権限が許可されているかを確認
|
||||||
await PermissionController.checkAndRequestPermissions();
|
await PermissionController.checkAndRequestPermissions();
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
print('Error starting background tracking: $e');
|
print('Error starting background tracking: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error starting background tracking: $e');
|
||||||
|
// 再試行するか、エラーを適切に処理
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,20 +485,24 @@ Future<void> addGPStoDB(double la, double ln) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> stopBackgroundTracking() async {
|
Future<void> stopBackgroundTracking() async {
|
||||||
if (Platform.isIOS && background==true) {
|
try {
|
||||||
background=false;
|
if (Platform.isIOS && background == true) {
|
||||||
debugPrint("バックグラウンド処理:停止しました。");
|
background = false;
|
||||||
await positionStream?.cancel();
|
debugPrint("バックグラウンド処理:停止しました。");
|
||||||
positionStream = null;
|
await positionStream?.cancel();
|
||||||
}else if(Platform.isAndroid && background==true){
|
positionStream = null;
|
||||||
background=false;
|
} else if (Platform.isAndroid && background == true) {
|
||||||
debugPrint("バックグラウンド処理:停止しました。");
|
background = false;
|
||||||
const platform = MethodChannel('location');
|
debugPrint("バックグラウンド処理:停止しました。");
|
||||||
try {
|
const platform = MethodChannel('location');
|
||||||
await platform.invokeMethod('stopLocationService');
|
try {
|
||||||
} on PlatformException catch (e) {
|
await platform.invokeMethod('stopLocationService');
|
||||||
print("Failed to stop location service: '${e.message}'.");
|
} on PlatformException catch (e) {
|
||||||
|
print("Failed to stop location service: '${e.message}'.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch(e){
|
||||||
|
print('Error stopping background tracking: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,18 +515,22 @@ class MyApp extends StatefulWidget {
|
|||||||
|
|
||||||
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
// This widget is the root of your application.
|
// This widget is the root of your application.
|
||||||
|
late final LocationController _locationController;
|
||||||
|
late final IndexController _indexController;
|
||||||
|
late final DestinationController _destinationController;
|
||||||
|
late final PermissionController _permissionController;
|
||||||
|
Timer? _memoryCheckTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (!Get.isRegistered<LocationController>()) {
|
_initializeControllers();
|
||||||
Get.put(LocationController());
|
WidgetsBinding.instance.addObserver(this);
|
||||||
}
|
//_startMemoryMonitoring();
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
restoreGame();
|
// _restoreGameAndInitialize();
|
||||||
}
|
}
|
||||||
WidgetsBinding.instance.addObserver(this);
|
|
||||||
|
|
||||||
// ウィジェットが構築された後に権限をチェック
|
// ウィジェットが構築された後に権限をチェック
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
@ -435,6 +540,105 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
|||||||
debugPrint("Start MyAppState...");
|
debugPrint("Start MyAppState...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _restoreGameAndInitialize() async {
|
||||||
|
await restoreGame();
|
||||||
|
// ここに他の初期化処理を追加できます
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initializeControllers() {
|
||||||
|
/*
|
||||||
|
if (!Get.isRegistered<IndexController>()) {
|
||||||
|
_locationController = Get.put(LocationController(), permanent: true);
|
||||||
|
}
|
||||||
|
if (!Get.isRegistered<IndexController>()) {
|
||||||
|
_indexController = Get.put(IndexController(apiService: Get.find<ApiService>()), permanent: true);
|
||||||
|
}
|
||||||
|
if (!Get.isRegistered<DestinationController>()) {
|
||||||
|
_destinationController =
|
||||||
|
Get.put(DestinationController(), permanent: true);
|
||||||
|
}
|
||||||
|
if (!Get.isRegistered<PermissionController>()) {
|
||||||
|
_permissionController = Get.put(PermissionController());
|
||||||
|
}
|
||||||
|
// 他の必要なコントローラーの初期化
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startMemoryMonitoring() {
|
||||||
|
/*
|
||||||
|
_memoryCheckTimer = Timer.periodic(const Duration(seconds: 10), (timer) {
|
||||||
|
_checkMemoryUsage();
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkMemoryUsage() async {
|
||||||
|
final memoryInfo = await _getMemoryInfo();
|
||||||
|
//debugPrint('Current memory usage: ${memoryInfo['used']} MB');
|
||||||
|
if (memoryInfo['used']! > 100) { // 100MB以上使用している場合
|
||||||
|
_performMemoryCleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void showPermissionRequiredDialog() {
|
void showPermissionRequiredDialog() {
|
||||||
showDialog(
|
showDialog(
|
||||||
@ -474,6 +678,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
_memoryCheckTimer?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,110 +692,118 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
|||||||
@override
|
@override
|
||||||
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
|
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||||
try {
|
try {
|
||||||
LocationController locationController = Get.find<LocationController>();
|
if (!Get.isRegistered<IndexController>()) {
|
||||||
|
_indexController = Get.find<IndexController>();
|
||||||
|
}
|
||||||
|
if (!Get.isRegistered<LocationController>()) {
|
||||||
|
_locationController = Get.find<LocationController>();
|
||||||
|
}
|
||||||
|
if (!Get.isRegistered<DestinationController>()) {
|
||||||
|
_destinationController = Get.find<DestinationController>();
|
||||||
|
}
|
||||||
|
|
||||||
DestinationController destinationController = Get.find<
|
|
||||||
DestinationController>();
|
|
||||||
|
|
||||||
//DestinationController destinationController =
|
|
||||||
// Get.find<DestinationController>();
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
// 追加 2024.8.13.
|
//await _onResumed();
|
||||||
await stopBackgroundTracking();
|
await _onResumed();
|
||||||
destinationController.restartGPS();
|
|
||||||
// 追加 2024.8.13.
|
|
||||||
|
|
||||||
// バックグラウンド処理を停止
|
|
||||||
if (Platform.isIOS && destinationController.isRunningBackgroundGPS) {
|
|
||||||
// Foreground に戻った時の処理
|
|
||||||
debugPrint(
|
|
||||||
" ==(Status Changed)==> RESUMED. フォアグラウンドに戻りました");
|
|
||||||
locationController.resumePositionStream();
|
|
||||||
//print("RESUMED");
|
|
||||||
restoreGame();
|
|
||||||
|
|
||||||
stopBackgroundTracking();
|
|
||||||
destinationController.isRunningBackgroundGPS = false;
|
|
||||||
destinationController.restartGPS();
|
|
||||||
} else if (Platform.isAndroid) {
|
|
||||||
if (destinationController.isRunningBackgroundGPS) {
|
|
||||||
const platform = MethodChannel('location');
|
|
||||||
platform.invokeMethod('stopLocationService');
|
|
||||||
destinationController.isRunningBackgroundGPS = false;
|
|
||||||
destinationController.restartGPS();
|
|
||||||
debugPrint("stopped android location service..");
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint(
|
|
||||||
"==(Status Changed)==> RESUMED. android フォアグラウンドに戻りました");
|
|
||||||
locationController.resumePositionStream();
|
|
||||||
//print("RESUMED");
|
|
||||||
restoreGame();
|
|
||||||
} else {
|
|
||||||
debugPrint("==(Status Changed)==> RESUMED 不明状態");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.inactive:
|
case AppLifecycleState.inactive:
|
||||||
|
|
||||||
// アプリが非アクティブになったときに発生します。
|
// アプリが非アクティブになったときに発生します。
|
||||||
|
await _onInactive();
|
||||||
if (Platform.isIOS && !destinationController
|
|
||||||
.isRunningBackgroundGPS) { // iOSはバックグラウンドでもフロントの処理が生きている。
|
|
||||||
// これは、別のアプリやシステムのオーバーレイ(着信通話やアラームなど)によって一時的に中断された状態です。
|
|
||||||
debugPrint(" ==(Status Changed)==> INACTIVE. 非アクティブ処理。");
|
|
||||||
//locationController.resumePositionStream();
|
|
||||||
|
|
||||||
// 追加: フロントエンドのGPS信号のlistenを停止
|
|
||||||
locationController.stopPositionStream();
|
|
||||||
|
|
||||||
destinationController.isRunningBackgroundGPS = true;
|
|
||||||
startBackgroundTracking();
|
|
||||||
} else if (Platform.isAndroid &&
|
|
||||||
!destinationController.isRunningBackgroundGPS) {
|
|
||||||
debugPrint(" ==(Status Changed)==> INACTIVE. 非アクティブ処理。");
|
|
||||||
} else {
|
|
||||||
debugPrint("==(Status Changed)==> INACTIVE 不明状態");
|
|
||||||
}
|
|
||||||
saveGameState();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppLifecycleState.paused:
|
case AppLifecycleState.paused:
|
||||||
// バックグラウンドに移行したときの処理
|
// バックグラウンドに移行したときの処理
|
||||||
//locationController.resumePositionStream();
|
//locationController.resumePositionStream();
|
||||||
debugPrint(" ==(Status Changed)==> PAUSED. バックグラウンド処理。");
|
await _onPaused();
|
||||||
if (Platform.isIOS && !destinationController.isRunningBackgroundGPS) {
|
|
||||||
debugPrint(
|
|
||||||
"iOS already running background GPS processing when it's inactive");
|
|
||||||
} else if (Platform.isAndroid &&
|
|
||||||
!destinationController.isRunningBackgroundGPS) {
|
|
||||||
debugPrint(
|
|
||||||
" ==(Status Changed)==> PAUSED. Android バックグラウンド処理。");
|
|
||||||
locationController.stopPositionStream();
|
|
||||||
const platform = MethodChannel('location');
|
|
||||||
platform.invokeMethod('startLocationService');
|
|
||||||
//platform.invokeMethod('stopLocationService');
|
|
||||||
destinationController.isRunningBackgroundGPS = true;
|
|
||||||
//startBackgroundTracking();
|
|
||||||
}
|
|
||||||
saveGameState();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppLifecycleState.detached:
|
case AppLifecycleState.detached:
|
||||||
// アプリが終了する直前に発生します。この状態では、アプリはメモリから解放される予定です。
|
// アプリが終了する直前に発生します。この状態では、アプリはメモリから解放される予定です。
|
||||||
//locationController.resumePositionStream();
|
//locationController.resumePositionStream();
|
||||||
debugPrint(" ==(Status Changed)==> DETACHED アプリは終了します。");
|
await _onDetached();
|
||||||
saveGameState();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppLifecycleState.hidden:
|
case AppLifecycleState.hidden:
|
||||||
// Web用の特殊な状態で、モバイルアプリでは発生しません。
|
// Web用の特殊な状態で、モバイルアプリでは発生しません。
|
||||||
//locationController.resumePositionStream();
|
//locationController.resumePositionStream();
|
||||||
debugPrint(" ==(Status Changed)==> Hidden アプリが隠れた");
|
await _onHidden();
|
||||||
saveGameState();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}catch(e){
|
}catch(e){
|
||||||
print('Error finding LocationController: $e');
|
print('Error finding didChangeAppLifecycleState: $e');
|
||||||
|
_initializeControllers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onResumed() async {
|
||||||
|
debugPrint("==(Status Changed)==> RESUMED");
|
||||||
|
try {
|
||||||
|
_initializeControllers();
|
||||||
|
|
||||||
|
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');
|
||||||
|
// 必要に応じて再試行またはエラー処理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@ -14,8 +14,11 @@ import 'package:gifunavi/services/external_service.dart';
|
|||||||
import 'package:gifunavi/utils/const.dart';
|
import 'package:gifunavi/utils/const.dart';
|
||||||
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http; // この行を追加
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../../routes/app_pages.dart'; // この行を追加
|
||||||
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
|
||||||
// 関数 getTagText は、特定の条件に基づいて文字列から特定の部分を抽出し、返却するためのものです。
|
// 関数 getTagText は、特定の条件に基づいて文字列から特定の部分を抽出し、返却するためのものです。
|
||||||
// 関数は2つのパラメータを受け取り、条件分岐を通じて結果を返します。
|
// 関数は2つのパラメータを受け取り、条件分岐を通じて結果を返します。
|
||||||
@ -220,10 +223,67 @@ class CameraPage extends StatelessWidget {
|
|||||||
|
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
|
|
||||||
|
bool isValidEventParticipation() {
|
||||||
|
final eventCode = indexController.currentUser[0]["user"]["event_code"];
|
||||||
|
final teamName = indexController.currentUser[0]["user"]["team_name"];
|
||||||
|
final dateString = indexController.currentUser[0]["user"]["event_date"];
|
||||||
|
//final parsedDate = DateTime.parse(dateString);
|
||||||
|
|
||||||
|
//final eventDate = tz.TZDateTime.from(parsedDate, tz.getLocation('Asia/Tokyo'));
|
||||||
|
|
||||||
|
//final today = DateTime.now();
|
||||||
|
|
||||||
|
return eventCode != null &&
|
||||||
|
teamName != null &&
|
||||||
|
dateString != null ;
|
||||||
|
|
||||||
|
// isSameDay(eventDate, today);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSameDay(DateTime date1, DateTime date2) {
|
||||||
|
return date1.year == date2.year &&
|
||||||
|
date1.month == date2.month &&
|
||||||
|
date1.day == date2.day;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showEventParticipationWarning(BuildContext context) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text("警告"),
|
||||||
|
content: const Text("今日のイベントにまず参加しないと事前チェックインはできません。サブメニューからイベント参加をタップして今日のイベントに参加してください。"),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: const Text("キャンセル"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: const Text("参加する"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
Get.toNamed(AppPages.EVENT_ENTRY);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 現在の状態に基づいて、適切なアクションボタンを返します。
|
// 現在の状態に基づいて、適切なアクションボタンを返します。
|
||||||
// 要修正:エラーハンドリングが不十分です。例外が発生した場合の処理を追加することをお勧めします。
|
// 要修正:エラーハンドリングが不十分です。例外が発生した場合の処理を追加することをお勧めします。
|
||||||
//
|
//
|
||||||
Widget getAction(BuildContext context) {
|
Widget getAction(BuildContext context) {
|
||||||
|
if (!isValidEventParticipation()) {
|
||||||
|
return ElevatedButton(
|
||||||
|
onPressed: () => showEventParticipationWarning(context),
|
||||||
|
child: const Text("チェックイン"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (manulaCheckin == true) {
|
if (manulaCheckin == true) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
@ -253,7 +313,9 @@ class CameraPage extends StatelessWidget {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await destinationController.makeCheckin(destination, true,
|
await destinationController.makeCheckin(destination, true,
|
||||||
destinationController.photos[0].path);
|
destinationController.photos[0].path);
|
||||||
destinationController.rogainingCounted.value = true;
|
if( destinationController.isInRog.value==true ) {
|
||||||
|
destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可
|
||||||
|
}
|
||||||
destinationController.skipGps = false;
|
destinationController.skipGps = false;
|
||||||
destinationController.isPhotoShoot.value = false;
|
destinationController.isPhotoShoot.value = false;
|
||||||
|
|
||||||
@ -387,7 +449,9 @@ class CameraPage extends StatelessWidget {
|
|||||||
await destinationController.makeBuyPoint(
|
await destinationController.makeBuyPoint(
|
||||||
destination, destinationController.photos[0].path);
|
destination, destinationController.photos[0].path);
|
||||||
Get.back();
|
Get.back();
|
||||||
destinationController.rogainingCounted.value = true;
|
if( destinationController.isInRog.value==true ) {
|
||||||
|
destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可
|
||||||
|
}
|
||||||
destinationController.skipGps = false;
|
destinationController.skipGps = false;
|
||||||
destinationController.isPhotoShoot.value = false;
|
destinationController.isPhotoShoot.value = false;
|
||||||
Get.snackbar("お買い物加点を行いました。",
|
Get.snackbar("お買い物加点を行いました。",
|
||||||
@ -428,7 +492,9 @@ class CameraPage extends StatelessWidget {
|
|||||||
await destinationController.makeBuyPoint(
|
await destinationController.makeBuyPoint(
|
||||||
destination, destinationController.photos[0].path);
|
destination, destinationController.photos[0].path);
|
||||||
Get.back();
|
Get.back();
|
||||||
destinationController.rogainingCounted.value = true;
|
if( destinationController.isInRog.value==true ) {
|
||||||
|
destinationController.rogainingCounted.value = true; //ロゲ開始後のみ許可
|
||||||
|
}
|
||||||
destinationController.skipGps = false;
|
destinationController.skipGps = false;
|
||||||
destinationController.isPhotoShoot.value = false;
|
destinationController.isPhotoShoot.value = false;
|
||||||
Get.snackbar("お買い物加点を行いました。",
|
Get.snackbar("お買い物加点を行いました。",
|
||||||
@ -465,7 +531,9 @@ class CameraPage extends StatelessWidget {
|
|||||||
true,
|
true,
|
||||||
destinationController.photos[0].path);
|
destinationController.photos[0].path);
|
||||||
//Get.back();
|
//Get.back();
|
||||||
destinationController.rogainingCounted.value = true;
|
if( destinationController.isInRog.value==true ) {
|
||||||
|
destinationController.rogainingCounted.value = true; //ロゲ開始後のみ許可
|
||||||
|
}
|
||||||
destinationController.skipGps = false;
|
destinationController.skipGps = false;
|
||||||
destinationController.isPhotoShoot.value = false;
|
destinationController.isPhotoShoot.value = false;
|
||||||
|
|
||||||
@ -496,6 +564,7 @@ class CameraPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
//print("---- photos ${destination.photos} ----");
|
//print("---- photos ${destination.photos} ----");
|
||||||
if (buyPointPhoto == true) {
|
if (buyPointPhoto == true) {
|
||||||
// buyPointPhotoがtrueの場合は、BuyPointCameraウィジェットを返します。
|
// buyPointPhotoがtrueの場合は、BuyPointCameraウィジェットを返します。
|
||||||
@ -780,7 +849,9 @@ class BuyPointCamera extends StatelessWidget {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await destinationController.cancelBuyPoint(destination);
|
await destinationController.cancelBuyPoint(destination);
|
||||||
Navigator.of(Get.context!).pop();
|
Navigator.of(Get.context!).pop();
|
||||||
destinationController.rogainingCounted.value = true;
|
if( destinationController.isInRog.value==true ) {
|
||||||
|
destinationController.rogainingCounted.value = true; // ロゲ開始後のみ許可
|
||||||
|
}
|
||||||
destinationController.skipGps = false;
|
destinationController.skipGps = false;
|
||||||
destinationController.isPhotoShoot.value = false;
|
destinationController.isPhotoShoot.value = false;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:gifunavi/model/destination.dart';
|
import 'package:gifunavi/model/destination.dart';
|
||||||
@ -8,8 +10,17 @@ import 'package:gifunavi/model/destination.dart';
|
|||||||
class CustomCameraView extends StatefulWidget {
|
class CustomCameraView extends StatefulWidget {
|
||||||
final Function(String) onImageCaptured;
|
final Function(String) onImageCaptured;
|
||||||
final Destination? destination;
|
final Destination? destination;
|
||||||
|
final Function(bool) onCameraStatusChanged;
|
||||||
|
|
||||||
|
//const CustomCameraView({super.key, required this.onImageCaptured, required this.destination});
|
||||||
|
|
||||||
|
const CustomCameraView({
|
||||||
|
Key? key,
|
||||||
|
required this.onImageCaptured,
|
||||||
|
required this.destination,
|
||||||
|
required this.onCameraStatusChanged, // 新しいコールバック
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
const CustomCameraView({super.key, required this.onImageCaptured, required this.destination});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CustomCameraViewState createState() => _CustomCameraViewState();
|
_CustomCameraViewState createState() => _CustomCameraViewState();
|
||||||
@ -17,6 +28,8 @@ class CustomCameraView extends StatefulWidget {
|
|||||||
|
|
||||||
class _CustomCameraViewState extends State<CustomCameraView> {
|
class _CustomCameraViewState extends State<CustomCameraView> {
|
||||||
CameraController? _controller;
|
CameraController? _controller;
|
||||||
|
bool _isCameraAvailable = true;
|
||||||
|
|
||||||
late List<CameraDescription> _cameras;
|
late List<CameraDescription> _cameras;
|
||||||
int _selectedCameraIndex = 0;
|
int _selectedCameraIndex = 0;
|
||||||
double _currentScale = 1.0;
|
double _currentScale = 1.0;
|
||||||
@ -31,10 +44,25 @@ class _CustomCameraViewState extends State<CustomCameraView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initializeCamera() async {
|
Future<void> _initializeCamera() async {
|
||||||
_cameras = await availableCameras();
|
try {
|
||||||
_controller = CameraController(_cameras[_selectedCameraIndex], ResolutionPreset.medium);
|
_cameras = await availableCameras();
|
||||||
await _controller!.initialize();
|
if (_cameras.isNotEmpty) {
|
||||||
setState(() {});
|
_controller = CameraController(
|
||||||
|
_cameras[_selectedCameraIndex], ResolutionPreset.medium);
|
||||||
|
await _controller!.initialize();
|
||||||
|
setState(() {
|
||||||
|
_isCameraAvailable = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw Exception('Camera is not available');
|
||||||
|
}
|
||||||
|
}catch(err){
|
||||||
|
print("Error initializing camera: $err");
|
||||||
|
setState(() {
|
||||||
|
_isCameraAvailable = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
widget.onCameraStatusChanged(_isCameraAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -82,20 +110,46 @@ class _CustomCameraViewState extends State<CustomCameraView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _captureImage() async {
|
void _captureImage() async {
|
||||||
if (_controller!.value.isInitialized) {
|
if (_isCameraAvailable) {
|
||||||
final Directory appDirectory = await getApplicationDocumentsDirectory();
|
if (_controller!.value.isInitialized) {
|
||||||
final String imagePath = path.join(appDirectory.path, '${DateTime.now()}.jpg');
|
final Directory appDirectory = await getApplicationDocumentsDirectory();
|
||||||
|
final String imagePath = path.join(
|
||||||
|
appDirectory.path, '${DateTime.now()}.jpg');
|
||||||
|
|
||||||
final XFile imageFile = await _controller!.takePicture();
|
final XFile imageFile = await _controller!.takePicture();
|
||||||
await imageFile.saveTo(imagePath);
|
await imageFile.saveTo(imagePath);
|
||||||
|
|
||||||
|
widget.onImageCaptured(imagePath);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// ダミー画像を使用
|
||||||
|
final String imagePath = await _saveDummyImage();
|
||||||
widget.onImageCaptured(imagePath);
|
widget.onImageCaptured(imagePath);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> _saveDummyImage() async {
|
||||||
|
final Directory appDirectory = await getApplicationDocumentsDirectory();
|
||||||
|
final String imagePath = path.join(appDirectory.path, 'dummy_${DateTime.now()}.png');
|
||||||
|
|
||||||
|
// アセットからダミー画像を読み込む
|
||||||
|
ByteData data = await rootBundle.load('assets/images/dummy_camera_image.png');
|
||||||
|
List<int> bytes = data.buffer.asUint8List();
|
||||||
|
|
||||||
|
// ダミー画像をファイルとして保存
|
||||||
|
await File(imagePath).writeAsBytes(bytes);
|
||||||
|
|
||||||
|
return imagePath;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (!_isCameraAvailable) {
|
||||||
|
return _buildDummyCameraView();
|
||||||
|
}
|
||||||
|
|
||||||
if (_controller == null || !_controller!.value.isInitialized) {
|
if (_controller == null || !_controller!.value.isInitialized) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
@ -182,4 +236,64 @@ class _CustomCameraViewState extends State<CustomCameraView> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildDummyCameraView() {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
color: Colors.black,
|
||||||
|
child: const Center(
|
||||||
|
child: Text(
|
||||||
|
'カメラを利用できません',
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 16.0,
|
||||||
|
left: 16.0,
|
||||||
|
right: 16.0,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(Icons.flash_off, color: Colors.white),
|
||||||
|
iconSize: 32,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: _captureEmulatedImage,
|
||||||
|
child: Container(
|
||||||
|
height: 80,
|
||||||
|
width: 80,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.white,
|
||||||
|
border: Border.all(color: Colors.red, width: 4),
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.camera_alt, color: Colors.red, size: 40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(Icons.flip_camera_ios, color: Colors.white),
|
||||||
|
iconSize: 32,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _captureEmulatedImage() async {
|
||||||
|
final Directory appDirectory = await getApplicationDocumentsDirectory();
|
||||||
|
final String imagePath = path.join(appDirectory.path, '${DateTime.now()}.jpg');
|
||||||
|
|
||||||
|
// ダミーの画像ファイルを作成
|
||||||
|
await File(imagePath).writeAsBytes(Uint8List(0));
|
||||||
|
|
||||||
|
widget.onImageCaptured(imagePath);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -29,12 +29,18 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||||
import 'package:gifunavi/widgets/debug_widget.dart';
|
import 'package:gifunavi/widgets/debug_widget.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
|
|
||||||
import 'package:gifunavi/pages/permission/permission.dart' ;
|
import 'package:gifunavi/pages/permission/permission.dart' ;
|
||||||
|
|
||||||
|
// 新しいインポート
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
|
||||||
// 目的地に関連する状態管理とロジックを担当するクラスです。
|
// 目的地に関連する状態管理とロジックを担当するクラスです。
|
||||||
//
|
//
|
||||||
class DestinationController extends GetxController {
|
class DestinationController extends GetxController {
|
||||||
@ -423,11 +429,11 @@ class DestinationController extends GetxController {
|
|||||||
// 写真撮影モードでない場合
|
// 写真撮影モードでない場合
|
||||||
|
|
||||||
if (ds.isEmpty) {
|
if (ds.isEmpty) {
|
||||||
debugPrint("* 目的地がない場合 ==> 検知半径=-1の場合");
|
//debugPrint("* 目的地がない場合 ==> ds=${ds}");
|
||||||
|
|
||||||
// print("----- in location popup cp - ${d.cp}----");
|
// print("----- in location popup cp - ${d.cp}----");
|
||||||
if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 10) {
|
if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 10) {
|
||||||
debugPrint("**1: 開始CPで、最後にゴールしてから24時間経過していれば、");
|
debugPrint("**1: 目的地がない場合で、スタート地点。開始CPで、最後にゴールしてから24時間経過していれば、");
|
||||||
|
|
||||||
chekcs = 1;
|
chekcs = 1;
|
||||||
//start
|
//start
|
||||||
@ -461,15 +467,15 @@ class DestinationController extends GetxController {
|
|||||||
// 以下の条件分岐を追加
|
// 以下の条件分岐を追加
|
||||||
} else if (ds.isNotEmpty && ds[0].checkedin == true) {
|
} else if (ds.isNotEmpty && ds[0].checkedin == true) {
|
||||||
// 目的地がDBに存在し、すでにチェックインしている場合は自動ポップアップを表示しない
|
// 目的地がDBに存在し、すでにチェックインしている場合は自動ポップアップを表示しない
|
||||||
debugPrint("チェックイン済み");
|
debugPrint("目的地がない場合で、チェックイン済み");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (isInRog.value == true &&
|
} else if (isInRog.value == true && // 常にfalse だよ。。
|
||||||
indexController.rogMode.value == 1 &&
|
indexController.rogMode.value == 1 && // マップではなくリストページだよ。
|
||||||
(locationAlreadyCheckedIn==false) &&
|
(locationAlreadyCheckedIn==false) && // まだチェックインしてないよ。
|
||||||
d.cp != -1 && d.cp != 0 && d.cp != -2) {
|
d.cp != -1 && d.cp != 0 && d.cp != -2) { // スタートでもゴールでもないよ。
|
||||||
|
|
||||||
debugPrint("**2: 標準CP まだチェックインしていない。");
|
debugPrint("**2: 目的地がない場合で、標準CP まだチェックインしていない。");
|
||||||
|
|
||||||
// print("----- in location popup checkin cp - ${d.cp}----");
|
// print("----- in location popup checkin cp - ${d.cp}----");
|
||||||
chekcs = 2; // 標準CP
|
chekcs = 2; // 標準CP
|
||||||
@ -494,14 +500,20 @@ class DestinationController extends GetxController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
}else{
|
||||||
|
debugPrint("**Else: isInRog=${isInRog.value}, rogMode=${indexController.rogMode.value},locationAlreadyCheckedIn=${locationAlreadyCheckedIn},d.cp=${d.cp}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 以降、検知範囲にある場合。
|
// 以降、検知範囲にある場合。
|
||||||
//debugPrint("検知範囲にある場合");
|
debugPrint("検知範囲にある場合だよ...");
|
||||||
|
|
||||||
|
debugPrint("---- 検知範囲: ${d.checkin_radious} > 距離:${distance} ----");
|
||||||
|
debugPrint("---- チェックイン済みか? $locationAlreadyCheckedIn ----");
|
||||||
|
debugPrint("---- isInRog : ${isInRog.value}, checkingin = ${isCheckingIn.value}");
|
||||||
|
debugPrint("---- buyPointImageAdded: ${buyPointImageAdded}, ds.isNotEmpty?: ${ds.isNotEmpty},buyPoint:${buyPoint},buyPointCanceled=${buyPointCanceled}");
|
||||||
|
debugPrint(" ");
|
||||||
|
|
||||||
// print("---- location checkin radious ${d.checkin_radious} ----");
|
|
||||||
// print("---- already checked in $locationAlreadyCheckedIn ----");
|
|
||||||
if ((checkinRadious >= distance || checkinRadious == -1) &&
|
if ((checkinRadious >= distance || checkinRadious == -1) &&
|
||||||
locationAlreadyCheckedIn == false &&
|
locationAlreadyCheckedIn == false &&
|
||||||
isInRog.value == true &&
|
isInRog.value == true &&
|
||||||
@ -515,9 +527,9 @@ class DestinationController extends GetxController {
|
|||||||
//print(
|
//print(
|
||||||
// "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ make checkin ${d.sub_loc_id}@@@@@@@@@@@");
|
// "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ make checkin ${d.sub_loc_id}@@@@@@@@@@@");
|
||||||
makeCheckin(d, true, ""); // チェックインして
|
makeCheckin(d, true, ""); // チェックインして
|
||||||
if (d.cp != -1 && d.cp != -2 && d.cp != 0 ) {
|
//if (d.cp != -1 && d.cp != -2 && d.cp != 0 ) {
|
||||||
rogainingCounted.value = true; // ゴール用チェックイン済み
|
// rogainingCounted.value = true; // ゴール用チェックイン済み
|
||||||
}
|
//}
|
||||||
skipGps = false;
|
skipGps = false;
|
||||||
}
|
}
|
||||||
return; // 戻る
|
return; // 戻る
|
||||||
@ -552,7 +564,9 @@ class DestinationController extends GetxController {
|
|||||||
))).whenComplete(() {
|
))).whenComplete(() {
|
||||||
shouldShowBottomSheet = true;
|
shouldShowBottomSheet = true;
|
||||||
skipGps = false;
|
skipGps = false;
|
||||||
rogainingCounted.value = true;
|
if( isInRog.value==true ) {
|
||||||
|
rogainingCounted.value = true;
|
||||||
|
}
|
||||||
chekcs = 0;
|
chekcs = 0;
|
||||||
isInCheckin.value = false;
|
isInCheckin.value = false;
|
||||||
isCheckingIn.value = false;
|
isCheckingIn.value = false;
|
||||||
@ -729,13 +743,15 @@ class DestinationController extends GetxController {
|
|||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
|
|
||||||
if (isgoal == false) {
|
if (isgoal == false) {
|
||||||
await db.deleteAllDestinations();
|
// await db.deleteAllDestinations();
|
||||||
await db.deleteAllRogaining();
|
// await db.deleteAllRogaining();
|
||||||
|
await db.deleteAllDestinationsExceptTodayCheckins();
|
||||||
|
await db.deleteAllRogainingExceptToday();
|
||||||
}
|
}
|
||||||
|
|
||||||
int? latgoal = await db.latestGoal();
|
int? latgoal = await db.latestGoal();
|
||||||
lastGoalAt = DateTime.fromMicrosecondsSinceEpoch(latgoal!);
|
lastGoalAt = DateTime.fromMicrosecondsSinceEpoch(latgoal!);
|
||||||
//print("===== last goal : $last_goal_at =====");
|
debugPrint("===== last goal : $lastGoalAt =====");
|
||||||
dbService.updateDatabase();
|
dbService.updateDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,7 +759,7 @@ class DestinationController extends GetxController {
|
|||||||
//
|
//
|
||||||
void deleteAllDestinations() {
|
void deleteAllDestinations() {
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
db.deleteAllDestinations().then((value) {
|
db.deleteAllDestinationsExceptTodayCheckins().then((value) {
|
||||||
populateDestinations();
|
populateDestinations();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -760,6 +776,18 @@ class DestinationController extends GetxController {
|
|||||||
photos.add(File(imagePath));
|
photos.add(File(imagePath));
|
||||||
},
|
},
|
||||||
destination: destination,
|
destination: destination,
|
||||||
|
onCameraStatusChanged: (isAvailable) {
|
||||||
|
// カメラの状態が変更されたときの処理
|
||||||
|
if (!isAvailable) {
|
||||||
|
// カメラが利用できない場合の処理
|
||||||
|
Get.snackbar(
|
||||||
|
'エラー',
|
||||||
|
'カメラを初期化できませんでした。',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
/*
|
/*
|
||||||
builder: (_) => CameraCamera(
|
builder: (_) => CameraCamera(
|
||||||
@ -859,7 +887,9 @@ class DestinationController extends GetxController {
|
|||||||
dbDest: dss,
|
dbDest: dss,
|
||||||
))).whenComplete(() {
|
))).whenComplete(() {
|
||||||
skipGps = false;
|
skipGps = false;
|
||||||
rogainingCounted.value = true;
|
if( isInRog.value == true ) { // ロゲ開始していれば、遠くまで来たことにする。
|
||||||
|
rogainingCounted.value = true;
|
||||||
|
}
|
||||||
chekcs = 0;
|
chekcs = 0;
|
||||||
isInCheckin.value = false;
|
isInCheckin.value = false;
|
||||||
//Get.back();
|
//Get.back();
|
||||||
@ -984,6 +1014,7 @@ class DestinationController extends GetxController {
|
|||||||
//
|
//
|
||||||
// 2024-4-8 Akira : See 2809
|
// 2024-4-8 Akira : See 2809
|
||||||
// checkForCheckinメソッドの再帰呼び出しをunawaitedで囲んで、非同期処理の結果を待たずに先に進むようにしました。また、再帰呼び出しの前に一定時間待機するようにしました。
|
// checkForCheckinメソッドの再帰呼び出しをunawaitedで囲んで、非同期処理の結果を待たずに先に進むようにしました。また、再帰呼び出しの前に一定時間待機するようにしました。
|
||||||
|
// 2024-8-24 ... 佐伯呼び出しが必要なのか?
|
||||||
//
|
//
|
||||||
Future<void> checkForCheckin() async {
|
Future<void> checkForCheckin() async {
|
||||||
//print("--- Start of checkForCheckin function ---");
|
//print("--- Start of checkForCheckin function ---");
|
||||||
@ -1022,13 +1053,15 @@ class DestinationController extends GetxController {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("An error occurred: $e");
|
print("An error occurred: $e");
|
||||||
// await checkForCheckin();
|
// await checkForCheckin();
|
||||||
} finally {
|
//} finally {
|
||||||
await Future.delayed(const Duration(seconds: 1)); // 一定時間待機してから再帰呼び出し
|
// await Future.delayed(const Duration(seconds: 1)); // 一定時間待機してから再帰呼び出し
|
||||||
//print("--- End of checkForCheckin function, calling recursively ---");
|
//print("--- End of checkForCheckin function, calling recursively ---");
|
||||||
unawaited( checkForCheckin() );
|
//unawaited( checkForCheckin() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// GPSデータをサーバーにプッシュする関数です。
|
// GPSデータをサーバーにプッシュする関数です。
|
||||||
//
|
//
|
||||||
Future<void> pushGPStoServer() async {
|
Future<void> pushGPStoServer() async {
|
||||||
@ -1089,55 +1122,46 @@ class DestinationController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _saveImageToGallery(String imagePath) async {
|
Future<String?> _saveImageToGallery(String imagePath) async {
|
||||||
final status = await PermissionController.checkStoragePermission();
|
final status = await PermissionController.checkStoragePermission();
|
||||||
if(!status){
|
if(!status){
|
||||||
await PermissionController.requestStoragePermission();
|
await PermissionController.requestStoragePermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
try {
|
||||||
final status = await Permission.storage.status;
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
if (!status.isGranted) {
|
//final fileName = path.basename(imagePath);
|
||||||
final result = await Permission.storage.request();
|
final fileName = 'checkin_${DateTime.now().millisecondsSinceEpoch}.jpg';
|
||||||
if (!result.isGranted) {
|
final savedImage = await File(imagePath).copy('${appDir.path}/$fileName');
|
||||||
// ユーザーがストレージの権限を拒否した場合の処理
|
|
||||||
showDialog(
|
|
||||||
context: Get.context!,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text('ストレージの権限が必要です'),
|
|
||||||
content: Text(
|
|
||||||
'画像をギャラリーに保存するには、ストレージの権限が必要です。アプリの設定画面で権限を許可してください。'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: Text('キャンセル'),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: Text('設定'),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
openAppSettings(); // アプリの設定画面を開く
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
debugPrint("fileName=${fileName}, appDir=${appDir} => ${savedImage}");
|
||||||
|
|
||||||
|
// ギャラリーにも保存
|
||||||
|
//await ImageGallerySaver.saveFile(savedImage.path);
|
||||||
|
await Future.delayed(const Duration(seconds: 3), () async {
|
||||||
|
final result = await ImageGallerySaver.saveFile(savedImage.path);
|
||||||
|
print("Save result: $result");
|
||||||
|
}).timeout(const Duration(seconds: 5));
|
||||||
|
|
||||||
|
|
||||||
|
debugPrint('Image saved to: ${savedImage.path}');
|
||||||
|
return savedImage.path;
|
||||||
|
|
||||||
|
/*
|
||||||
|
final result = await ImageGallerySaver.saveFile(imagePath);
|
||||||
|
debugPrint('Image saved to gallery: $result');
|
||||||
|
if (result['isSuccess']) {
|
||||||
|
return result['filePath'];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} catch (e) {
|
||||||
|
if (e is TimeoutException) {
|
||||||
|
print("Operation timed out");
|
||||||
|
} else {
|
||||||
|
print('Failed to save image to gallery: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
return null;
|
||||||
|
|
||||||
try {
|
|
||||||
final result = await ImageGallerySaver.saveFile(imagePath);
|
|
||||||
print('Image saved to gallery: $result');
|
|
||||||
} catch (e) {
|
|
||||||
print('Failed to save image to gallery: $e');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 買い物ポイントを作成する関数です。 指定された目的地に対して買い物ポイントの処理を行います。
|
// 買い物ポイントを作成する関数です。 指定された目的地に対して買い物ポイントの処理を行います。
|
||||||
@ -1145,13 +1169,10 @@ class DestinationController extends GetxController {
|
|||||||
// 買い物ポイントの作成に失敗した場合のエラーハンドリングを追加することを検討してください。
|
// 買い物ポイントの作成に失敗した場合のエラーハンドリングを追加することを検討してください。
|
||||||
//
|
//
|
||||||
Future<void> makeBuyPoint(Destination destination, String imageurl) async {
|
Future<void> makeBuyPoint(Destination destination, String imageurl) async {
|
||||||
|
String? savedImagePath = await _saveImageToGallery(imageurl);
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
await db.updateBuyPoint(destination, imageurl);
|
await db.updateBuyPoint(destination, savedImagePath ?? imageurl);
|
||||||
populateDestinations();
|
populateDestinations();
|
||||||
//await _saveImageFromPath(imageurl);
|
|
||||||
await _saveImageToGallery(imageurl);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (indexController.currentUser.isNotEmpty) {
|
if (indexController.currentUser.isNotEmpty) {
|
||||||
double cpNum = destination.cp!;
|
double cpNum = destination.cp!;
|
||||||
@ -1160,6 +1181,7 @@ class DestinationController extends GetxController {
|
|||||||
|
|
||||||
int userId = indexController.currentUser[0]["user"]["id"];
|
int userId = indexController.currentUser[0]["user"]["id"];
|
||||||
//print("--- Pressed -----");
|
//print("--- Pressed -----");
|
||||||
|
debugPrint("user=${indexController.currentUser[0]["user"]}");
|
||||||
String team = indexController.currentUser[0]["user"]['team_name'];
|
String team = indexController.currentUser[0]["user"]['team_name'];
|
||||||
//print("--- _team : ${_team}-----");
|
//print("--- _team : ${_team}-----");
|
||||||
String eventCode = indexController.currentUser[0]["user"]["event_code"];
|
String eventCode = indexController.currentUser[0]["user"]["event_code"];
|
||||||
@ -1172,7 +1194,7 @@ class DestinationController extends GetxController {
|
|||||||
//print("------ checkin event $eventCode ------");
|
//print("------ checkin event $eventCode ------");
|
||||||
ExternalService()
|
ExternalService()
|
||||||
.makeCheckpoint(userId, token, formattedDate, team, cpNum.round(),
|
.makeCheckpoint(userId, token, formattedDate, team, cpNum.round(),
|
||||||
eventCode, imageurl)
|
eventCode, savedImagePath ?? imageurl)
|
||||||
.then((value) {
|
.then((value) {
|
||||||
//print("------Ext service check point $value ------");
|
//print("------Ext service check point $value ------");
|
||||||
});
|
});
|
||||||
@ -1197,7 +1219,10 @@ class DestinationController extends GetxController {
|
|||||||
|
|
||||||
if (ddd.isEmpty) {
|
if (ddd.isEmpty) {
|
||||||
destination.checkedin = true;
|
destination.checkedin = true;
|
||||||
destination.checkin_image = imageurl;
|
if (imageurl.isNotEmpty) {
|
||||||
|
String? savedImagePath = await _saveImageToGallery(imageurl);
|
||||||
|
destination.checkin_image = savedImagePath ?? imageurl;
|
||||||
|
}
|
||||||
await db.insertDestination(destination);
|
await db.insertDestination(destination);
|
||||||
// print("~~~~ inserted into db ~~~~");
|
// print("~~~~ inserted into db ~~~~");
|
||||||
}
|
}
|
||||||
@ -1212,7 +1237,8 @@ class DestinationController extends GetxController {
|
|||||||
//await _saveImageFromPath(imageurl!);
|
//await _saveImageFromPath(imageurl!);
|
||||||
}
|
}
|
||||||
if (imageurl.isNotEmpty) {
|
if (imageurl.isNotEmpty) {
|
||||||
await _saveImageToGallery(imageurl);
|
String? savedImagePath = await _saveImageToGallery(imageurl);
|
||||||
|
destination.checkin_image = savedImagePath ?? imageurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
populateDestinations();
|
populateDestinations();
|
||||||
@ -1299,11 +1325,11 @@ class DestinationController extends GetxController {
|
|||||||
void onInit() async {
|
void onInit() async {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
|
||||||
/*
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
await PermissionController.checkAndRequestPermissions();
|
await PermissionController.checkAndRequestPermissions();
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
startGPSCheckTimer();
|
startGPSCheckTimer();
|
||||||
|
|
||||||
@ -1810,7 +1836,7 @@ class DestinationController extends GetxController {
|
|||||||
//
|
//
|
||||||
void deleteDBDestinations() {
|
void deleteDBDestinations() {
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
db.deleteAllDestinations().then((value) {
|
db.deleteAllDestinationsExceptTodayCheckins().then((value) {
|
||||||
populateDestinations();
|
populateDestinations();
|
||||||
});
|
});
|
||||||
dbService.updateDatabase();
|
dbService.updateDatabase();
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import 'package:get/get.dart';
|
|||||||
import 'package:gifunavi/pages/entry/entry_controller.dart';
|
import 'package:gifunavi/pages/entry/entry_controller.dart';
|
||||||
import 'package:gifunavi/services/api_service.dart';
|
import 'package:gifunavi/services/api_service.dart';
|
||||||
|
|
||||||
|
import '../index/index_controller.dart';
|
||||||
|
|
||||||
class EntryBinding extends Bindings {
|
class EntryBinding extends Bindings {
|
||||||
@override
|
@override
|
||||||
void dependencies() {
|
void dependencies() {
|
||||||
|
|||||||
@ -191,18 +191,21 @@ class EntryController extends GetxController {
|
|||||||
final updatedCategory = await _apiService.getZekkenNumber(selectedCategory.value!.id);
|
final updatedCategory = await _apiService.getZekkenNumber(selectedCategory.value!.id);
|
||||||
final zekkenNumber = updatedCategory.categoryNumber.toString();
|
final zekkenNumber = updatedCategory.categoryNumber.toString();
|
||||||
|
|
||||||
|
// selectedDate.value に 9時間を加えてJSTのオフセットを適用
|
||||||
|
final jstDate = selectedDate.value!.add(const Duration(hours: 9));
|
||||||
|
|
||||||
final newEntry = await _apiService.createEntry(
|
final newEntry = await _apiService.createEntry(
|
||||||
selectedTeam.value!.id,
|
selectedTeam.value!.id,
|
||||||
selectedEvent.value!.id,
|
selectedEvent.value!.id,
|
||||||
selectedCategory.value!.id,
|
selectedCategory.value!.id,
|
||||||
selectedDate.value!,
|
jstDate, // JSTオフセットが適用された日付を使用
|
||||||
zekkenNumber,
|
zekkenNumber,
|
||||||
);
|
);
|
||||||
entries.add(newEntry);
|
entries.add(newEntry);
|
||||||
Get.back();
|
Get.back();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error creating entry: $e');
|
print('Error creating entry: $e');
|
||||||
Get.snackbar('Error', 'Failed to create entry');
|
Get.snackbar('Error', '$e');
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:gifunavi/model/destination.dart';
|
import 'package:gifunavi/model/destination.dart';
|
||||||
import 'package:gifunavi/utils/database_helper.dart';
|
import 'package:gifunavi/utils/database_helper.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
class HistoryPage extends StatefulWidget {
|
class HistoryPage extends StatefulWidget {
|
||||||
const HistoryPage({super.key});
|
const HistoryPage({super.key});
|
||||||
@ -15,6 +17,48 @@ class HistoryPage extends StatefulWidget {
|
|||||||
class _HistoryPageState extends State<HistoryPage> {
|
class _HistoryPageState extends State<HistoryPage> {
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("pass_history".tr),
|
||||||
|
),
|
||||||
|
body: FutureBuilder<List<Destination>>(
|
||||||
|
future: db.getDestinations(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Center(child: Text('Error: ${snapshot.error}'));
|
||||||
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||||
|
return Center(child: Text("no_checkin_yet".tr));
|
||||||
|
}
|
||||||
|
|
||||||
|
final dests = snapshot.data!;
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: dests.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: CustomWidget(
|
||||||
|
title: dests[index].name ?? 'No Name',
|
||||||
|
subtitle: "${dests[index].sub_loc_id ?? 'N/A'} : ${dests[index].name ?? 'N/A'}",
|
||||||
|
image1Path: dests[index].checkin_image,
|
||||||
|
image2Path: dests[index].buypoint_image,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
class _HistoryPageState_old extends State<HistoryPage> {
|
||||||
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -86,8 +130,97 @@ class _HistoryPageState extends State<HistoryPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
class CustomWidget extends StatelessWidget {
|
class CustomWidget extends StatelessWidget {
|
||||||
|
final String? image1Path;
|
||||||
|
final String? image2Path;
|
||||||
|
final String title;
|
||||||
|
final String subtitle;
|
||||||
|
|
||||||
|
const CustomWidget({
|
||||||
|
super.key,
|
||||||
|
this.image1Path,
|
||||||
|
this.image2Path,
|
||||||
|
required this.title,
|
||||||
|
required this.subtitle,
|
||||||
|
});
|
||||||
|
|
||||||
|
Widget _buildImage(String? path) {
|
||||||
|
if (path == null) return const SizedBox.shrink();
|
||||||
|
|
||||||
|
return FutureBuilder<String>(
|
||||||
|
future: _getFullImagePath(path),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
|
||||||
|
return Image.file(
|
||||||
|
File(snapshot.data!),
|
||||||
|
width: 50,
|
||||||
|
height: 100,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
print('Error loading image: $error');
|
||||||
|
return const Icon(Icons.error);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
print('Error loading image path: ${snapshot.error}');
|
||||||
|
return const Icon(Icons.error);
|
||||||
|
} else {
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _getFullImagePath(String imagePath) async {
|
||||||
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
|
final fileName = path.basename(imagePath);
|
||||||
|
final fullPath = path.join(appDir.path, fileName);
|
||||||
|
debugPrint("Full image path: $fullPath");
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 104,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
_buildImage(image1Path),
|
||||||
|
if (image1Path != null && image2Path != null) const SizedBox(width: 2),
|
||||||
|
_buildImage(image2Path),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
|
maxLines: null,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
subtitle,
|
||||||
|
style: const TextStyle(fontSize: 16),
|
||||||
|
maxLines: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
class CustomWidget_old extends StatelessWidget {
|
||||||
final Image? image1;
|
final Image? image1;
|
||||||
final Image? image2;
|
final Image? image2;
|
||||||
final String title;
|
final String title;
|
||||||
@ -152,3 +285,4 @@ class CustomWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
@ -3,12 +3,18 @@ import 'package:gifunavi/pages/destination/destination_controller.dart';
|
|||||||
import 'package:gifunavi/pages/index/index_controller.dart';
|
import 'package:gifunavi/pages/index/index_controller.dart';
|
||||||
import 'package:gifunavi/utils/location_controller.dart';
|
import 'package:gifunavi/utils/location_controller.dart';
|
||||||
|
|
||||||
|
import '../../services/api_service.dart';
|
||||||
|
|
||||||
class IndexBinding extends Bindings {
|
class IndexBinding extends Bindings {
|
||||||
@override
|
@override
|
||||||
void dependencies() {
|
void dependencies() {
|
||||||
Get.lazyPut<IndexController>(() => IndexController());
|
//Get.lazyPut<IndexController>(() => IndexController());
|
||||||
//Get.put<IndexController>(IndexController());
|
////Get.put<IndexController>(IndexController());
|
||||||
Get.put<LocationController>(LocationController());
|
//Get.put<LocationController>(LocationController());
|
||||||
Get.put<DestinationController>(DestinationController());
|
//Get.put<DestinationController>(DestinationController());
|
||||||
|
|
||||||
|
Get.put(IndexController(apiService: Get.find<ApiService>()), permanent: true);
|
||||||
|
Get.put(LocationController(), permanent: true);
|
||||||
|
Get.put(DestinationController(), permanent: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -31,6 +32,8 @@ import 'package:gifunavi/widgets/helper_dialog.dart';
|
|||||||
import 'package:timezone/timezone.dart' as tz;
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
|
||||||
|
import '../permission/permission.dart';
|
||||||
|
|
||||||
class IndexController extends GetxController with WidgetsBindingObserver {
|
class IndexController extends GetxController with WidgetsBindingObserver {
|
||||||
List<GeoJSONFeatureCollection> locations = <GeoJSONFeatureCollection>[].obs;
|
List<GeoJSONFeatureCollection> locations = <GeoJSONFeatureCollection>[].obs;
|
||||||
List<GeoJSONFeature> currentFeature = <GeoJSONFeature>[].obs;
|
List<GeoJSONFeature> currentFeature = <GeoJSONFeature>[].obs;
|
||||||
@ -68,9 +71,14 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
String? userToken;
|
String? userToken;
|
||||||
|
|
||||||
//late final ApiService _apiService;
|
//late final ApiService _apiService;
|
||||||
final ApiService _apiService = Get.find<ApiService>();
|
final ApiService _apiService; // = Get.find<ApiService>();
|
||||||
final DatabaseHelper _dbHelper = DatabaseHelper.instance;
|
final DatabaseHelper _dbHelper = DatabaseHelper.instance;
|
||||||
|
|
||||||
|
IndexController({
|
||||||
|
required ApiService apiService,
|
||||||
|
}) : _apiService = apiService;
|
||||||
|
|
||||||
|
|
||||||
// mode = 0 is map mode, mode = 1 list mode
|
// mode = 0 is map mode, mode = 1 list mode
|
||||||
var mode = 0.obs;
|
var mode = 0.obs;
|
||||||
|
|
||||||
@ -235,6 +243,10 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
initConnectivity();
|
initConnectivity();
|
||||||
_connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
|
_connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
await PermissionController.checkAndRequestPermissions();
|
||||||
|
});
|
||||||
|
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
_startLocationService(); // アプリ起動時にLocationServiceを開始する
|
_startLocationService(); // アプリ起動時にLocationServiceを開始する
|
||||||
|
|
||||||
@ -263,10 +275,10 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
connectionStatusName.value = "WiFi";
|
connectionStatusName.value = "WiFi";
|
||||||
break;
|
break;
|
||||||
case ConnectivityResult.mobile:
|
case ConnectivityResult.mobile:
|
||||||
connectionStatusName.value = "モバイルデータ";
|
connectionStatusName.value = "mobile";
|
||||||
break;
|
break;
|
||||||
case ConnectivityResult.none:
|
case ConnectivityResult.none:
|
||||||
connectionStatusName.value = "オフライン";
|
connectionStatusName.value = "offline";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
connectionStatusName.value = "不明";
|
connectionStatusName.value = "不明";
|
||||||
@ -352,22 +364,53 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _startLocationService() async {
|
void _startLocationService() async {
|
||||||
const platform = MethodChannel('location');
|
if (Platform.isAndroid) {
|
||||||
try {
|
const platform = MethodChannel('location');
|
||||||
logManager.addOperationLog("Called start location service.");
|
try {
|
||||||
await platform.invokeMethod('startLocationService');
|
logManager.addOperationLog("Called start location service.");
|
||||||
} on PlatformException catch (e) {
|
await platform.invokeMethod('startLocationService');
|
||||||
print("Failed to start location service: '${e.message}'.");
|
} on PlatformException catch (e) {
|
||||||
|
print("Failed to start location service: '${e.message}'.");
|
||||||
|
}
|
||||||
|
}else if (Platform.isIOS) {
|
||||||
|
// iOSの位置情報サービス開始ロジック
|
||||||
|
// 例: geolocatorプラグインを使用する場合
|
||||||
|
try {
|
||||||
|
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||||
|
if (!serviceEnabled) {
|
||||||
|
// 位置情報サービスが無効の場合の処理
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 位置情報の権限確認と取得開始
|
||||||
|
LocationPermission permission = await Geolocator.checkPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
permission = await Geolocator.requestPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
// 権限が拒否された場合の処理
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 位置情報の取得開始
|
||||||
|
Geolocator.getPositionStream().listen((Position position) {
|
||||||
|
// 位置情報を使用した処理
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
print('Error starting iOS location service: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _stopLocationService() async {
|
void _stopLocationService() async {
|
||||||
const platform = MethodChannel('location');
|
if (Platform.isAndroid) {
|
||||||
try {
|
const platform = MethodChannel('location');
|
||||||
logManager.addOperationLog("Called stop location service.");
|
try {
|
||||||
await platform.invokeMethod('stopLocationService');
|
logManager.addOperationLog("Called stop location service.");
|
||||||
} on PlatformException catch (e) {
|
await platform.invokeMethod('stopLocationService');
|
||||||
print("Failed to stop location service: '${e.message}'.");
|
} on PlatformException catch (e) {
|
||||||
|
print("Failed to stop location service: '${e.message}'.");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
debugPrint("stopLocation for iOS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,51 +476,75 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// 要検討:エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
|
// 要検討:エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
|
||||||
//
|
//
|
||||||
void login(String email, String password, BuildContext context) async{
|
Future<void> login(String email, String password) async {
|
||||||
|
try {
|
||||||
AuthService.login(email, password).then((value) async {
|
final value = await AuthService.login(email, password);
|
||||||
print("------- logged in user details ######## $value ###### --------");
|
if (value.isNotEmpty && value['token'] != null) {
|
||||||
if (value.isNotEmpty) {
|
await changeUser(value);
|
||||||
logManager.addOperationLog("User logged in : $value.");
|
await _initializeUserData();
|
||||||
|
Get.offAllNamed(AppPages.INDEX);
|
||||||
// Navigator.pop(context);
|
|
||||||
print("--------- user details login ----- $value");
|
|
||||||
changeUser(value);
|
|
||||||
|
|
||||||
// ログイン成功後、api_serviceを初期化
|
|
||||||
await Get.putAsync(() => ApiService().init());
|
|
||||||
|
|
||||||
// ユーザー情報の完全性をチェック
|
|
||||||
if (await checkUserInfoComplete()) {
|
|
||||||
Get.offAllNamed(AppPages.INDEX);
|
|
||||||
} else {
|
|
||||||
Get.offAllNamed(AppPages.USER_DETAILS_EDIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logManager.addOperationLog("User failed login : $email , $password.");
|
Get.snackbar('Login Failed', 'Invalid credentials');
|
||||||
isLoading.value = false;
|
}
|
||||||
Get.snackbar(
|
} catch (e) {
|
||||||
"login_failed".tr,
|
print('Login error: $e');
|
||||||
"check_login_id_or_password".tr,
|
Get.snackbar('Login Failed', 'An error occurred. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initializeUserData() async {
|
||||||
|
try {
|
||||||
|
await fetchUserEventInfo();
|
||||||
|
await fetchTeamData();
|
||||||
|
// 他の必要なデータ取得処理
|
||||||
|
} catch (e) {
|
||||||
|
print('Error initializing user data: $e');
|
||||||
|
Get.snackbar('Error', 'Failed to load user data. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future<void> login_old(String email, String password, BuildContext context) async{
|
||||||
|
|
||||||
|
try {
|
||||||
|
AuthService.login(email, password).then((value) async {
|
||||||
|
print("------- logged in user details ######## $value ###### --------");
|
||||||
|
if (value.isNotEmpty && value['token']!=null) {
|
||||||
|
logManager.addOperationLog("User logged in : $value.");
|
||||||
|
|
||||||
|
// Navigator.pop(context);
|
||||||
|
print("--------- user details login ----- $value");
|
||||||
|
// ログイン成功後、api_serviceを初期化
|
||||||
|
await Get.putAsync(() => ApiService().init());
|
||||||
|
|
||||||
|
// ユーザー情報の完全性をチェック
|
||||||
|
if (await checkUserInfoComplete()) {
|
||||||
|
Get.offAllNamed(AppPages.INDEX);
|
||||||
|
} else {
|
||||||
|
Get.offAllNamed(AppPages.USER_DETAILS_EDIT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logManager.addOperationLog("User failed login : $email , $password.");
|
||||||
|
isLoading.value = false;
|
||||||
|
Get.snackbar(
|
||||||
|
"login_failed".tr,
|
||||||
|
"check_login_id_or_password".tr,
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
colorText: Colors.white,
|
colorText: Colors.white,
|
||||||
icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
|
icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
|
||||||
snackPosition: SnackPosition.TOP,
|
snackPosition: SnackPosition.TOP,
|
||||||
duration: const Duration(seconds: 3),
|
duration: const Duration(seconds: 3),
|
||||||
//backgroundColor: Colors.yellow,
|
//backgroundColor: Colors.yellow,
|
||||||
//icon:Image(image:AssetImage("assets/images/dora.png"))
|
//icon:Image(image:AssetImage("assets/images/dora.png"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} catch(e ){
|
||||||
|
print('Login error: $e');
|
||||||
|
Get.snackbar('Login Failed', 'An error occurred. Please try again.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> checkUserInfoComplete() async {
|
|
||||||
final user = await ApiService.to.getCurrentUser();
|
|
||||||
return user.firstname.isNotEmpty &&
|
|
||||||
user.lastname.isNotEmpty &&
|
|
||||||
user.dateOfBirth != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 要検討:エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
|
// 要検討:エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
|
||||||
//
|
//
|
||||||
@ -532,12 +599,12 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void logout() async {
|
Future<void> logout() async {
|
||||||
logManager.addOperationLog("User logout : $currentUser .");
|
logManager.addOperationLog("User logout : $currentUser .");
|
||||||
saveGameState();
|
saveGameState();
|
||||||
locations.clear();
|
locations.clear();
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
db.deleteAllDestinations().then((value) {
|
db.deleteAllDestinationsExceptTodayCheckins().then((value) {
|
||||||
DestinationController destinationController =
|
DestinationController destinationController =
|
||||||
Get.find<DestinationController>();
|
Get.find<DestinationController>();
|
||||||
destinationController.populateDestinations();
|
destinationController.populateDestinations();
|
||||||
@ -619,28 +686,48 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void changeUser(Map<String, dynamic> value, {bool replace = true}) async{
|
Future<void> changeUser(Map<String, dynamic> value, {bool replace = true}) async{
|
||||||
currentUser.clear();
|
try {
|
||||||
currentUser.add(value);
|
if (value['user'] == null || value['token'] == null) {
|
||||||
if (replace) {
|
throw Exception('Invalid user data');
|
||||||
saveToDevice(currentUser[0]["token"]);
|
}
|
||||||
|
currentUser.clear();
|
||||||
|
currentUser.add(value);
|
||||||
|
if (replace) {
|
||||||
|
saveToDevice(currentUser[0]["token"]);
|
||||||
|
}
|
||||||
|
isLoading.value = false;
|
||||||
|
|
||||||
|
// ユーザーのイベント情報を取得
|
||||||
|
await fetchUserEventInfo();
|
||||||
|
|
||||||
|
loadLocationsBound(currentUser[0]["user"]["event_code"]);
|
||||||
|
if (currentUser.isNotEmpty) {
|
||||||
|
rogMode.value = 0;
|
||||||
|
restoreGame();
|
||||||
|
|
||||||
|
// チームデータを取得
|
||||||
|
await fetchTeamData();
|
||||||
|
} else {
|
||||||
|
rogMode.value = 1;
|
||||||
|
}
|
||||||
|
Get.toNamed(AppPages.INDEX);
|
||||||
|
} catch( e ){
|
||||||
|
print('Error in changeUser: $e');
|
||||||
|
Get.snackbar('Error', 'Failed to update user information');
|
||||||
}
|
}
|
||||||
isLoading.value = false;
|
}
|
||||||
|
|
||||||
// ユーザーのイベント情報を取得
|
Future<bool> checkUserInfoComplete() async {
|
||||||
await fetchUserEventInfo();
|
try {
|
||||||
|
final user = await ApiService.to.getCurrentUser();
|
||||||
loadLocationsBound( currentUser[0]["user"]["event_code"]);
|
return user.firstname.isNotEmpty &&
|
||||||
if (currentUser.isNotEmpty) {
|
user.lastname.isNotEmpty &&
|
||||||
rogMode.value = 0;
|
user.dateOfBirth != null;
|
||||||
restoreGame();
|
} catch (e) {
|
||||||
|
print('Error checking user info: $e');
|
||||||
// チームデータを取得
|
return false;
|
||||||
await fetchTeamData();
|
|
||||||
} else {
|
|
||||||
rogMode.value = 1;
|
|
||||||
}
|
}
|
||||||
Get.toNamed(AppPages.INDEX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchUserEventInfo() async {
|
Future<void> fetchUserEventInfo() async {
|
||||||
@ -697,7 +784,7 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
Future<void> fetchTeamData() async {
|
Future<void> fetchTeamData() async {
|
||||||
try {
|
try {
|
||||||
Get.put(TeamController());
|
Get.put(TeamController(apiService:Get.find<ApiService>()));
|
||||||
// \"TeamController\" not found. You need to call \"Get.put(TeamController())\" or \"Get.lazyPut(()=>TeamController())\"
|
// \"TeamController\" not found. You need to call \"Get.put(TeamController())\" or \"Get.lazyPut(()=>TeamController())\"
|
||||||
final teamController = Get.find<TeamController>();
|
final teamController = Get.find<TeamController>();
|
||||||
await teamController.fetchTeams();
|
await teamController.fetchTeams();
|
||||||
@ -945,7 +1032,7 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
Future<void> checkEntryData() async {
|
Future<void> checkEntryData() async {
|
||||||
// エントリーデータの有無をチェックするロジック
|
// エントリーデータの有無をチェックするロジック
|
||||||
final teamController = TeamController();
|
final teamController = TeamController(apiService:Get.find<ApiService>());
|
||||||
bool hasEntryData = teamController.checkIfUserHasEntryData();
|
bool hasEntryData = teamController.checkIfUserHasEntryData();
|
||||||
if (!hasEntryData) {
|
if (!hasEntryData) {
|
||||||
await showHelperDialog(
|
await showHelperDialog(
|
||||||
|
|||||||
@ -38,10 +38,21 @@ class _IndexPageState extends State<IndexPage> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
//checkLoginAndShowDialog();
|
//checkLoginAndShowDialog();
|
||||||
|
//checkEventAndNavigate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkLoginAndShowDialog() {
|
void checkEventAndNavigate() async {
|
||||||
|
if (indexController.currentUser.isNotEmpty &&
|
||||||
|
indexController.currentUser[0]["user"]["event_code"] == null) {
|
||||||
|
// イベントコードがない場合、EVENT_ENTRYページに遷移
|
||||||
|
await Get.toNamed(AppPages.EVENT_ENTRY);
|
||||||
|
// EVENT_ENTRYページから戻ってきた後に警告を表示
|
||||||
|
_showEventSelectionWarning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkLoginAndShowDialog() async {
|
||||||
if (indexController.currentUser.isEmpty) {
|
if (indexController.currentUser.isEmpty) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -78,9 +89,30 @@ class _IndexPageState extends State<IndexPage> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}else{
|
||||||
|
if(indexController.currentUser[0]["user"]["event_code"] == null) {
|
||||||
|
// イベントコードがない場合、EVENT_ENTRYページに遷移
|
||||||
|
await Get.toNamed(AppPages.EVENT_ENTRY);
|
||||||
|
// EVENT_ENTRYページから戻ってきた後に警告を表示
|
||||||
|
_showEventSelectionWarning();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showEventSelectionWarning() {
|
||||||
|
Get.dialog(
|
||||||
|
AlertDialog(
|
||||||
|
title: Text('警告'),
|
||||||
|
content: Text('イベントを選択してください。'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text('OK'),
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// class IndexPage extends GetView<IndexController> {
|
// class IndexPage extends GetView<IndexController> {
|
||||||
// IndexPage({Key? key}) : super(key: key);
|
// IndexPage({Key? key}) : super(key: key);
|
||||||
|
|||||||
@ -119,8 +119,7 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
onTap: () => FocusScope.of(context).unfocus(),
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
child: indexController.currentUser.isEmpty
|
child: indexController.currentUser.isEmpty
|
||||||
? SizedBox(
|
? SingleChildScrollView(
|
||||||
width: double.infinity,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -216,8 +215,8 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
true;
|
true;
|
||||||
indexController.login(
|
indexController.login(
|
||||||
emailController.text,
|
emailController.text,
|
||||||
passwordController.text,
|
passwordController.text
|
||||||
context);
|
);
|
||||||
},
|
},
|
||||||
color: Colors.indigoAccent[400],
|
color: Colors.indigoAccent[400],
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@ -271,37 +270,34 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(8.0),
|
||||||
Flexible(
|
child: Row(
|
||||||
child: Padding(
|
children: [
|
||||||
padding: const EdgeInsets.all(8.0),
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"app_developed_by_gifu_dx".tr,
|
"app_developed_by_gifu_dx".tr,
|
||||||
style: const TextStyle(
|
style: const TextStyle(fontSize: 10.0),
|
||||||
overflow: TextOverflow.ellipsis,
|
textAlign: TextAlign.center,
|
||||||
fontSize: 10.0),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
const Row(
|
Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
padding: const EdgeInsets.all(8.0),
|
||||||
children: [
|
child: Row(
|
||||||
Flexible(
|
children: [
|
||||||
child: Padding(
|
Expanded(
|
||||||
padding: EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
"※第8回と第9回は、岐阜県の令和5年度「清流の国ぎふ」SDGs推進ネットワーク連携促進補助金を受けています",
|
"※第8回と第9回は、岐阜県の令和5年度「清流の国ぎふ」SDGs推進ネットワーク連携促進補助金を受けています",
|
||||||
style: TextStyle(
|
style: const TextStyle(fontSize: 10.0),
|
||||||
fontSize: 10.0,
|
textAlign: TextAlign.center,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -120,8 +120,8 @@ class LoginPopupPage extends StatelessWidget {
|
|||||||
true;
|
true;
|
||||||
indexController.login(
|
indexController.login(
|
||||||
emailController.text,
|
emailController.text,
|
||||||
passwordController.text,
|
passwordController.text
|
||||||
context);
|
);
|
||||||
},
|
},
|
||||||
color: Colors.indigoAccent[400],
|
color: Colors.indigoAccent[400],
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -10,15 +12,6 @@ class PermissionController {
|
|||||||
static bool _isRequestingPermission = false;
|
static bool _isRequestingPermission = false;
|
||||||
static Completer<bool>? _permissionCompleter;
|
static Completer<bool>? _permissionCompleter;
|
||||||
|
|
||||||
static Future<bool> 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<bool> checkAndRequestPermissions() async {
|
static Future<bool> checkAndRequestPermissions() async {
|
||||||
if (_isRequestingPermission) {
|
if (_isRequestingPermission) {
|
||||||
return _permissionCompleter!.future;
|
return _permissionCompleter!.future;
|
||||||
@ -27,13 +20,119 @@ class PermissionController {
|
|||||||
_isRequestingPermission = true;
|
_isRequestingPermission = true;
|
||||||
_permissionCompleter = Completer<bool>();
|
_permissionCompleter = Completer<bool>();
|
||||||
|
|
||||||
bool hasPermissions = await checkLocationPermissions();
|
try {
|
||||||
|
bool hasPermissions = await _checkLocationPermissions();
|
||||||
|
if (!hasPermissions) {
|
||||||
|
bool userAgreed = await showLocationDisclosure();
|
||||||
|
if (userAgreed) {
|
||||||
|
if (Platform.isAndroid && !await _isAndroid13OrAbove()) {
|
||||||
|
hasPermissions = await _requestAndroidPreS();
|
||||||
|
} else {
|
||||||
|
hasPermissions = await _requestAllLocationPermissions();
|
||||||
|
}
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _permissionCompleter!.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> _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<bool> _requestAllLocationPermissions() async {
|
||||||
|
await Permission.location.request();
|
||||||
|
await Permission.locationWhenInUse.request();
|
||||||
|
final alwaysStatus = await Permission.locationAlways.request();
|
||||||
|
|
||||||
|
return alwaysStatus == PermissionStatus.granted;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> _requestAndroidPreS() async {
|
||||||
|
await Permission.location.request();
|
||||||
|
await Permission.locationWhenInUse.request();
|
||||||
|
|
||||||
|
// Android 13以前では、ユーザーに設定画面で権限を許可するように促す
|
||||||
|
await showDialog(
|
||||||
|
context: Get.context!,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text('バックグラウンド位置情報の許可'),
|
||||||
|
content: Text('アプリの設定画面で「常に許可」を選択してください。'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text('設定を開く'),
|
||||||
|
onPressed: () {
|
||||||
|
openAppSettings();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 設定画面から戻ってきた後、再度権限をチェック
|
||||||
|
return await Permission.locationAlways.isGranted;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> _isAndroid13OrAbove() async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final androidVersion = int.tryParse(Platform.operatingSystemVersion.split('.').first) ?? 0;
|
||||||
|
return androidVersion >= 13;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Future<bool> checkLocationPermissions_old() async {
|
||||||
|
final locationPermission = await Permission.location.status;
|
||||||
|
if (locationPermission.isDenied) {
|
||||||
|
await showLocationDisclosure();
|
||||||
|
final result = await Permission.location.request();
|
||||||
|
if (result.isDenied) {
|
||||||
|
await openAppSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final whenInUsePermission = await Permission.locationWhenInUse.status;
|
||||||
|
final alwaysPermission = await Permission.locationAlways.status;
|
||||||
|
|
||||||
|
return locationPermission == PermissionStatus.granted &&
|
||||||
|
(whenInUsePermission == PermissionStatus.granted || alwaysPermission == PermissionStatus.granted);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> checkAndRequestPermissions_old() async {
|
||||||
|
if (_isRequestingPermission) {
|
||||||
|
return _permissionCompleter!.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isRequestingPermission = true;
|
||||||
|
_permissionCompleter = Completer<bool>();
|
||||||
|
|
||||||
|
bool hasPermissions = await _checkLocationPermissions();
|
||||||
if (!hasPermissions) {
|
if (!hasPermissions) {
|
||||||
bool userAgreed = await showLocationDisclosure();
|
bool userAgreed = await showLocationDisclosure();
|
||||||
if (userAgreed) {
|
if (userAgreed) {
|
||||||
try {
|
try {
|
||||||
await requestAllLocationPermissions();
|
await requestAllLocationPermissions();
|
||||||
hasPermissions = await checkLocationPermissions();
|
hasPermissions = await _checkLocationPermissions();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error requesting location permissions: $e');
|
print('Error requesting location permissions: $e');
|
||||||
hasPermissions = false;
|
hasPermissions = false;
|
||||||
@ -48,6 +147,8 @@ class PermissionController {
|
|||||||
|
|
||||||
_isRequestingPermission = false;
|
_isRequestingPermission = false;
|
||||||
_permissionCompleter!.complete(hasPermissions);
|
_permissionCompleter!.complete(hasPermissions);
|
||||||
|
|
||||||
|
debugPrint("Finish checkAndRequestPermissions...");
|
||||||
return _permissionCompleter!.future;
|
return _permissionCompleter!.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,35 +168,51 @@ class PermissionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<bool> showLocationDisclosure() async {
|
static Future<bool> showLocationDisclosure() async {
|
||||||
return await Get.dialog<bool>(
|
if (Get.context == null) {
|
||||||
AlertDialog(
|
print('Context is null, cannot show dialog');
|
||||||
title: const Text('位置情報の使用について'),
|
return false;
|
||||||
content: const SingleChildScrollView(
|
}
|
||||||
child: ListBody(
|
if (Get.isDialogOpen ?? false) {
|
||||||
children: <Widget>[
|
print('A dialog is already open');
|
||||||
Text('このアプリでは、以下の目的で位置情報を使用します:'),
|
return false;
|
||||||
Text('• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'),
|
}
|
||||||
Text('• 移動履歴の記録(バックグラウンドでも継続)'),
|
|
||||||
Text('• 現在地周辺の情報表示'),
|
try {
|
||||||
Text('\nバックグラウンドでも位置情報を継続的に取得します。'),
|
final result = await Get.dialog<bool>(
|
||||||
Text('これにより、バッテリーの消費が増加する可能性があります。'),
|
AlertDialog(
|
||||||
Text('同意しない場合には、アプリは終了します。'),
|
title: const Text('位置情報の使用について'),
|
||||||
],
|
content: const SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: <Widget>[
|
||||||
|
Text('このアプリでは、以下の目的で位置情報を使用します:'),
|
||||||
|
Text(
|
||||||
|
'• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'),
|
||||||
|
Text('• 移動履歴の記録(バックグラウンドでも継続)'),
|
||||||
|
Text('• 現在地周辺の情報表示'),
|
||||||
|
Text('\nバックグラウンドでも位置情報を継続的に取得します。'),
|
||||||
|
Text('これにより、バッテリーの消費が増加する可能性があります。'),
|
||||||
|
Text('同意しない場合には、アプリは終了します。'),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: const Text('同意しない'),
|
||||||
|
onPressed: () => Get.back(result: false),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: const Text('同意する'),
|
||||||
|
onPressed: () => Get.back(result: true),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
barrierDismissible: false,
|
||||||
TextButton(
|
);
|
||||||
child: const Text('同意しない'),
|
return result ?? false;
|
||||||
onPressed: () => Get.back(result: false),
|
}catch(e){
|
||||||
),
|
print('Dialog error: $e');
|
||||||
TextButton(
|
return false;
|
||||||
child: const Text('同意する'),
|
}
|
||||||
onPressed: () => Get.back(result: true),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
barrierDismissible: false,
|
|
||||||
) ?? false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void showPermissionDeniedDialog(String title,String message) {
|
static void showPermissionDeniedDialog(String title,String message) {
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import 'package:get/get.dart';
|
|||||||
import 'package:gifunavi/pages/team/member_controller.dart';
|
import 'package:gifunavi/pages/team/member_controller.dart';
|
||||||
import 'package:gifunavi/services/api_service.dart';
|
import 'package:gifunavi/services/api_service.dart';
|
||||||
|
|
||||||
|
import '../index/index_controller.dart';
|
||||||
|
|
||||||
class MemberBinding extends Bindings {
|
class MemberBinding extends Bindings {
|
||||||
@override
|
@override
|
||||||
void dependencies() {
|
void dependencies() {
|
||||||
|
|||||||
@ -2,10 +2,15 @@ import 'package:get/get.dart';
|
|||||||
import 'package:gifunavi/pages/team/team_controller.dart';
|
import 'package:gifunavi/pages/team/team_controller.dart';
|
||||||
import 'package:gifunavi/services/api_service.dart';
|
import 'package:gifunavi/services/api_service.dart';
|
||||||
|
|
||||||
|
//import '../entry/entry_controller.dart';
|
||||||
|
import '../index/index_controller.dart';
|
||||||
|
|
||||||
class TeamBinding extends Bindings {
|
class TeamBinding extends Bindings {
|
||||||
@override
|
@override
|
||||||
void dependencies() {
|
void dependencies() {
|
||||||
Get.lazyPut<ApiService>(() => ApiService());
|
Get.lazyPut<ApiService>(() => ApiService());
|
||||||
Get.lazyPut<TeamController>(() => TeamController());
|
Get.lazyPut<TeamController>(() => TeamController(
|
||||||
|
apiService:Get.find<ApiService>())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -15,8 +15,14 @@ import 'package:gifunavi/model/event.dart';
|
|||||||
|
|
||||||
|
|
||||||
class TeamController extends GetxController {
|
class TeamController extends GetxController {
|
||||||
late final ApiService _apiService;
|
final ApiService _apiService;
|
||||||
late final EntryController _entryController;
|
//final EntryController _entryController;
|
||||||
|
|
||||||
|
TeamController({
|
||||||
|
required ApiService apiService,
|
||||||
|
//required EntryController entryController,
|
||||||
|
}) : _apiService = apiService;
|
||||||
|
//_entryController = entryController;
|
||||||
|
|
||||||
final teams = <Team>[].obs;
|
final teams = <Team>[].obs;
|
||||||
final categories = <NewCategory>[].obs;
|
final categories = <NewCategory>[].obs;
|
||||||
@ -35,12 +41,12 @@ class TeamController extends GetxController {
|
|||||||
void onInit() async {
|
void onInit() async {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
try {
|
try {
|
||||||
_apiService = Get.find<ApiService>();
|
//_apiService = Get.find<ApiService>();
|
||||||
|
|
||||||
if (!Get.isRegistered<EntryController>()) {
|
//if (!Get.isRegistered<EntryController>()) {
|
||||||
Get.put(EntryController());
|
// Get.put(EntryController());
|
||||||
}
|
//}
|
||||||
_entryController = Get.find<EntryController>();
|
//_entryController = Get.find<EntryController>();
|
||||||
|
|
||||||
await loadInitialData();
|
await loadInitialData();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:gifunavi/model/team.dart';
|
|||||||
import 'package:gifunavi/model/category.dart';
|
import 'package:gifunavi/model/category.dart';
|
||||||
import 'package:gifunavi/model/user.dart';
|
import 'package:gifunavi/model/user.dart';
|
||||||
import 'package:gifunavi/pages/index/index_controller.dart';
|
import 'package:gifunavi/pages/index/index_controller.dart';
|
||||||
|
import '../routes/app_pages.dart';
|
||||||
import '../utils/const.dart';
|
import '../utils/const.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
@ -22,11 +23,15 @@ class ApiService extends GetxService{
|
|||||||
|
|
||||||
Future<ApiService> init() async {
|
Future<ApiService> init() async {
|
||||||
try {
|
try {
|
||||||
|
//if (!Get.isRegistered<IndexController>()) {
|
||||||
|
// Get.put(IndexController(apiService: Get.find<ApiService>()));
|
||||||
|
//}
|
||||||
|
|
||||||
// ここで必要な初期化処理を行う
|
// ここで必要な初期化処理を行う
|
||||||
serverUrl = ConstValues.currentServer();
|
serverUrl = ConstValues.currentServer();
|
||||||
baseUrl = '$serverUrl/api';
|
baseUrl = '$serverUrl/api';
|
||||||
//await Future.delayed(Duration(seconds: 2)); // 仮の遅延(実際の初期化処理に置き換えてください)
|
//await Future.delayed(Duration(seconds: 2)); // 仮の遅延(実際の初期化処理に置き換えてください)
|
||||||
print('ApiService initialized successfully');
|
print('ApiService initialized successfully . baseUrl = $baseUrl');
|
||||||
return this;
|
return this;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
print('Error in ApiService initialization: $e');
|
print('Error in ApiService initialization: $e');
|
||||||
@ -47,11 +52,13 @@ class ApiService extends GetxService{
|
|||||||
注意点として、API のレスポンス形式が変更された場合や、新しいフィールドが追加された場合は、このメソッドも更新する必要があります。そのため、API の変更とクライアントサイドのコードの同期を保つことが重要です。
|
注意点として、API のレスポンス形式が変更された場合や、新しいフィールドが追加された場合は、このメソッドも更新する必要があります。そのため、API の変更とクライアントサイドのコードの同期を保つことが重要です。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String getToken()
|
Future<String> getToken2 () async
|
||||||
{
|
{
|
||||||
// IndexControllerの初期化を待つ
|
// IndexControllerの初期化を待つ
|
||||||
|
if (!Get.isRegistered<IndexController>()) {
|
||||||
|
Get.find<IndexController>();
|
||||||
|
}
|
||||||
final indexController = Get.find<IndexController>();
|
final indexController = Get.find<IndexController>();
|
||||||
|
|
||||||
if (indexController.currentUser.isNotEmpty) {
|
if (indexController.currentUser.isNotEmpty) {
|
||||||
token = indexController.currentUser[0]['token'] ?? '';
|
token = indexController.currentUser[0]['token'] ?? '';
|
||||||
print("Get token = $token");
|
print("Get token = $token");
|
||||||
@ -61,11 +68,61 @@ class ApiService extends GetxService{
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getToken()
|
||||||
|
{
|
||||||
|
// IndexControllerの初期化を待つ
|
||||||
|
if (!Get.isRegistered<IndexController>()) {
|
||||||
|
Get.find<IndexController>();
|
||||||
|
}
|
||||||
|
final indexController = Get.find<IndexController>();
|
||||||
|
if (indexController.currentUser.isNotEmpty) {
|
||||||
|
token = indexController.currentUser[0]['token'] ?? '';
|
||||||
|
print("Get token = $token");
|
||||||
|
}else{
|
||||||
|
token = "";
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> _handleRequest(Future<http.Response> Function() request) async {
|
||||||
|
try {
|
||||||
|
final response = await request();
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return json.decode(utf8.decode(response.bodyBytes));
|
||||||
|
} else if (response.statusCode == 401) {
|
||||||
|
await _handleUnauthorized();
|
||||||
|
throw Exception('Authentication failed. Please log in again.');
|
||||||
|
} else {
|
||||||
|
throw Exception('Request failed with status: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('API request error: $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleUnauthorized() async {
|
||||||
|
// トークンをクリアし、ユーザーをログアウトさせる
|
||||||
|
final indexController = Get.find<IndexController>();
|
||||||
|
await indexController.logout();
|
||||||
|
Get.offAllNamed(AppPages.LOGIN);
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<Team>> getTeams() async {
|
Future<List<Team>> getTeams() async {
|
||||||
|
final token = await getToken2();
|
||||||
|
return _handleRequest(() => http.get(
|
||||||
|
Uri.parse('$baseUrl/teams/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
)).then((data) => (data as List).map((json) => Team.fromJson(json)).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future<List<Team>> getTeams_old() async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
final token = await getToken2();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
Uri.parse('$baseUrl/teams/'),
|
Uri.parse('$baseUrl/teams/'),
|
||||||
headers: {'Authorization': 'Token $token',"Content-Type": "application/json; charset=UTF-8"},
|
headers: {'Authorization': 'Token $token',"Content-Type": "application/json; charset=UTF-8"},
|
||||||
@ -136,6 +193,14 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<NewCategory> getZekkenNumber(int categoryId) async {
|
Future<NewCategory> getZekkenNumber(int categoryId) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
return _handleRequest(() => http.post(
|
||||||
|
Uri.parse('$baseUrl/categories-viewset/$categoryId/get_zekken_number/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
)).then((data) => NewCategory.fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<NewCategory> getZekkenNumber_old(int categoryId) async {
|
||||||
try {
|
try {
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$baseUrl/categories-viewset/$categoryId/get_zekken_number/'),
|
Uri.parse('$baseUrl/categories-viewset/$categoryId/get_zekken_number/'),
|
||||||
@ -157,7 +222,7 @@ class ApiService extends GetxService{
|
|||||||
|
|
||||||
Future<User> getCurrentUser() async {
|
Future<User> getCurrentUser() async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
final token = getToken();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
@ -174,6 +239,13 @@ class ApiService extends GetxService{
|
|||||||
//_printDataComparison(jsonData, User);
|
//_printDataComparison(jsonData, User);
|
||||||
|
|
||||||
return User.fromJson(jsonData);
|
return User.fromJson(jsonData);
|
||||||
|
} else if (response.statusCode == 401) {
|
||||||
|
// トークンが無効な場合、ログアウトしてログインページにリダイレクト
|
||||||
|
await Get.find<IndexController>().logout();
|
||||||
|
//indexController.logout();
|
||||||
|
Get.offAllNamed(AppPages.LOGIN);
|
||||||
|
throw Exception('Authentication failed. Please log in again.');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to get current user. Status code: ${response.statusCode}');
|
throw Exception('Failed to get current user. Status code: ${response.statusCode}');
|
||||||
}
|
}
|
||||||
@ -244,6 +316,15 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Team> createTeam(String teamName, int categoryId) async {
|
Future<Team> createTeam(String teamName, int categoryId) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
return _handleRequest(() => http.post(
|
||||||
|
Uri.parse('$baseUrl/teams/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
body: json.encode({'team_name': teamName, 'category': categoryId}),
|
||||||
|
)).then((data) => Team.fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Team> createTeam_old(String teamName, int categoryId) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -268,6 +349,15 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Team> updateTeam(int teamId, String teamName, int categoryId) async {
|
Future<Team> updateTeam(int teamId, String teamName, int categoryId) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
return _handleRequest(() => http.put(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
body: json.encode({'team_name': teamName, 'category': categoryId}),
|
||||||
|
)).then((data) => Team.fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Team> updateTeam_old(int teamId, String teamName, int categoryId) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -293,6 +383,14 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteTeam(int teamId) async {
|
Future<void> deleteTeam(int teamId) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
await _handleRequest(() => http.delete(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteTeamold_(int teamId) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -311,6 +409,14 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<User>> getTeamMembers(int teamId) async {
|
Future<List<User>> getTeamMembers(int teamId) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
return _handleRequest(() => http.get(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/members/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
)).then((data) => (data as List).map((json) => User.fromJson(json)).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<User>> getTeamMembers_old(int teamId) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -330,7 +436,23 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<User> createTeamMember(int teamId, String? email, String? firstname, String? lastname, DateTime? dateOfBirth,bool? female) async {
|
Future<User> createTeamMember(int teamId, String? email, String? firstname, String? lastname, DateTime? dateOfBirth, bool? female) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
String? formattedDateOfBirth = dateOfBirth != null ? DateFormat('yyyy-MM-dd').format(dateOfBirth) : null;
|
||||||
|
return _handleRequest(() => http.post(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/members/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
body: json.encode({
|
||||||
|
'email': email,
|
||||||
|
'firstname': firstname,
|
||||||
|
'lastname': lastname,
|
||||||
|
'date_of_birth': formattedDateOfBirth,
|
||||||
|
'female': female,
|
||||||
|
}),
|
||||||
|
)).then((data) => User.fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<User> createTeamMember_old(int teamId, String? email, String? firstname, String? lastname, DateTime? dateOfBirth,bool? female) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -370,7 +492,22 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<User> updateTeamMember(int teamId,int? memberId, String firstname, String lastname, DateTime? dateOfBirth,bool? female) async {
|
Future<User> updateTeamMember(int teamId, int? memberId, String firstname, String lastname, DateTime? dateOfBirth, bool? female) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
String? formattedDateOfBirth = dateOfBirth != null ? DateFormat('yyyy-MM-dd').format(dateOfBirth) : null;
|
||||||
|
return _handleRequest(() => http.put(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/members/$memberId/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
body: json.encode({
|
||||||
|
'firstname': firstname,
|
||||||
|
'lastname': lastname,
|
||||||
|
'date_of_birth': formattedDateOfBirth,
|
||||||
|
'female': female,
|
||||||
|
}),
|
||||||
|
)).then((data) => User.fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<User> updateTeamMember_old(int teamId,int? memberId, String firstname, String lastname, DateTime? dateOfBirth,bool? female) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -401,7 +538,15 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteTeamMember(int teamId,int memberId) async {
|
Future<void> deleteTeamMember(int teamId, int memberId) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
await _handleRequest(() => http.delete(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/members/$memberId/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteTeamMember_old(int teamId,int memberId) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -442,6 +587,14 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Entry>> getEntries() async {
|
Future<List<Entry>> getEntries() async {
|
||||||
|
final token = await getToken2();
|
||||||
|
return _handleRequest(() => http.get(
|
||||||
|
Uri.parse('$baseUrl/entry/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
)).then((data) => (data as List).map((json) => Entry.fromJson(json)).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Entry>> getEntries_old() async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -500,7 +653,23 @@ class ApiService extends GetxService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Entry> createEntry(int teamId, int eventId, int categoryId, DateTime date,String zekkenNumber) async {
|
Future<Entry> createEntry(int teamId, int eventId, int categoryId, DateTime date, String zekkenNumber) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
String formattedDate = DateFormat('yyyy-MM-dd').format(date);
|
||||||
|
return _handleRequest(() => http.post(
|
||||||
|
Uri.parse('$baseUrl/entry/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
body: json.encode({
|
||||||
|
'team': teamId,
|
||||||
|
'event': eventId,
|
||||||
|
'category': categoryId,
|
||||||
|
'date': formattedDate,
|
||||||
|
'zekken_number': zekkenNumber,
|
||||||
|
}),
|
||||||
|
)).then((data) => Entry.fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Entry> createEntry_old(int teamId, int eventId, int categoryId, DateTime date,String zekkenNumber) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -529,11 +698,28 @@ class ApiService extends GetxService{
|
|||||||
} else {
|
} else {
|
||||||
final decodedResponse = utf8.decode(response.bodyBytes);
|
final decodedResponse = utf8.decode(response.bodyBytes);
|
||||||
print("decodedResponse = $decodedResponse");
|
print("decodedResponse = $decodedResponse");
|
||||||
throw Exception('Failed to create entry');
|
final errorInfo = json.decode(decodedResponse);
|
||||||
|
throw Exception(errorInfo['error']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateUserInfo(int userId, Entry entry) async {
|
Future<void> updateUserInfo(int userId, Entry entry) async {
|
||||||
|
final token = await getToken2();
|
||||||
|
String formattedDate = DateFormat('yyyy-MM-dd').format(entry.date!);
|
||||||
|
await _handleRequest(() => http.put(
|
||||||
|
Uri.parse('$baseUrl/userinfo/$userId/'),
|
||||||
|
headers: {'Authorization': 'Token $token', "Content-Type": "application/json; charset=UTF-8"},
|
||||||
|
body: json.encode({
|
||||||
|
'zekken_number': entry.zekkenNumber,
|
||||||
|
'event_code': entry.event.eventName,
|
||||||
|
'group': entry.team.category.categoryName,
|
||||||
|
'team_name': entry.team.teamName,
|
||||||
|
'date': formattedDate,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateUserInfo_old(int userId, Entry entry) async {
|
||||||
init();
|
init();
|
||||||
getToken();
|
getToken();
|
||||||
|
|
||||||
@ -598,7 +784,10 @@ class ApiService extends GetxService{
|
|||||||
final decodedResponse = utf8.decode(response.bodyBytes);
|
final decodedResponse = utf8.decode(response.bodyBytes);
|
||||||
final blk = json.decode(decodedResponse);
|
final blk = json.decode(decodedResponse);
|
||||||
|
|
||||||
throw Exception('Failed to update entry');
|
Map<String, dynamic> error_dict = blk[0]['error'];
|
||||||
|
String ? error_message = error_dict['non_field_errors'][0].string;
|
||||||
|
|
||||||
|
throw Exception(error_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,8 +51,8 @@ class ExternalService {
|
|||||||
//print("--- _team : ${_team}-----");
|
//print("--- _team : ${_team}-----");
|
||||||
String eventCode = indexController.currentUser[0]["user"]["event_code"];
|
String eventCode = indexController.currentUser[0]["user"]["event_code"];
|
||||||
|
|
||||||
if (indexController.connectionStatusName.value != "wifi" &&
|
if (indexController.connectionStatusName.value.toLowerCase() != "wifi" &&
|
||||||
indexController.connectionStatusName.value != "mobile") {
|
indexController.connectionStatusName.value.toLowerCase() != "mobile") {
|
||||||
debugPrint("== No network ==");
|
debugPrint("== No network ==");
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
Rog rog = Rog(
|
Rog rog = Rog(
|
||||||
@ -114,8 +114,8 @@ class ExternalService {
|
|||||||
|
|
||||||
//int teamId = indexController.teamController.teams[0];
|
//int teamId = indexController.teamController.teams[0];
|
||||||
|
|
||||||
if (indexController.connectionStatusName.value != "wifi" &&
|
if (indexController.connectionStatusName.value.toLowerCase() != "wifi" &&
|
||||||
indexController.connectionStatusName.value != "mobile") {
|
indexController.connectionStatusName.value.toLowerCase() != "mobile") {
|
||||||
debugPrint("== checkin without network ==");
|
debugPrint("== checkin without network ==");
|
||||||
|
|
||||||
DatabaseHelper db = DatabaseHelper.instance;
|
DatabaseHelper db = DatabaseHelper.instance;
|
||||||
@ -326,8 +326,8 @@ class ExternalService {
|
|||||||
//print("--- _team : ${_team}-----");
|
//print("--- _team : ${_team}-----");
|
||||||
String eventCode = indexController.currentUser[0]["user"]["event_code"];
|
String eventCode = indexController.currentUser[0]["user"]["event_code"];
|
||||||
|
|
||||||
if (indexController.connectionStatusName.value != "wifi" &&
|
if (indexController.connectionStatusName.value.toLowerCase() != "wifi" &&
|
||||||
indexController.connectionStatusName.value != "mobile") {
|
indexController.connectionStatusName.value.toLowerCase() != "mobile") {
|
||||||
return Future.value(false);
|
return Future.value(false);
|
||||||
} else {
|
} else {
|
||||||
String serverUrl = ConstValues.currentServer();
|
String serverUrl = ConstValues.currentServer();
|
||||||
@ -376,8 +376,8 @@ class ExternalService {
|
|||||||
|
|
||||||
List<GpsData> gpsDataList = [];
|
List<GpsData> gpsDataList = [];
|
||||||
|
|
||||||
if (indexController.connectionStatusName.value != "wifi" &&
|
if (indexController.connectionStatusName.value.toLowerCase() != "wifi" &&
|
||||||
indexController.connectionStatusName.value != "mobile") {
|
indexController.connectionStatusName.value.toLowerCase() != "mobile") {
|
||||||
return Future.value(false);
|
return Future.value(false);
|
||||||
} else {
|
} else {
|
||||||
// Step 1: Fetch data from the local database
|
// Step 1: Fetch data from the local database
|
||||||
|
|||||||
@ -13,6 +13,11 @@ class DatabaseHelper {
|
|||||||
static Database? _database;
|
static Database? _database;
|
||||||
Future<Database> get database async => _database ??= await _initDatabase();
|
Future<Database> get database async => _database ??= await _initDatabase();
|
||||||
|
|
||||||
|
// データベース初期化:
|
||||||
|
//
|
||||||
|
// シングルトンパターンを使用してDatabaseHelperのインスタンスを管理しています。
|
||||||
|
// _initDatabase()メソッドでデータベースを初期化し、必要なテーブルを作成します。
|
||||||
|
//
|
||||||
Future<Database> _initDatabase() async {
|
Future<Database> _initDatabase() async {
|
||||||
Directory documentDirectory = await getApplicationDocumentsDirectory();
|
Directory documentDirectory = await getApplicationDocumentsDirectory();
|
||||||
String path = join(documentDirectory.path, 'rog.db');
|
String path = join(documentDirectory.path, 'rog.db');
|
||||||
@ -30,7 +35,10 @@ class DatabaseHelper {
|
|||||||
onCreate: _onCreate);
|
onCreate: _onCreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DBを初期化する際に、必要なテーブルを作成します。
|
||||||
|
//
|
||||||
Future _onCreate(Database db, int version) async {
|
Future _onCreate(Database db, int version) async {
|
||||||
|
// destinationテーブル: 目的地の情報を保存(位置、名前、住所、連絡先情報など)。
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE destination(
|
CREATE TABLE destination(
|
||||||
location_id INTEGER PRIMARY KEY,
|
location_id INTEGER PRIMARY KEY,
|
||||||
@ -63,6 +71,7 @@ class DatabaseHelper {
|
|||||||
)
|
)
|
||||||
''');
|
''');
|
||||||
|
|
||||||
|
// rogainingテーブル: ロゲイニング(orienteering的なアクティビティ)の記録を保存。
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE rogaining(
|
CREATE TABLE rogaining(
|
||||||
rog_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
rog_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -76,6 +85,7 @@ class DatabaseHelper {
|
|||||||
)
|
)
|
||||||
''');
|
''');
|
||||||
|
|
||||||
|
// rogテーブル: ロゲイニングのチェックポイント情報を保存。
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE rog(
|
CREATE TABLE rog(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -138,6 +148,22 @@ class DatabaseHelper {
|
|||||||
await db.delete('rog');
|
await db.delete('rog');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> deleteAllRogainingExceptToday() async {
|
||||||
|
Database db = await instance.database;
|
||||||
|
|
||||||
|
// 今日の開始時刻をエポックミリ秒で取得
|
||||||
|
final now = DateTime.now();
|
||||||
|
final startOfDay = DateTime(now.year, now.month, now.day).millisecondsSinceEpoch;
|
||||||
|
|
||||||
|
// 今日チェックインしたもの以外を削除
|
||||||
|
await db.delete(
|
||||||
|
'rog',
|
||||||
|
where: 'checkintime < ?',
|
||||||
|
whereArgs: [startOfDay]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<bool> isRogAlreadyAvailable(int id) async {
|
Future<bool> isRogAlreadyAvailable(int id) async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
var rog = await db.query('rog', where: "id = $id");
|
var rog = await db.query('rog', where: "id = $id");
|
||||||
@ -229,6 +255,27 @@ class DatabaseHelper {
|
|||||||
await db.delete('destination');
|
await db.delete('destination');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> deleteAllDestinationsExceptTodayCheckins() async {
|
||||||
|
Database db = await instance.database;
|
||||||
|
|
||||||
|
// 今日の開始時刻をエポックからのミリ秒で取得
|
||||||
|
final now = DateTime.now();
|
||||||
|
final startOfDay = DateTime(now.year, now.month, now.day).millisecondsSinceEpoch;
|
||||||
|
|
||||||
|
// 今日チェックインされ、buy_pointを持つ目的地を除いて全て削除
|
||||||
|
await db.rawDelete('''
|
||||||
|
DELETE FROM destination
|
||||||
|
WHERE location_id NOT IN (
|
||||||
|
SELECT d.location_id
|
||||||
|
FROM destination d
|
||||||
|
JOIN rog r ON d.location_id = r.cp_number
|
||||||
|
WHERE date(r.checkintime / 1000, 'unixepoch', 'localtime') = date('now', 'localtime')
|
||||||
|
AND d.buy_point > 0
|
||||||
|
AND d.checkedin = 1
|
||||||
|
)
|
||||||
|
''', [startOfDay]);
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> isAlreadyAvailable(int locationId) async {
|
Future<bool> isAlreadyAvailable(int locationId) async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
var dest =
|
var dest =
|
||||||
|
|||||||
@ -129,20 +129,25 @@ class LocationController extends GetxController {
|
|||||||
|
|
||||||
// 現在位置を調整するメソッドを追加
|
// 現在位置を調整するメソッドを追加
|
||||||
LatLng? adjustCurrentLocation(Position? position) {
|
LatLng? adjustCurrentLocation(Position? position) {
|
||||||
if (position == null) {
|
if (position == null) { // positionがnullなら、lastValidLocationを使用する。
|
||||||
if( lastValidLocation!=null ) {
|
if( lastValidLocation!=null ) {
|
||||||
|
debugPrint("== 現在位置なし。最後の位置を使用 ==");
|
||||||
//debugPrint("=== adjustCurrentLocation (Position:Null and using LastValidLocation ${lastValidLocation})===");
|
//debugPrint("=== adjustCurrentLocation (Position:Null and using LastValidLocation ${lastValidLocation})===");
|
||||||
return LatLng(lastValidLocation!.latitude, lastValidLocation!.longitude);
|
return LatLng(lastValidLocation!.latitude, lastValidLocation!.longitude);
|
||||||
}else {
|
}else {
|
||||||
print("=== adjustCurrentLocation (Position:Null and No LastValidLocation ... )===");
|
debugPrint("== 現在位置なし。最後の位置も無し ==");
|
||||||
|
//print("=== adjustCurrentLocation (Position:Null and No LastValidLocation ... )===");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
//return lastValidLocation ?? LatLng(0, 0);
|
//return lastValidLocation ?? LatLng(0, 0);
|
||||||
}
|
}
|
||||||
final signalStrength = getGpsSignalStrength(position);
|
final signalStrength = getGpsSignalStrength(position);
|
||||||
if (signalStrength == 'high' || signalStrength == 'medium') {
|
if (signalStrength == 'high' || signalStrength == 'medium') {
|
||||||
|
debugPrint("== 信号強度 ${signalStrength} ==> 最新位置を使用 ==");
|
||||||
//debugPrint("=== adjustCurrentLocation (Position:Get and return Valid location:${position} ... )===");
|
//debugPrint("=== adjustCurrentLocation (Position:Get and return Valid location:${position} ... )===");
|
||||||
lastValidLocation = LatLng(position.latitude, position.longitude);
|
lastValidLocation = LatLng(position.latitude, position.longitude);
|
||||||
|
}else{
|
||||||
|
debugPrint("== 信号強度 ${signalStrength} ==> 最後の位置を使用 ==");
|
||||||
}
|
}
|
||||||
return lastValidLocation ?? LatLng(lastValidLocation!.latitude, lastValidLocation!.longitude);
|
return lastValidLocation ?? LatLng(lastValidLocation!.latitude, lastValidLocation!.longitude);
|
||||||
}
|
}
|
||||||
@ -169,10 +174,39 @@ class LocationController extends GetxController {
|
|||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
// Start listening to location updates when the controller is initialized
|
// Start listening to location updates when the controller is initialized
|
||||||
startPositionStream();
|
_initLocationService();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initLocationService() async {
|
||||||
|
try {
|
||||||
|
bool serviceEnabled;
|
||||||
|
LocationPermission permission;
|
||||||
|
|
||||||
|
serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||||
|
if (!serviceEnabled) {
|
||||||
|
return Future.error('Location services are disabled.');
|
||||||
|
}
|
||||||
|
|
||||||
|
permission = await Geolocator.checkPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
permission = await Geolocator.requestPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
return Future.error('Location permissions are denied');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permission == LocationPermission.deniedForever) {
|
||||||
|
return Future.error(
|
||||||
|
'Location permissions are permanently denied, we cannot request permissions.');
|
||||||
|
}
|
||||||
|
|
||||||
|
startPositionStream();
|
||||||
|
} catch( e ){
|
||||||
|
print('Error initializing location service: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 位置情報のストリームを開始するメソッドです。
|
// 位置情報のストリームを開始するメソッドです。
|
||||||
// 位置情報サービスが有効か確認し、無効な場合はダイアログを表示します。
|
// 位置情報サービスが有効か確認し、無効な場合はダイアログを表示します。
|
||||||
// 位置情報の権限を確認し、必要な権限がない場合は権限をリクエストします。
|
// 位置情報の権限を確認し、必要な権限がない場合は権限をリクエストします。
|
||||||
@ -185,7 +219,26 @@ class LocationController extends GetxController {
|
|||||||
// 2024-4-8 Akira : See 2809
|
// 2024-4-8 Akira : See 2809
|
||||||
// stopPositionStreamメソッドを追加して、既存のストリームをキャンセルするようにしました。また、ストリームが完了したらnullに設定し、エラー発生時にストリームをキャンセルするようにしました。
|
// stopPositionStreamメソッドを追加して、既存のストリームをキャンセルするようにしました。また、ストリームが完了したらnullに設定し、エラー発生時にストリームをキャンセルするようにしました。
|
||||||
//
|
//
|
||||||
void startPositionStream() async {
|
void startPositionStream() {
|
||||||
|
positionStream = Geolocator.getPositionStream(
|
||||||
|
locationSettings: const LocationSettings(
|
||||||
|
accuracy: LocationAccuracy.high,
|
||||||
|
distanceFilter: 5, //10, 10mから5mに変更
|
||||||
|
),
|
||||||
|
).listen((Position position) {
|
||||||
|
currentPosition.value = position;
|
||||||
|
//debugPrint("== startPositionStream: ${position} ==");
|
||||||
|
locationMarkerPositionStreamController.add(
|
||||||
|
LocationMarkerPosition(
|
||||||
|
latitude: position.latitude,
|
||||||
|
longitude: position.longitude,
|
||||||
|
accuracy: position.accuracy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void startPositionStream_old() async {
|
||||||
// Check for location service and permissions before starting the stream
|
// Check for location service and permissions before starting the stream
|
||||||
// 位置情報サービスの有効性をチェックし、無効な場合はエラーハンドリングを行います。
|
// 位置情報サービスの有効性をチェックし、無効な場合はエラーハンドリングを行います。
|
||||||
//
|
//
|
||||||
|
|||||||
89
lib/utils/memory_monitor.dart
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
void _performMemoryCleanup() {
|
||||||
|
//debugPrint('Performing memory cleanup');
|
||||||
|
|
||||||
|
// キャッシュのクリア
|
||||||
|
Get.deleteAll(); // GetXを使用している場合、すべてのコントローラをクリア
|
||||||
|
imageCache.clear(); // 画像キャッシュをクリア
|
||||||
|
imageCache.clearLiveImages(); // 使用中の画像キャッシュをクリア
|
||||||
|
|
||||||
|
// 大きなオブジェクトの解放
|
||||||
|
_clearLargeObjects();
|
||||||
|
|
||||||
|
// 未使用のリソースの解放
|
||||||
|
_releaseUnusedResources();
|
||||||
|
|
||||||
|
// ガベージコレクションの促進
|
||||||
|
_forceGarbageCollection();
|
||||||
|
|
||||||
|
debugPrint('Memory cleanup completed');
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearLargeObjects() {
|
||||||
|
// 大きなリストやマップをクリア
|
||||||
|
// 例: myLargeList.clear();
|
||||||
|
// 例: myLargeMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _releaseUnusedResources() {
|
||||||
|
// 使用していないストリームのクローズ
|
||||||
|
// 例: myStream?.close();
|
||||||
|
|
||||||
|
// 未使用のアニメーションコントローラーの破棄
|
||||||
|
// 例: myAnimationController?.dispose();
|
||||||
|
|
||||||
|
// テキスト編集コントローラーの破棄
|
||||||
|
// 例: myTextEditingController?.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _forceGarbageCollection() {
|
||||||
|
// Dart VMにガベージコレクションを促す
|
||||||
|
Timer(const Duration(seconds: 1), () {
|
||||||
|
//debugPrint('Forcing garbage collection');
|
||||||
|
// この呼び出しは必ずしもガベージコレクションを即座に実行するわけではありませんが、
|
||||||
|
// Dart VMにガベージコレクションの実行を強く促します。
|
||||||
|
// ignore: dead_code
|
||||||
|
bool didRun = false;
|
||||||
|
assert(() {
|
||||||
|
didRun = true;
|
||||||
|
return true;
|
||||||
|
}());
|
||||||
|
if (didRun) {
|
||||||
|
//debugPrint('Garbage collection forced in debug mode');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// メモリ使用量を監視し、必要に応じてクリーンアップを実行する関数
|
||||||
|
void startMemoryMonitoring() {
|
||||||
|
const Duration checkInterval = Duration(minutes: 5);
|
||||||
|
Timer.periodic(checkInterval, (Timer timer) {
|
||||||
|
_checkMemoryUsage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkMemoryUsage() async {
|
||||||
|
// ここでメモリ使用量をチェックするロジックを実装
|
||||||
|
// 例えば、プラットフォーム固有の方法でメモリ使用量を取得する
|
||||||
|
|
||||||
|
// 仮の閾値(実際のアプリケーションに応じて調整が必要)
|
||||||
|
const int memoryThreshold = 100 * 1024 * 1024; // 100 MB
|
||||||
|
|
||||||
|
// 仮のメモリ使用量チェック(実際の実装に置き換える必要があります)
|
||||||
|
int currentMemoryUsage = await _getCurrentMemoryUsage();
|
||||||
|
|
||||||
|
if (currentMemoryUsage > memoryThreshold) {
|
||||||
|
debugPrint('High memory usage detected: $currentMemoryUsage bytes');
|
||||||
|
_performMemoryCleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> _getCurrentMemoryUsage() async {
|
||||||
|
// プラットフォーム固有のメモリ使用量取得ロジックを実装
|
||||||
|
// この例では仮の値を返しています
|
||||||
|
return 150 * 1024 * 1024; // 仮に150MBとする
|
||||||
|
}
|
||||||
@ -175,7 +175,12 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
|||||||
destinationController.currentLat, destinationController.currentLon),
|
destinationController.currentLat, destinationController.currentLon),
|
||||||
LatLng(cdest.lat!, cdest.lon!));
|
LatLng(cdest.lat!, cdest.lon!));
|
||||||
|
|
||||||
// Check conditions to show confirmation dialog
|
// スタートボタン:
|
||||||
|
// 表示条件:
|
||||||
|
// 1. 目的地のCP番号が-1または0の場合
|
||||||
|
// 2. ロゲイニングがまだ開始されていない場合(destinationController.isInRog.value == false)
|
||||||
|
// 3. 最後のゴールから10時間以上経過している場合
|
||||||
|
//
|
||||||
if (destinationController.isInRog.value == false &&
|
if (destinationController.isInRog.value == false &&
|
||||||
(destinationController.distanceToStart() <= 100 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
|
(destinationController.distanceToStart() <= 100 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
|
||||||
(destination.cp == -1 || destination.cp == 0 ) &&
|
(destination.cp == -1 || destination.cp == 0 ) &&
|
||||||
@ -294,7 +299,15 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
|||||||
//print("counted ${destinationController.rogainingCounted.value}");
|
//print("counted ${destinationController.rogainingCounted.value}");
|
||||||
|
|
||||||
|
|
||||||
|
// ゴールボタン:
|
||||||
|
// 表示条件:
|
||||||
|
// 1. 目的地のCP番号が0、-2、または-1の場合
|
||||||
|
// 2. ロゲイニングが開始されている場合(destinationController.rogainingCounted.value == true)
|
||||||
|
// 3. スタート地点から500m以内にいる場合、または GPS信号が弱い場合
|
||||||
|
// 4. ゴール準備完了フラグが立っている場合(DestinationController.ready_for_goal == true)
|
||||||
|
//
|
||||||
}else if (destinationController.rogainingCounted.value == true &&
|
}else if (destinationController.rogainingCounted.value == true &&
|
||||||
|
destinationController.isInRog.value == true &&
|
||||||
// destinationController.distanceToStart() <= 500 && ... GPS信号が弱い時でもOKとする。
|
// destinationController.distanceToStart() <= 500 && ... GPS信号が弱い時でもOKとする。
|
||||||
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) &&
|
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) &&
|
||||||
(destination.cp == 0 || destination.cp == -2 || destination.cp == -1) &&
|
(destination.cp == 0 || destination.cp == -2 || destination.cp == -1) &&
|
||||||
@ -334,7 +347,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
|||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
child: Text(
|
child: Text(
|
||||||
"finish_rogaining".tr,
|
"finish_rogaining".tr, // ロゲゴール
|
||||||
style: const TextStyle(color: Colors.white),
|
style: const TextStyle(color: Colors.white),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -353,6 +366,9 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
|||||||
destinationController.isCheckingIn.value = true; // ここを追加
|
destinationController.isCheckingIn.value = true; // ここを追加
|
||||||
Get.back();
|
Get.back();
|
||||||
Get.back();
|
Get.back();
|
||||||
|
if(destinationController.isInRog.value==false && destination.cp == -1){
|
||||||
|
destinationController.rogainingCounted.value = false;
|
||||||
|
}
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
await destinationController.callforCheckin(destination);
|
await destinationController.callforCheckin(destination);
|
||||||
destinationController.isCheckingIn.value = false;
|
destinationController.isCheckingIn.value = false;
|
||||||
@ -371,8 +387,8 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
|||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
destination.cp == -1 &&
|
destination.cp == -1 &&
|
||||||
destinationController.isInRog.value == false &&
|
destinationController.isInRog.value == false //&&
|
||||||
destinationController.rogainingCounted.value == false
|
//destinationController.rogainingCounted.value == false
|
||||||
? "ロゲ開始"
|
? "ロゲ開始"
|
||||||
: destinationController.isInRog.value == true &&
|
: destinationController.isInRog.value == true &&
|
||||||
destination.cp == -1
|
destination.cp == -1
|
||||||
|
|||||||
@ -151,26 +151,23 @@ class _GameStateWidgetState extends State<GameStateWidget> {
|
|||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: StreamBuilder<List<Destination>>(
|
child: StreamBuilder<List<Destination>>(
|
||||||
stream: dbService.destinationUpdatesStream,
|
stream: dbService.destinationUpdatesStream,
|
||||||
|
initialData: const [], // 初期値を設定
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState ==
|
if (snapshot.hasError) {
|
||||||
ConnectionState.waiting) {
|
print('Error: ${snapshot.error}');
|
||||||
return const CircularProgressIndicator();
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return LocationVisitedWidget(
|
|
||||||
count: 0,
|
|
||||||
minimized: !isExpanded,
|
|
||||||
);
|
|
||||||
} else if (snapshot.hasData) {
|
|
||||||
return LocationVisitedWidget(
|
|
||||||
count: snapshot.data!.length,
|
|
||||||
minimized: !isExpanded,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return LocationVisitedWidget(
|
return LocationVisitedWidget(
|
||||||
count: 0,
|
count: 0,
|
||||||
minimized: !isExpanded,
|
minimized: !isExpanded,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// データがある場合はそのデータを使用し、ない場合は空のリストを使用
|
||||||
|
final destinations = snapshot.data ?? [];
|
||||||
|
|
||||||
|
return LocationVisitedWidget(
|
||||||
|
count: destinations.length,
|
||||||
|
minimized: !isExpanded,
|
||||||
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -183,12 +180,12 @@ class _GameStateWidgetState extends State<GameStateWidget> {
|
|||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: Obx(() => ConnectionStatusIndicator(
|
child: Obx(() => ConnectionStatusIndicator(
|
||||||
connectionStatus: (indexController
|
connectionStatus: (indexController
|
||||||
.connectionStatusName.value ==
|
.connectionStatusName.value.toLowerCase() ==
|
||||||
"wifi" ||
|
"wifi" ||
|
||||||
indexController
|
indexController
|
||||||
.connectionStatusName.value ==
|
.connectionStatusName.value.toLowerCase() ==
|
||||||
"mobile")
|
"mobile")
|
||||||
? indexController.connectionStatusName.value ==
|
? indexController.connectionStatusName.value.toLowerCase() ==
|
||||||
"wifi"
|
"wifi"
|
||||||
? ConnectionStatus.wifi
|
? ConnectionStatus.wifi
|
||||||
: ConnectionStatus.mobile
|
: ConnectionStatus.mobile
|
||||||
|
|||||||
@ -26,7 +26,8 @@ class _HelperDialogState extends State<HelperDialog> {
|
|||||||
Text('ヘルプ'),
|
Text('ヘルプ'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Column(
|
content: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -42,11 +43,17 @@ class _HelperDialogState extends State<HelperDialog> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Text('この画面を二度と表示しない'),
|
const Flexible(
|
||||||
|
child: Text(
|
||||||
|
'この画面を二度と表示しない',
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
child: const Text('OK'),
|
child: const Text('OK'),
|
||||||
@ -68,6 +75,9 @@ Future<void> showHelperDialog(String message, String screenKey) async {
|
|||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final showHelper = prefs.getBool('helper_$screenKey') ?? true;
|
final showHelper = prefs.getBool('helper_$screenKey') ?? true;
|
||||||
if (showHelper) {
|
if (showHelper) {
|
||||||
Get.dialog(HelperDialog(message: message, screenKey: screenKey));
|
Get.dialog(
|
||||||
|
HelperDialog(message: message, screenKey: screenKey),
|
||||||
|
barrierDismissible: false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,6 +52,12 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
// 追加
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
PermissionController.checkAndRequestPermissions();
|
||||||
|
});
|
||||||
|
|
||||||
debugPrint('MapWidget: initState called');
|
debugPrint('MapWidget: initState called');
|
||||||
SettingsBinding().dependencies(); // これを追加
|
SettingsBinding().dependencies(); // これを追加
|
||||||
_startIdleTimer();
|
_startIdleTimer();
|
||||||
@ -84,6 +90,23 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
|
|||||||
mapResetController.resetIdleTimer = _resetIdleTimer;
|
mapResetController.resetIdleTimer = _resetIdleTimer;
|
||||||
Get.put(mapResetController);
|
Get.put(mapResetController);
|
||||||
|
|
||||||
|
// Add this debug subscription
|
||||||
|
subscription = locationController.locationMarkerPositionStreamController.stream.listen(
|
||||||
|
(LocationMarkerPosition? position) {
|
||||||
|
if (position != null) {
|
||||||
|
//debugPrint('Location update received: lat=${position.latitude}, lon=${position.longitude}');
|
||||||
|
} else {
|
||||||
|
debugPrint('Received null location update');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
debugPrint('Error in location stream: $error');
|
||||||
|
},
|
||||||
|
onDone: () {
|
||||||
|
debugPrint('Location stream closed');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// indexController.mapController = MapController(initCompleter: mapControllerCompleter);
|
// indexController.mapController = MapController(initCompleter: mapControllerCompleter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gifunavi/pages/permission/permission.dart';
|
import 'package:gifunavi/pages/permission/permission.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class PermissionHandlerScreen extends StatefulWidget {
|
class PermissionHandlerScreen extends StatefulWidget {
|
||||||
const PermissionHandlerScreen({super.key});
|
const PermissionHandlerScreen({super.key});
|
||||||
@ -24,8 +25,14 @@ class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('権限の確認'),
|
title: const Text('権限の確認'),
|
||||||
),
|
),
|
||||||
body: const Center(
|
body: Center(
|
||||||
child: Text('権限の確認中...'),
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Text('権限の確認中...'),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import connectivity_plus
|
import connectivity_plus
|
||||||
|
import device_info_plus
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
import geolocator_apple
|
import geolocator_apple
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
@ -17,6 +18,7 @@ import webview_flutter_wkwebview
|
|||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||||
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
|
|||||||
30
pubspec.lock
@ -185,6 +185,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.10"
|
||||||
|
device_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: device_info_plus
|
||||||
|
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.1.2"
|
||||||
|
device_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_platform_interface
|
||||||
|
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -802,7 +818,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.1"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
@ -1314,10 +1330,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
|
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.4"
|
version: "14.2.5"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1366,6 +1382,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.5.4"
|
version: "5.5.4"
|
||||||
|
win32_registry:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32_registry
|
||||||
|
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.4"
|
||||||
wkt_parser:
|
wkt_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -44,6 +44,9 @@ dependencies:
|
|||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^4.0.0
|
flutter_lints: ^4.0.0
|
||||||
|
|
||||||
|
path: ^1.8.0
|
||||||
|
device_info_plus: #^8.0.0
|
||||||
|
|
||||||
win32: ^5.5.3
|
win32: ^5.5.3
|
||||||
sqflite: ^2.0.1
|
sqflite: ^2.0.1
|
||||||
get: ^4.6.6
|
get: ^4.6.6
|
||||||
|
|||||||