Fix Android issues
This commit is contained in:
@ -44,6 +44,9 @@ import 'package:path_provider/path_provider.dart';
|
||||
// 目的地に関連する状態管理とロジックを担当するクラスです。
|
||||
//
|
||||
class DestinationController extends GetxController {
|
||||
Timer? _checkForCheckinTimer;
|
||||
final int _checkInterval = 3000; // ミリ秒単位でチェック間隔を設定
|
||||
|
||||
late LocationSettings locationSettings; // 位置情報の設定を保持する変数です。
|
||||
|
||||
//late TeamController teamController = TeamController();
|
||||
@ -1019,15 +1022,16 @@ class DestinationController extends GetxController {
|
||||
// 2024-8-24 ... 佐伯呼び出しが必要なのか?
|
||||
//
|
||||
Future<void> checkForCheckin() async {
|
||||
//print("--- Start of checkForCheckin function ---");
|
||||
dbService.updateDatabase();
|
||||
await Future.delayed(const Duration(milliseconds: 3000));
|
||||
game_started = true;
|
||||
if (!game_started) {
|
||||
game_started = true;
|
||||
dbService.updateDatabase();
|
||||
}
|
||||
|
||||
try {
|
||||
// ここで、エラー
|
||||
if( indexController.locations.isNotEmpty ) {
|
||||
indexController.locations[0].features.forEach((fs) async {
|
||||
for (var fs in indexController.locations[0].features) {
|
||||
//indexController.locations[0].features.forEach((fs) async {
|
||||
GeoJSONMultiPoint mp = fs!.geometry as GeoJSONMultiPoint;
|
||||
LatLng pt = LatLng(mp.coordinates[0][1], mp.coordinates[0][0]);
|
||||
|
||||
@ -1045,10 +1049,11 @@ class DestinationController extends GetxController {
|
||||
await startTimerLocation(fs, distFs);
|
||||
// Note: You cannot break out of forEach. If you need to stop processing, you might have to reconsider using forEach.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (gps_push_started == false) {
|
||||
unawaited(pushGPStoServer());
|
||||
pushGPStoServer();
|
||||
//unawaited(pushGPStoServer());
|
||||
}
|
||||
}
|
||||
//print("--- 123 ---- $skip_gps----");
|
||||
@ -1071,14 +1076,19 @@ class DestinationController extends GetxController {
|
||||
// "^^^^^^^^ ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}");
|
||||
try {
|
||||
gps_push_started = true;
|
||||
ExternalService().pushGPS();
|
||||
await ExternalService().pushGPS();
|
||||
} catch (e) {
|
||||
print("An error occurred in pushGPStoServer: $e");
|
||||
//print("An error occurred: $e");
|
||||
//await pushGPStoServer();
|
||||
} finally {
|
||||
//print("--- End of pushGPStoServer function, calling recursively ---");
|
||||
await Future.delayed(const Duration(seconds: 5 * 60));
|
||||
await pushGPStoServer();
|
||||
if (gps_push_started) {
|
||||
Future.delayed(Duration(minutes: 5), pushGPStoServer);
|
||||
}
|
||||
|
||||
//print("--- End of pushGPStoServer function, calling recursively ---");
|
||||
//await Future.delayed(const Duration(seconds: 5 * 60));
|
||||
//await pushGPStoServer();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1332,12 +1342,13 @@ class DestinationController extends GetxController {
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
startCheckForCheckinTimer();
|
||||
|
||||
|
||||
/*
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
startGPSCheckTimer();
|
||||
|
||||
@ -1415,6 +1426,18 @@ class DestinationController extends GetxController {
|
||||
//checkGPSDataReceived();
|
||||
}
|
||||
|
||||
void startCheckForCheckinTimer() {
|
||||
_checkForCheckinTimer = Timer.periodic(Duration(milliseconds: _checkInterval), (_) {
|
||||
checkForCheckin();
|
||||
});
|
||||
}
|
||||
|
||||
void stopCheckForCheckinTimer() {
|
||||
_checkForCheckinTimer?.cancel();
|
||||
_checkForCheckinTimer = null;
|
||||
}
|
||||
|
||||
|
||||
void restartGPS(){
|
||||
// GPSデータのListenを再開する処理を追加
|
||||
Future.delayed(const Duration(seconds: 5), () {
|
||||
@ -1427,8 +1450,9 @@ class DestinationController extends GetxController {
|
||||
//
|
||||
@override
|
||||
void onClose() {
|
||||
gpsCheckTimer?.cancel();
|
||||
locationController.stopPositionStream();
|
||||
stopCheckForCheckinTimer();
|
||||
//gpsCheckTimer?.cancel();
|
||||
//locationController.stopPositionStream();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@ import 'package:gifunavi/services/api_service.dart';
|
||||
import 'package:gifunavi/pages/index/index_controller.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
|
||||
import '../../model/user.dart';
|
||||
|
||||
class EntryController extends GetxController {
|
||||
late ApiService _apiService;
|
||||
|
||||
@ -29,6 +31,8 @@ class EntryController extends GetxController {
|
||||
|
||||
final activeEvents = <Event>[].obs; //有効なイベントリスト
|
||||
|
||||
final teamMembers = <User>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
@ -98,12 +102,64 @@ class EntryController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
void updateTeam(Team? value) {
|
||||
Future<void> fetchTeamMembers(int teamId) async {
|
||||
try {
|
||||
final members = await _apiService.getTeamMembers(teamId);
|
||||
teamMembers.assignAll(members);
|
||||
} catch (e) {
|
||||
print('Error fetching team members: $e');
|
||||
Get.snackbar('Error', 'Failed to fetch team members');
|
||||
}
|
||||
}
|
||||
|
||||
List<NewCategory> getFilteredCategories() {
|
||||
if (selectedTeam.value == null) return [];
|
||||
|
||||
if (teamMembers.isEmpty) {
|
||||
// ソロの場合
|
||||
String baseCategory = selectedTeam.value!.members.first.female ? 'ソロ女子' : 'ソロ男子';
|
||||
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
|
||||
} else if (teamMembers.length == 1) {
|
||||
// チームメンバーが1人の場合(ソロ)
|
||||
String baseCategory = teamMembers.first.female ? 'ソロ女子' : 'ソロ男子';
|
||||
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
|
||||
} else {
|
||||
// 複数人の場合
|
||||
bool hasElementaryOrYounger = teamMembers.any(isElementarySchoolOrYounger);
|
||||
String baseCategory = hasElementaryOrYounger ? 'ファミリー' : '一般';
|
||||
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
bool isElementarySchoolOrYounger(User user) {
|
||||
final now = DateTime.now();
|
||||
final age = now.year - user.dateOfBirth!.year;
|
||||
return age <= 12;
|
||||
}
|
||||
|
||||
void updateTeam(Team? value) async {
|
||||
selectedTeam.value = value;
|
||||
if (value != null) {
|
||||
await fetchTeamMembers(value.id);
|
||||
final filteredCategories = getFilteredCategories();
|
||||
if (filteredCategories.isNotEmpty) {
|
||||
selectedCategory.value = filteredCategories.first;
|
||||
} else {
|
||||
selectedCategory.value = null;
|
||||
}
|
||||
} else {
|
||||
teamMembers.clear();
|
||||
selectedCategory.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
void updateTeam_old(Team? value) {
|
||||
selectedTeam.value = value;
|
||||
if (value != null) {
|
||||
selectedCategory.value = value.category;
|
||||
}
|
||||
}
|
||||
|
||||
//void updateTeam(Team? value) => selectedTeam.value = value;
|
||||
void updateCategory(NewCategory? value) => selectedCategory.value = value;
|
||||
//void updateDate(DateTime value) => selectedDate.value = value;
|
||||
|
||||
@ -175,6 +175,20 @@ class EntryDetailPage extends GetView<EntryController> {
|
||||
}
|
||||
|
||||
Widget _buildCategoryDropdown() {
|
||||
final eligibleCategories = controller.getFilteredCategories();
|
||||
|
||||
return DropdownButtonFormField<NewCategory>(
|
||||
decoration: InputDecoration(labelText: 'カテゴリ'),
|
||||
value: controller.selectedCategory.value,
|
||||
items: eligibleCategories.map((category) => DropdownMenuItem<NewCategory>(
|
||||
value: category,
|
||||
child: Text(category.categoryName),
|
||||
)).toList(),
|
||||
onChanged: (value) => controller.updateCategory(value),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCategoryDropdown_old() {
|
||||
final eligibleCategories = controller.categories.where((c) =>
|
||||
c.baseCategory == controller.selectedCategory.value?.baseCategory
|
||||
).toList();
|
||||
|
||||
@ -240,14 +240,14 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
try {
|
||||
super.onInit();
|
||||
initConnectivity();
|
||||
_connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
//WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
// await PermissionController.checkAndRequestPermissions();
|
||||
//});
|
||||
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_startLocationService(); // アプリ起動時にLocationServiceを開始する
|
||||
|
||||
@ -40,7 +40,7 @@ class _IndexPageState extends State<IndexPage> {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await _ensureControllersAreInitialized();
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
//await PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -167,6 +167,17 @@ class PermissionController {
|
||||
}
|
||||
|
||||
static Future<bool> showLocationDisclosure() async {
|
||||
if (Platform.isIOS) {
|
||||
return await _showLocationDisclosureIOS();
|
||||
} else if (Platform.isAndroid) {
|
||||
return await _showLocationDisclosureAndroid();
|
||||
} else {
|
||||
// その他のプラットフォームの場合はデフォルトの処理を行う
|
||||
return await _showLocationDisclosureIOS();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> _showLocationDisclosureIOS() async {
|
||||
if (Get.context == null) {
|
||||
print('Context is null, cannot show dialog');
|
||||
return false;
|
||||
@ -214,6 +225,41 @@ class PermissionController {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> _showLocationDisclosureAndroid() async {
|
||||
return await showDialog<bool>(
|
||||
context: Get.overlayContext ?? Get.context ?? (throw Exception('No valid context found')),
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
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: () => Navigator.of(context).pop(false),
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('同意する'),
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
) ?? false;
|
||||
}
|
||||
|
||||
static void showPermissionDeniedDialog(String title,String message) {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
|
||||
@ -329,13 +329,6 @@ class TeamController extends GetxController {
|
||||
}
|
||||
|
||||
List<NewCategory> getFilteredCategories_old() {
|
||||
//List<User> teamMembers = getCurrentTeamMembers();
|
||||
return categories.where((category) {
|
||||
return isCategoryValid(category, teamMembers);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<NewCategory> getFilteredCategories() {
|
||||
if (teamMembers.isEmpty && currentUser.value != null) {
|
||||
// ソロの場合
|
||||
String baseCategory = currentUser.value!.female ? 'ソロ女子' : 'ソロ男子';
|
||||
@ -347,6 +340,24 @@ class TeamController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
List<NewCategory> getFilteredCategories() {
|
||||
if (teamMembers.isEmpty && currentUser.value != null) {
|
||||
// ソロの場合
|
||||
String baseCategory = currentUser.value!.female ? 'ソロ女子' : 'ソロ男子';
|
||||
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
|
||||
} else if (teamMembers.length == 1) {
|
||||
// チームメンバーが1人の場合(ソロ)
|
||||
String baseCategory = teamMembers.first.female ? 'ソロ女子' : 'ソロ男子';
|
||||
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
|
||||
} else {
|
||||
// 複数人の場合
|
||||
bool hasElementaryOrYounger = teamMembers.any(isElementarySchoolOrYounger);
|
||||
String baseCategory = hasElementaryOrYounger ? 'ファミリー' : '一般';
|
||||
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isElementarySchoolOrYounger(User user) {
|
||||
final now = DateTime.now();
|
||||
final age = now.year - user.dateOfBirth!.year;
|
||||
@ -379,17 +390,7 @@ class TeamController extends GetxController {
|
||||
// メンバーリストの最新状態を取得
|
||||
await fetchTeamMembers(selectedTeam.value!.id);
|
||||
|
||||
List<NewCategory> eligibleCategories = [];
|
||||
if (teamMembers.isEmpty || teamMembers.length == 1) {
|
||||
if (currentUser.value != null) {
|
||||
String baseCategory = currentUser.value!.female ? 'ソロ女子' : 'ソロ男子';
|
||||
eligibleCategories = categories.where((c) => c.baseCategory == baseCategory).toList();
|
||||
}
|
||||
} else {
|
||||
bool hasElementaryOrYounger = teamMembers.any(isElementarySchoolOrYounger);
|
||||
String baseCategory = hasElementaryOrYounger ? 'ファミリー' : '一般';
|
||||
eligibleCategories = categories.where((c) => c.baseCategory == baseCategory).toList();
|
||||
}
|
||||
List<NewCategory> eligibleCategories = getFilteredCategories();
|
||||
|
||||
// 同じ時間のカテゴリを優先的に選択
|
||||
NewCategory? newCategory = eligibleCategories.firstWhereOrNull((c) => c.time == oldTime);
|
||||
|
||||
@ -120,15 +120,19 @@ class _TeamDetailPageState extends State<TeamDetailPage> {
|
||||
}
|
||||
|
||||
final filteredCategories = controller.getFilteredCategories();
|
||||
final categoriesToDisplay = filteredCategories.isEmpty
|
||||
? controller.categories
|
||||
: filteredCategories;
|
||||
// 選択されているカテゴリが表示リストに含まれていない場合、最初の項目を選択する
|
||||
if (controller.selectedCategory.value == null ||
|
||||
!filteredCategories.contains(controller.selectedCategory.value)) {
|
||||
controller.updateCategory(filteredCategories.isNotEmpty
|
||||
? filteredCategories.first
|
||||
: null);
|
||||
}
|
||||
|
||||
// 選択されているカテゴリが表示リストに含まれていない場合、最初の項目を選択する
|
||||
if (controller.selectedCategory.value == null ||
|
||||
!categoriesToDisplay.contains(controller.selectedCategory.value)) {
|
||||
controller.updateCategory(categoriesToDisplay.isNotEmpty
|
||||
? categoriesToDisplay.first
|
||||
!filteredCategories.contains(controller.selectedCategory.value)) {
|
||||
controller.updateCategory(filteredCategories.isNotEmpty
|
||||
? filteredCategories.first
|
||||
: null);
|
||||
}
|
||||
|
||||
@ -147,7 +151,7 @@ class _TeamDetailPageState extends State<TeamDetailPage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (categoriesToDisplay.isEmpty)
|
||||
if (filteredCategories.isEmpty)
|
||||
const Text('カテゴリデータを読み込めませんでした。',
|
||||
style: TextStyle(color: Colors.red))
|
||||
else
|
||||
@ -156,7 +160,7 @@ class _TeamDetailPageState extends State<TeamDetailPage> {
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'カテゴリ'),
|
||||
value: controller.selectedCategory.value,
|
||||
items: categoriesToDisplay.map((category) =>
|
||||
items: filteredCategories.map((category) =>
|
||||
DropdownMenuItem(
|
||||
value: category,
|
||||
child: Text(category.categoryName),
|
||||
|
||||
Reference in New Issue
Block a user