2024-08-22 14:35:09 +09:00
|
|
|
|
import 'dart:ui' as ui;
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
2022-06-27 12:15:54 +05:30
|
|
|
|
import 'package:flutter/material.dart';
|
2024-08-22 14:35:09 +09:00
|
|
|
|
import 'package:geojson_vi/geojson_vi.dart';
|
2023-02-16 19:36:39 +05:30
|
|
|
|
import 'package:geolocator/geolocator.dart';
|
2022-06-27 12:15:54 +05:30
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
|
import 'package:image_picker/image_picker.dart';
|
2022-07-09 22:51:34 +05:30
|
|
|
|
import 'package:latlong2/latlong.dart';
|
2024-08-22 14:35:09 +09:00
|
|
|
|
import 'package:gifunavi/main.dart';
|
|
|
|
|
|
import 'package:gifunavi/model/destination.dart';
|
|
|
|
|
|
import 'package:gifunavi/pages/camera/camera_page.dart';
|
|
|
|
|
|
import 'package:gifunavi/pages/destination/destination_controller.dart';
|
|
|
|
|
|
import 'package:gifunavi/pages/index/index_controller.dart';
|
|
|
|
|
|
import 'package:gifunavi/services/external_service.dart';
|
|
|
|
|
|
import 'package:gifunavi/utils/const.dart';
|
|
|
|
|
|
import 'package:gifunavi/utils/database_helper.dart';
|
|
|
|
|
|
import 'package:gifunavi/utils/text_util.dart';
|
|
|
|
|
|
import 'package:gifunavi/widgets/bottom_sheet_controller.dart';
|
2022-06-27 12:15:54 +05:30
|
|
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
import 'package:timezone/timezone.dart' as tz;
|
|
|
|
|
|
import 'package:timezone/data/latest.dart' as tz;
|
|
|
|
|
|
|
|
|
|
|
|
// BottomSheetNewは、StatelessWidgetを継承したクラスで、目的地の詳細情報を表示するボトムシートのUIを構築します。
|
|
|
|
|
|
// コンストラクタでは、destination(目的地オブジェクト)とisAlreadyCheckedIn(すでにチェックイン済みかどうかのフラグ)を受け取ります。
|
|
|
|
|
|
// buildメソッドでは、detailsSheetメソッドを呼び出して、目的地の詳細情報を表示します。
|
|
|
|
|
|
//
|
2022-06-27 12:15:54 +05:30
|
|
|
|
class BottomSheetNew extends GetView<BottomSheetController> {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
BottomSheetNew(
|
|
|
|
|
|
{this.isAlreadyCheckedIn = false, super.key, required this.destination});
|
2022-06-27 12:15:54 +05:30
|
|
|
|
|
|
|
|
|
|
final IndexController indexController = Get.find<IndexController>();
|
2023-09-03 23:37:41 +05:30
|
|
|
|
final DestinationController destinationController =
|
|
|
|
|
|
Get.find<DestinationController>();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
final Destination destination; // 目的地オブジェクト
|
|
|
|
|
|
final bool isAlreadyCheckedIn; // すでにチェックイン済みかどうかのフラグ
|
|
|
|
|
|
|
|
|
|
|
|
final RxBool isButtonDisabled = false.obs;
|
|
|
|
|
|
|
|
|
|
|
|
static bool _timezoneInitialized = false;
|
|
|
|
|
|
|
|
|
|
|
|
void _initializeTimezone() {
|
|
|
|
|
|
if (!_timezoneInitialized) {
|
|
|
|
|
|
tz.initializeTimeZones();
|
|
|
|
|
|
_timezoneInitialized = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-06-27 12:15:54 +05:30
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// 目的地の画像を取得するためのメソッドです。
|
|
|
|
|
|
// indexController.rogModeの値に基づいて、適切な画像を返します。画像が見つからない場合は、デフォルトの画像を返します。
|
|
|
|
|
|
//
|
2023-09-03 23:37:41 +05:30
|
|
|
|
Image getImage() {
|
|
|
|
|
|
String serverUrl = ConstValues.currentServer();
|
2024-08-22 14:35:09 +09:00
|
|
|
|
|
|
|
|
|
|
if (indexController.rogMode == 1) {
|
2023-09-03 23:37:41 +05:30
|
|
|
|
if (indexController.currentDestinationFeature.isEmpty ||
|
|
|
|
|
|
indexController.currentDestinationFeature[0].photos! == "") {
|
|
|
|
|
|
return const Image(image: AssetImage('assets/images/empty_image.png'));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
//print("@@@@@@@@@@@@@ rog mode -------------------- ${indexController.currentDestinationFeature[0].photos} @@@@@@@@@@@");
|
|
|
|
|
|
String photo = indexController.currentDestinationFeature[0].photos!;
|
|
|
|
|
|
if (photo.contains('http')) {
|
|
|
|
|
|
return Image(
|
|
|
|
|
|
image: NetworkImage(
|
|
|
|
|
|
indexController.currentDestinationFeature[0].photos!,
|
2022-09-27 17:52:54 +05:30
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
errorBuilder: (BuildContext context, Object exception,
|
|
|
|
|
|
StackTrace? stackTrace) {
|
2022-09-27 17:52:54 +05:30
|
|
|
|
return Image.asset("assets/images/empty_image.png");
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
2023-09-03 23:37:41 +05:30
|
|
|
|
} else {
|
|
|
|
|
|
return Image(
|
|
|
|
|
|
image: NetworkImage(
|
|
|
|
|
|
'$serverUrl/media/compressed/${indexController.currentDestinationFeature[0].photos!}',
|
2022-09-27 17:52:54 +05:30
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
errorBuilder: (BuildContext context, Object exception,
|
|
|
|
|
|
StackTrace? stackTrace) {
|
2022-09-27 17:52:54 +05:30
|
|
|
|
return Image.asset("assets/images/empty_image.png");
|
|
|
|
|
|
},
|
2022-07-14 23:10:24 +05:30
|
|
|
|
);
|
2022-09-27 17:52:54 +05:30
|
|
|
|
}
|
2022-07-14 23:10:24 +05:30
|
|
|
|
}
|
2023-09-03 23:37:41 +05:30
|
|
|
|
} else {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
GeoJSONFeature gf = indexController.currentFeature[0];
|
|
|
|
|
|
//print("=== photo sss ${gf.properties!["photos"]}");
|
2023-09-03 23:37:41 +05:30
|
|
|
|
if (gf.properties!["photos"] == null || gf.properties!["photos"] == "") {
|
|
|
|
|
|
return const Image(image: AssetImage('assets/images/empty_image.png'));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
String photo = gf.properties!["photos"];
|
|
|
|
|
|
if (photo.contains('http')) {
|
|
|
|
|
|
return Image(
|
|
|
|
|
|
image: NetworkImage(
|
|
|
|
|
|
gf.properties!["photos"],
|
2022-09-27 17:52:54 +05:30
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
errorBuilder: (BuildContext context, Object exception,
|
|
|
|
|
|
StackTrace? stackTrace) {
|
2022-09-27 17:52:54 +05:30
|
|
|
|
return Image.asset("assets/images/empty_image.png");
|
|
|
|
|
|
},
|
2023-09-03 23:37:41 +05:30
|
|
|
|
);
|
|
|
|
|
|
} else {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
String imageUrl = Uri.encodeFull(
|
|
|
|
|
|
'$serverUrl/media/compressed/${gf.properties!["photos"]}');
|
2023-09-03 23:37:41 +05:30
|
|
|
|
return Image(
|
|
|
|
|
|
image: NetworkImage(
|
2024-08-22 14:35:09 +09:00
|
|
|
|
imageUrl,
|
2022-09-27 17:52:54 +05:30
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
errorBuilder: (BuildContext context, Object exception,
|
|
|
|
|
|
StackTrace? stackTrace) {
|
2022-09-27 17:52:54 +05:30
|
|
|
|
return Image.asset("assets/images/empty_image.png");
|
|
|
|
|
|
},
|
2023-09-03 23:37:41 +05:30
|
|
|
|
);
|
2022-09-27 17:52:54 +05:30
|
|
|
|
}
|
2023-09-03 23:37:41 +05:30
|
|
|
|
}
|
2022-07-14 23:10:24 +05:30
|
|
|
|
}
|
2022-06-27 12:15:54 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// URLを開くためのメソッドです。
|
|
|
|
|
|
// url_launcherパッケージを使用して、指定されたURLを開きます。
|
|
|
|
|
|
//
|
2022-06-27 12:15:54 +05:30
|
|
|
|
void _launchURL(url) async {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
if (!await launchUrl(url)) throw 'Could not launch $url';
|
2022-06-27 12:15:54 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// 指定されたlocationidが目的地リストに含まれているかどうかを確認するメソッドです。
|
|
|
|
|
|
// destinationController.destinationsリストを走査し、locationidが一致する目的地があるかどうかを返します。
|
|
|
|
|
|
//
|
2023-09-03 23:37:41 +05:30
|
|
|
|
bool isInDestination(String locationid) {
|
2022-07-22 19:36:04 +05:30
|
|
|
|
int lid = int.parse(locationid);
|
2023-09-03 23:37:41 +05:30
|
|
|
|
if (destinationController.destinations
|
|
|
|
|
|
.where((element) => element.location_id == lid)
|
|
|
|
|
|
.isNotEmpty) {
|
2022-07-22 19:36:04 +05:30
|
|
|
|
return true;
|
2023-09-03 23:37:41 +05:30
|
|
|
|
} else {
|
2022-07-22 19:36:04 +05:30
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Future<void> saveTemporaryImage(Destination destination) async {
|
|
|
|
|
|
final serverUrl = ConstValues.currentServer();
|
|
|
|
|
|
final imagePath = '$serverUrl/media/compressed/${destination.photos}';
|
|
|
|
|
|
|
|
|
|
|
|
final tempDir = await getTemporaryDirectory();
|
|
|
|
|
|
final tempFile = await File('${tempDir.path}/temp_image.jpg').create(recursive: true);
|
|
|
|
|
|
final response = await http.get(Uri.parse(imagePath));
|
|
|
|
|
|
await tempFile.writeAsBytes(response.bodyBytes);
|
|
|
|
|
|
|
|
|
|
|
|
destinationController.photos.clear();
|
|
|
|
|
|
destinationController.photos.add(tempFile);
|
2022-07-14 23:10:24 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// アクションボタン(チェックイン、ゴールなど)を表示するためのメソッドです。
|
|
|
|
|
|
// 現在の状態に基づいて、適切なボタンを返します。
|
|
|
|
|
|
// ボタンがタップされたときの処理も含まれています。
|
|
|
|
|
|
//
|
|
|
|
|
|
Widget getActionButton(BuildContext context, Destination destination) {
|
|
|
|
|
|
_initializeTimezone(); // タイムゾーンの初期化
|
|
|
|
|
|
/*
|
|
|
|
|
|
debugPrint("getActionButton ${destinationController.rogainingCounted.value}");
|
|
|
|
|
|
debugPrint("getActionButton ${destinationController.distanceToStart()}");
|
|
|
|
|
|
debugPrint("getActionButton ${destination.cp}");
|
|
|
|
|
|
debugPrint("getActionButton ${DestinationController.ready_for_goal}");
|
|
|
|
|
|
// ...2024-04-03 Akira デバッグモードのみ出力するようにした。
|
|
|
|
|
|
*/
|
2022-10-30 21:43:29 +05:30
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// bool isInRog=false;
|
|
|
|
|
|
Destination cdest = destinationController
|
|
|
|
|
|
.festuretoDestination(indexController.currentFeature[0]);
|
|
|
|
|
|
var distance = const Distance();
|
|
|
|
|
|
double distanceToDest = distance.as(
|
|
|
|
|
|
LengthUnit.Meter,
|
|
|
|
|
|
LatLng(
|
|
|
|
|
|
destinationController.currentLat, destinationController.currentLon),
|
|
|
|
|
|
LatLng(cdest.lat!, cdest.lon!));
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
// スタートボタン:
|
|
|
|
|
|
// 表示条件:
|
|
|
|
|
|
// 1. 目的地のCP番号が-1または0の場合
|
|
|
|
|
|
// 2. ロゲイニングがまだ開始されていない場合(destinationController.isInRog.value == false)
|
|
|
|
|
|
// 3. 最後のゴールから10時間以上経過している場合
|
|
|
|
|
|
//
|
2024-08-22 14:35:09 +09:00
|
|
|
|
if (destinationController.isInRog.value == false &&
|
|
|
|
|
|
(destinationController.distanceToStart() <= 100 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
|
|
|
|
|
|
(destination.cp == -1 || destination.cp == 0 ) &&
|
|
|
|
|
|
destinationController.rogainingCounted.value == false) {
|
|
|
|
|
|
// ゲームが始まってなければ
|
|
|
|
|
|
// ロゲ開始している && (開始地点から100m以内 又は 電波が弱い) && CP番号が 1 or 0 && rogainingCounted==false(どこにもチェックインしていない) なら
|
|
|
|
|
|
return Obx(() {
|
|
|
|
|
|
final isInRog = destinationController.isInRog.value;
|
|
|
|
|
|
|
|
|
|
|
|
return ElevatedButton(
|
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
|
backgroundColor: Theme.of(context).colorScheme.secondary,
|
|
|
|
|
|
),
|
|
|
|
|
|
onPressed: destinationController.isInRog.value
|
|
|
|
|
|
? null
|
|
|
|
|
|
: () async {
|
|
|
|
|
|
// Check if the event is for today
|
|
|
|
|
|
bool isEventToday = await checkIfEventIsToday();
|
|
|
|
|
|
if (!isEventToday) {
|
|
|
|
|
|
Get.dialog(
|
|
|
|
|
|
AlertDialog(
|
|
|
|
|
|
title: const Text("警告"),
|
|
|
|
|
|
content: const Text("参加したエントリーは別日のものですので、ロゲの開始はできません。当日のエントリーを選択するか、エントリーを今日に変更してからロゲ開始を行ってください。"),
|
|
|
|
|
|
actions: <Widget>[
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: const Text("OK"),
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
Get.back(); // Close the dialog
|
|
|
|
|
|
Get.back(); // Close the bottom sheet
|
|
|
|
|
|
},
|
2022-10-12 21:46:17 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check if user has already completed a rogaining event today
|
|
|
|
|
|
bool hasCompletedToday = await checkIfCompletedToday();
|
|
|
|
|
|
if (hasCompletedToday) {
|
|
|
|
|
|
Get.dialog(
|
|
|
|
|
|
AlertDialog(
|
|
|
|
|
|
title: const Text("警告"),
|
|
|
|
|
|
content: const Text("すでにロゲの参加を行いゴールをしています。ロゲは1日1回に制限されています。ご了承ください。"),
|
|
|
|
|
|
actions: <Widget>[
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: const Text("OK"),
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
Get.back(); // Close the dialog
|
|
|
|
|
|
Get.back(); // Close the bottom sheet
|
|
|
|
|
|
},
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
destinationController.isInRog.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Show confirmation dialog
|
|
|
|
|
|
Get.dialog(
|
|
|
|
|
|
AlertDialog(
|
|
|
|
|
|
title: Text("confirm".tr), //confirm
|
|
|
|
|
|
content: Text(
|
|
|
|
|
|
"clear_rog_data_message".tr), //are you sure
|
|
|
|
|
|
actions: <Widget>[
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: Text("no".tr), //no
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
// ダイアログをキャンセルした場合はボタンを再度有効化
|
|
|
|
|
|
destinationController.isInRog.value = false;
|
|
|
|
|
|
Get.back(); // Close the dialog
|
|
|
|
|
|
Get.back(); // Close the bottom sheet
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: Text("yes".tr), //yes
|
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
|
destinationController.isInRog.value = true;
|
|
|
|
|
|
await saveTemporaryImage(destination);
|
|
|
|
|
|
|
|
|
|
|
|
// Clear data and start game logic here
|
|
|
|
|
|
destinationController.resetRogaining();
|
|
|
|
|
|
|
|
|
|
|
|
destinationController.addToRogaining(
|
|
|
|
|
|
destinationController.currentLat,
|
|
|
|
|
|
destinationController.currentLon,
|
|
|
|
|
|
destination.location_id!,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
saveGameState();
|
|
|
|
|
|
//int teamId = indexController.teamId.value; // teamIdを使用
|
|
|
|
|
|
await ExternalService().startRogaining();
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
Get.back();// Close the dialog and potentially navigate away
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
barrierDismissible: false, // User must tap a button to close the dialog
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
child: Text(
|
|
|
|
|
|
isInRog ? 'in_game'.tr : 'start_rogaining'.tr,
|
|
|
|
|
|
style: const TextStyle(color: Colors.white),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//print("counted ${destinationController.rogainingCounted.value}");
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-02 21:25:19 +09:00
|
|
|
|
// ゴールボタン:
|
|
|
|
|
|
// 表示条件:
|
|
|
|
|
|
// 1. 目的地のCP番号が0、-2、または-1の場合
|
|
|
|
|
|
// 2. ロゲイニングが開始されている場合(destinationController.rogainingCounted.value == true)
|
|
|
|
|
|
// 3. スタート地点から500m以内にいる場合、または GPS信号が弱い場合
|
|
|
|
|
|
// 4. ゴール準備完了フラグが立っている場合(DestinationController.ready_for_goal == true)
|
|
|
|
|
|
//
|
2024-08-22 14:35:09 +09:00
|
|
|
|
}else if (destinationController.rogainingCounted.value == true &&
|
2024-09-02 21:25:19 +09:00
|
|
|
|
destinationController.isInRog.value == true &&
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// destinationController.distanceToStart() <= 500 && ... GPS信号が弱い時でもOKとする。
|
|
|
|
|
|
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) &&
|
|
|
|
|
|
(destination.cp == 0 || destination.cp == -2 || destination.cp == -1) &&
|
|
|
|
|
|
// (destination.cp == 0 || destination.cp == -2 ) &&
|
|
|
|
|
|
DestinationController.ready_for_goal == true) {
|
|
|
|
|
|
|
|
|
|
|
|
// ready_for_goal && (開始地点から500m以内 又は 電波が弱い) && CP番号が -1 or -2 or 0 && rogainingCounted==true なら
|
|
|
|
|
|
// Goal ボタン
|
|
|
|
|
|
//goal
|
|
|
|
|
|
|
|
|
|
|
|
return ElevatedButton(
|
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
|
foregroundColor: Colors.white,
|
|
|
|
|
|
backgroundColor: Colors.red
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
onPressed: destinationController.rogainingCounted.value == true &&
|
|
|
|
|
|
destinationController.distanceToStart() <= 500 &&
|
|
|
|
|
|
(destination.cp == 0 || destination.cp == -2|| destination.cp == -1) &&
|
|
|
|
|
|
DestinationController.ready_for_goal == true
|
|
|
|
|
|
? () async {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
destinationController.isAtGoal.value = true;
|
|
|
|
|
|
destinationController.photos.clear();
|
|
|
|
|
|
await showModalBottomSheet(
|
|
|
|
|
|
constraints: BoxConstraints.loose(
|
|
|
|
|
|
ui.Size(Get.width, Get.height * 0.75)),
|
|
|
|
|
|
context: Get.context!,
|
|
|
|
|
|
isScrollControlled: true,
|
|
|
|
|
|
builder: ((context) => CameraPage(
|
|
|
|
|
|
destination: destination,
|
|
|
|
|
|
))).whenComplete(() {
|
|
|
|
|
|
destinationController.skipGps = false;
|
|
|
|
|
|
destinationController.chekcs = 0;
|
|
|
|
|
|
destinationController.isAtGoal.value = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
: null,
|
|
|
|
|
|
child: Text(
|
2024-09-02 21:25:19 +09:00
|
|
|
|
"finish_rogaining".tr, // ロゲゴール
|
2024-08-22 14:35:09 +09:00
|
|
|
|
style: const TextStyle(color: Colors.white),
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
|
|
} else if (distanceToDest <=
|
|
|
|
|
|
destinationController.getForcedChckinDistance(destination)) {
|
|
|
|
|
|
// cpごとの強制チェックイン以内にいれば
|
|
|
|
|
|
//start
|
|
|
|
|
|
return ElevatedButton(
|
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
|
backgroundColor: Theme.of(context).colorScheme.secondary,
|
|
|
|
|
|
),
|
|
|
|
|
|
onPressed: isAlreadyCheckedIn == true
|
|
|
|
|
|
? null
|
|
|
|
|
|
: () async {
|
|
|
|
|
|
try{
|
|
|
|
|
|
destinationController.isCheckingIn.value = true; // ここを追加
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
Get.back();
|
2024-09-02 21:25:19 +09:00
|
|
|
|
if(destinationController.isInRog.value==false && destination.cp == -1){
|
|
|
|
|
|
destinationController.rogainingCounted.value = false;
|
|
|
|
|
|
}
|
2024-08-22 14:35:09 +09:00
|
|
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
|
|
|
|
await destinationController.callforCheckin(destination);
|
|
|
|
|
|
destinationController.isCheckingIn.value = false;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// エラーハンドリング
|
|
|
|
|
|
Get.snackbar(
|
|
|
|
|
|
'Error',
|
|
|
|
|
|
'An error occurred while processing check-in.',
|
|
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
|
|
colorText: Colors.white,
|
|
|
|
|
|
duration: const Duration(seconds: 3),
|
|
|
|
|
|
);
|
|
|
|
|
|
// 必要に応じてエラーログを記録
|
|
|
|
|
|
print('Error processing check-in: $e');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
child: Text(
|
|
|
|
|
|
destination.cp == -1 &&
|
2024-09-02 21:25:19 +09:00
|
|
|
|
destinationController.isInRog.value == false //&&
|
|
|
|
|
|
//destinationController.rogainingCounted.value == false
|
2024-08-22 14:35:09 +09:00
|
|
|
|
? "ロゲ開始"
|
|
|
|
|
|
: destinationController.isInRog.value == true &&
|
|
|
|
|
|
destination.cp == -1
|
|
|
|
|
|
? "in_game".tr
|
|
|
|
|
|
: isAlreadyCheckedIn == true
|
|
|
|
|
|
? "in_game".tr
|
|
|
|
|
|
: (destinationController.isInRog.value == true || (destination.buy_point != null && destination.buy_point! > 0))
|
|
|
|
|
|
? "checkin".tr
|
|
|
|
|
|
: "rogaining_not_started".tr,
|
|
|
|
|
|
style: TextStyle(color: Theme.of(context).colorScheme.onSecondary),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Container();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Add these new methods to check event date and completion status
|
|
|
|
|
|
Future<bool> checkIfEventIsToday() async {
|
|
|
|
|
|
try {
|
|
|
|
|
|
final now = tz.TZDateTime.now(tz.getLocation('Asia/Tokyo'));
|
|
|
|
|
|
|
|
|
|
|
|
// Null チェックと安全な操作を追加
|
|
|
|
|
|
final userEventDate = indexController.currentUser.isNotEmpty &&
|
|
|
|
|
|
indexController.currentUser[0]["user"] != null
|
|
|
|
|
|
? indexController.currentUser[0]["user"]["event_date"]
|
|
|
|
|
|
: null;
|
|
|
|
|
|
|
|
|
|
|
|
if (userEventDate == null || userEventDate.toString().isEmpty) {
|
|
|
|
|
|
print('Event date is null or empty');
|
|
|
|
|
|
return false; // イベント日付が設定されていない場合は false を返す
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
final eventDate = tz.TZDateTime.from(
|
|
|
|
|
|
DateTime.parse(userEventDate.toString()),
|
|
|
|
|
|
tz.getLocation('Asia/Tokyo')
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
return eventDate.year == now.year &&
|
|
|
|
|
|
eventDate.month == now.month &&
|
|
|
|
|
|
eventDate.day == now.day;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
print('Error in checkIfEventIsToday: $e');
|
|
|
|
|
|
// エラーが発生した場合はダイアログを表示
|
|
|
|
|
|
Get.dialog(
|
|
|
|
|
|
AlertDialog(
|
|
|
|
|
|
title: const Text('エラー'),
|
|
|
|
|
|
content: const Text('イベント日付の確認中にエラーが発生しました。\nアプリを再起動するか、管理者にお問い合わせください。'),
|
|
|
|
|
|
actions: <Widget>[
|
|
|
|
|
|
TextButton(
|
|
|
|
|
|
child: const Text('OK'),
|
|
|
|
|
|
onPressed: () => Get.back(),
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
return false; // エラーが発生した場合は false を返す
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<bool> checkIfCompletedToday() async {
|
|
|
|
|
|
final IndexController indexController = Get.find<IndexController>();
|
|
|
|
|
|
final lastGoalTime = await indexController.getLastGoalTime();
|
|
|
|
|
|
if (lastGoalTime == null) return false;
|
|
|
|
|
|
|
|
|
|
|
|
final now = DateTime.now();
|
|
|
|
|
|
return lastGoalTime.year == now.year &&
|
|
|
|
|
|
lastGoalTime.month == now.month &&
|
|
|
|
|
|
lastGoalTime.day == now.day;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 継承元のbuild をオーバーライドし、detailsSheetメソッドを呼び出して、目的地の詳細情報を表示します。
|
|
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
|
//print("to start ${destinationController.distanceToStart()}");
|
|
|
|
|
|
|
|
|
|
|
|
destinationController.skipGps = true;
|
|
|
|
|
|
// print('--- c use --- ${indexController.currentUser[0].values}');
|
|
|
|
|
|
// print('---- rog_mode ----- ${indexController.rogMode.value} -----');
|
|
|
|
|
|
// return indexController.rogMode.value == 0
|
|
|
|
|
|
// ? detailsSheet(context)
|
|
|
|
|
|
// : destinationSheet(context);
|
|
|
|
|
|
|
|
|
|
|
|
return Obx(() {
|
|
|
|
|
|
if (!destinationController.isCheckingIn.value) {
|
|
|
|
|
|
return detailsSheet(context);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Container(); // チェックイン操作中は空のコンテナを返す
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 指定された目的地がすでにチェックイン済みかどうかを確認するメソッドです。
|
|
|
|
|
|
// DatabaseHelperを使用して、目的地の位置情報に基づいてデータベースを検索し、結果を返します。
|
|
|
|
|
|
//
|
|
|
|
|
|
Future<bool> isDestinationCheckedIn(Destination d) async {
|
|
|
|
|
|
DatabaseHelper db = DatabaseHelper.instance;
|
|
|
|
|
|
List<Destination> ds = await db.getDestinationByLatLon(d.lat!, d.lon!);
|
|
|
|
|
|
|
|
|
|
|
|
return ds.isNotEmpty;
|
2023-09-03 23:37:41 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// show add location details
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// 目的地の詳細情報を表示するためのUIを構築するメソッドです。
|
|
|
|
|
|
// 目的地の画像、名前、住所、電話番号、Webサイト、備考などの情報を表示します。
|
|
|
|
|
|
// また、アクションボタンや「ここへ行く」ボタンも表示されます。
|
|
|
|
|
|
//
|
2023-09-03 23:37:41 +05:30
|
|
|
|
SingleChildScrollView detailsSheet(BuildContext context) {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Destination cdest = destinationController
|
|
|
|
|
|
.festuretoDestination(indexController.currentFeature[0]);
|
|
|
|
|
|
var distance = const Distance();
|
|
|
|
|
|
double distanceToDest = distance.as(
|
|
|
|
|
|
LengthUnit.Meter,
|
|
|
|
|
|
LatLng(
|
|
|
|
|
|
destinationController.currentLat, destinationController.currentLon),
|
|
|
|
|
|
LatLng(cdest.lat!, cdest.lon!));
|
|
|
|
|
|
|
|
|
|
|
|
debugPrint("Distance from current point : $distanceToDest");
|
|
|
|
|
|
debugPrint(
|
|
|
|
|
|
"forced distance for point : ${destinationController.getForcedChckinDistance(destination)}");
|
|
|
|
|
|
debugPrint(
|
|
|
|
|
|
"current point : ${destinationController.currentLat}, ${destinationController.currentLon} - ${DateTime.now().hour}:${DateTime.now().minute}:${DateTime.now().second}:${DateTime.now().microsecond}");
|
|
|
|
|
|
|
|
|
|
|
|
debugPrint("Checkin radius : ${destination.checkin_radious}");
|
|
|
|
|
|
debugPrint("--${destination.cp}--");
|
|
|
|
|
|
|
2023-09-03 23:37:41 +05:30
|
|
|
|
return SingleChildScrollView(
|
|
|
|
|
|
child: Column(
|
|
|
|
|
|
children: [
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Padding( // 1行目
|
2023-09-03 23:37:41 +05:30
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
child: Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
MaterialButton( // キャンセルボタン
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
},
|
|
|
|
|
|
color: Colors.blue,
|
|
|
|
|
|
textColor: Colors.white,
|
|
|
|
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
|
|
shape: const CircleBorder(),
|
|
|
|
|
|
child: const Icon(
|
|
|
|
|
|
Icons.arrow_back_ios,
|
|
|
|
|
|
size: 14,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
),
|
|
|
|
|
|
Expanded( // チェックポイント番号+ポイント名
|
|
|
|
|
|
child: Container(
|
|
|
|
|
|
alignment: Alignment.centerLeft,
|
|
|
|
|
|
child: Obx(() => Text(
|
|
|
|
|
|
"${TextUtils.getDisplayTextFeture(indexController.currentFeature[0])} : ${indexController.currentFeature[0].properties!["location_name"]}",
|
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
|
fontSize: 15.0,
|
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
|
),
|
|
|
|
|
|
)),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
),
|
|
|
|
|
|
],
|
2022-09-29 15:32:33 +05:30
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Row( // 2行目 チェックポイント写真
|
2023-09-03 23:37:41 +05:30
|
|
|
|
children: [
|
|
|
|
|
|
Expanded(
|
|
|
|
|
|
child: SizedBox(
|
2024-08-22 14:35:09 +09:00
|
|
|
|
height: 260.0,
|
|
|
|
|
|
child: Obx(() => getImage()),
|
|
|
|
|
|
)),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
],
|
|
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Obx(() => Padding( // 3行め ボタン類
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: Column(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
Row( // 開始・ゴールボタン
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
children: [
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// Finish or Goal
|
|
|
|
|
|
(destination.cp == -1 || destination.cp == 0 || destination.cp == -2)
|
|
|
|
|
|
? getActionButton(context, destination)
|
|
|
|
|
|
: Container(), // 一般CPは空
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
Row( // 2列目 チェックインボタン
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
|
|
children: [
|
|
|
|
|
|
//checkin or remove checkin
|
|
|
|
|
|
(destinationController.isInRog.value == true || (destination.buy_point != null && destination.buy_point! > 0))
|
|
|
|
|
|
&& (distanceToDest <=
|
|
|
|
|
|
destinationController.getForcedChckinDistance(destination) || destination.checkin_radious==-1 )
|
|
|
|
|
|
&& destination.cp != 0 && destination.cp != -1 && destination.cp != -2
|
|
|
|
|
|
? (isAlreadyCheckedIn == false
|
|
|
|
|
|
? ElevatedButton( // まだチェックインしていなければ、チェックインボタンを表示
|
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
|
backgroundColor: Colors.red),
|
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
|
try {
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
|
|
|
|
|
|
await destinationController.callforCheckin(destination);
|
|
|
|
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// エラーハンドリング
|
|
|
|
|
|
Get.snackbar(
|
|
|
|
|
|
'Error',
|
|
|
|
|
|
'An error occurred while processing check-in.',
|
|
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
|
|
colorText: Colors.white,
|
|
|
|
|
|
duration: const Duration(seconds: 3),
|
|
|
|
|
|
);
|
|
|
|
|
|
// 必要に応じてエラーログを記録
|
|
|
|
|
|
print('Error processing check-in: $e');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
child: Text(
|
|
|
|
|
|
"checkin".tr,
|
|
|
|
|
|
style: const TextStyle(color: Colors.white),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
: ElevatedButton( // チェックインしていれば、チェックイン取消ボタン
|
|
|
|
|
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.grey[300]),
|
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await destinationController.removeCheckin(destination.cp!.toInt());
|
|
|
|
|
|
destinationController.deleteDestination(destination);
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
Get.snackbar(
|
|
|
|
|
|
'チェックイン取り消し',
|
|
|
|
|
|
'${destination.name}のチェックインは取り消されました',
|
|
|
|
|
|
backgroundColor: Colors.green,
|
|
|
|
|
|
colorText: Colors.white,
|
|
|
|
|
|
duration: const Duration(seconds: 3),
|
|
|
|
|
|
);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// エラーハンドリング
|
|
|
|
|
|
Get.snackbar(
|
|
|
|
|
|
'Error',
|
|
|
|
|
|
'An error occurred while canceling check-in.',
|
|
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
|
|
colorText: Colors.white,
|
|
|
|
|
|
duration: const Duration(seconds: 3),
|
|
|
|
|
|
);
|
|
|
|
|
|
// 必要に応じてエラーログを記録
|
|
|
|
|
|
print('Error canceling check-in: $e');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
child: Text(
|
|
|
|
|
|
"cancel_checkin".tr,
|
|
|
|
|
|
style: const TextStyle(color: Colors.black),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
) : Container(), // 近くにいなければ空
|
|
|
|
|
|
// go here or cancel route
|
|
|
|
|
|
Obx(() => ElevatedButton(
|
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
|
backgroundColor: Theme.of(context)
|
|
|
|
|
|
.colorScheme
|
|
|
|
|
|
.onPrimaryContainer),
|
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
|
if (destinationController.isRouteShowing.value) {
|
|
|
|
|
|
destinationController.clearRoute();
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Get.back();
|
|
|
|
|
|
Position position =
|
|
|
|
|
|
await Geolocator.getCurrentPosition(
|
|
|
|
|
|
desiredAccuracy:
|
|
|
|
|
|
LocationAccuracy.bestForNavigation,
|
|
|
|
|
|
forceAndroidLocationManager: true);
|
|
|
|
|
|
Destination ds = Destination(
|
|
|
|
|
|
lat: position.latitude,
|
|
|
|
|
|
lon: position.longitude);
|
|
|
|
|
|
|
|
|
|
|
|
Destination tp = Destination(
|
|
|
|
|
|
lat: destination.lat, lon: destination.lon);
|
|
|
|
|
|
|
|
|
|
|
|
destinationController
|
|
|
|
|
|
.destinationMatrixFromCurrentPoint([ds, tp]);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
child: Text( //ルート表示 or ルート消去
|
|
|
|
|
|
destinationController.isRouteShowing.value
|
|
|
|
|
|
? "cancel_route".tr
|
|
|
|
|
|
: "go_here".tr,
|
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
|
color:
|
|
|
|
|
|
Theme.of(context).colorScheme.onPrimary),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
Expanded(
|
2023-09-03 23:37:41 +05:30
|
|
|
|
child: Row(
|
2024-08-22 14:35:09 +09:00
|
|
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
children: [
|
2024-08-22 14:35:09 +09:00
|
|
|
|
indexController.currentDestinationFeature
|
|
|
|
|
|
.isNotEmpty &&
|
|
|
|
|
|
destinationController.isInCheckin.value ==
|
|
|
|
|
|
true
|
|
|
|
|
|
? Container()
|
|
|
|
|
|
: FutureBuilder<Widget>(
|
|
|
|
|
|
future: wantToGo(context),
|
|
|
|
|
|
builder: (context, snapshot) {
|
|
|
|
|
|
return Container(
|
|
|
|
|
|
child: snapshot.data,
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
|
|
|
|
|
indexController.currentFeature[0]
|
2024-08-22 14:35:09 +09:00
|
|
|
|
.properties!["location_name"] !=
|
|
|
|
|
|
null &&
|
|
|
|
|
|
(indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["location_name"]
|
|
|
|
|
|
as String)
|
|
|
|
|
|
.isNotEmpty
|
|
|
|
|
|
? Flexible(
|
|
|
|
|
|
child: Text(indexController
|
|
|
|
|
|
.currentFeature[0]
|
|
|
|
|
|
.properties!["location_name"]))
|
2023-09-03 23:37:41 +05:30
|
|
|
|
: const SizedBox(
|
2024-08-22 14:35:09 +09:00
|
|
|
|
width: 0.0,
|
|
|
|
|
|
height: 0,
|
|
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
height: 8.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
const Icon(Icons.roundabout_left),
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 8.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["address"] !=
|
|
|
|
|
|
null &&
|
|
|
|
|
|
(indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["address"] as String)
|
|
|
|
|
|
.isNotEmpty
|
|
|
|
|
|
? getDetails(
|
|
|
|
|
|
context,
|
|
|
|
|
|
"address".tr,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
indexController.currentFeature[0]
|
2024-08-22 14:35:09 +09:00
|
|
|
|
.properties!["address"] ??
|
|
|
|
|
|
'')
|
|
|
|
|
|
: const SizedBox(
|
|
|
|
|
|
width: 0.0,
|
|
|
|
|
|
height: 0,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
const Icon(Icons.phone),
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 8.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["phone"] !=
|
|
|
|
|
|
null &&
|
|
|
|
|
|
(indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["phone"] as String)
|
|
|
|
|
|
.isNotEmpty
|
|
|
|
|
|
? getDetails(
|
|
|
|
|
|
context,
|
|
|
|
|
|
"telephone".tr,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
indexController.currentFeature[0]
|
2024-08-22 14:35:09 +09:00
|
|
|
|
.properties!["phone"] ??
|
|
|
|
|
|
'')
|
|
|
|
|
|
: const SizedBox(
|
|
|
|
|
|
width: 0.0,
|
|
|
|
|
|
height: 0,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
const Icon(Icons.email),
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 8.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["email"] !=
|
|
|
|
|
|
null &&
|
|
|
|
|
|
(indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["email"] as String)
|
|
|
|
|
|
.isNotEmpty
|
|
|
|
|
|
? getDetails(
|
|
|
|
|
|
context,
|
|
|
|
|
|
"email".tr,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
indexController.currentFeature[0]
|
2024-08-22 14:35:09 +09:00
|
|
|
|
.properties!["email"] ??
|
|
|
|
|
|
'')
|
|
|
|
|
|
: const SizedBox(
|
|
|
|
|
|
width: 0.0,
|
|
|
|
|
|
height: 0,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
const Icon(Icons.language),
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 8.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["webcontents"] !=
|
|
|
|
|
|
null &&
|
|
|
|
|
|
(indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["webcontents"] as String)
|
|
|
|
|
|
.isNotEmpty
|
|
|
|
|
|
? getDetails(
|
|
|
|
|
|
context,
|
|
|
|
|
|
"web".tr,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
indexController.currentFeature[0]
|
2024-08-22 14:35:09 +09:00
|
|
|
|
.properties!["webcontents"] ??
|
|
|
|
|
|
'',
|
|
|
|
|
|
isurl: true)
|
|
|
|
|
|
: const SizedBox(
|
|
|
|
|
|
width: 0.0,
|
|
|
|
|
|
height: 0,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
Padding(
|
|
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 8.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["remark"] !=
|
|
|
|
|
|
null &&
|
|
|
|
|
|
(indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["remark"] as String)
|
|
|
|
|
|
.isNotEmpty
|
|
|
|
|
|
? getDetails(
|
|
|
|
|
|
context,
|
|
|
|
|
|
"remarks".tr,
|
|
|
|
|
|
indexController.currentFeature[0]
|
|
|
|
|
|
.properties!["remark"] ??
|
|
|
|
|
|
'',
|
|
|
|
|
|
isurl: false)
|
|
|
|
|
|
: const SizedBox(
|
|
|
|
|
|
width: 0.0,
|
|
|
|
|
|
height: 0,
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
)),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
const SizedBox(
|
|
|
|
|
|
height: 60.0,
|
|
|
|
|
|
)
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
2022-06-27 12:15:54 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// 「行きたい」ボタンを表示するためのUIを構築するメソッドです。
|
|
|
|
|
|
// 目的地が選択されているかどうかに基づいて、適切なアイコンとテキストを表示します。
|
|
|
|
|
|
// ボタンがタップされたときの処理も含まれています。
|
|
|
|
|
|
//
|
2023-09-03 23:37:41 +05:30
|
|
|
|
Future<Widget> wantToGo(BuildContext context) async {
|
|
|
|
|
|
bool selected = false;
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// print(
|
|
|
|
|
|
// '---target-- ${indexController.currentFeature[0].properties!["location_id"]}----');
|
2023-09-03 23:37:41 +05:30
|
|
|
|
for (Destination d in destinationController.destinations) {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
//print('---- ${d.location_id.toString()} ----');
|
2023-09-03 23:37:41 +05:30
|
|
|
|
if (d.location_id ==
|
|
|
|
|
|
indexController.currentFeature[0].properties!["location_id"]) {
|
|
|
|
|
|
selected = true;
|
2022-09-27 17:52:54 +05:30
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-07-14 23:10:24 +05:30
|
|
|
|
|
2022-07-10 23:50:43 +05:30
|
|
|
|
DatabaseHelper db = DatabaseHelper.instance;
|
2023-09-03 23:37:41 +05:30
|
|
|
|
return Row(
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
|
children: [
|
|
|
|
|
|
Row(
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
|
children: [
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// indexController.rog_mode == 0 ?
|
|
|
|
|
|
// // IconButton(
|
|
|
|
|
|
// // icon: Icon(Icons.pin_drop_sharp, size: 32, color: _selected == true ? Colors.amber : Colors.blue,),
|
|
|
|
|
|
// // onPressed: (){
|
|
|
|
|
|
// // if(_selected){
|
|
|
|
|
|
// // // show remove from destination
|
|
|
|
|
|
// // Get.defaultDialog(
|
|
|
|
|
|
// // title: "本当にこのポイントを通過順から外しますか?",
|
|
|
|
|
|
// // middleText: "場所は目的地リストから削除されます",
|
|
|
|
|
|
// // backgroundColor: Colors.blue.shade300,
|
|
|
|
|
|
// // titleStyle: TextStyle(color: Colors.white),
|
|
|
|
|
|
// // middleTextStyle: TextStyle(color: Colors.white),
|
|
|
|
|
|
// // textConfirm: "はい",
|
|
|
|
|
|
// // textCancel: "いいえ",
|
|
|
|
|
|
// // cancelTextColor: Colors.white,
|
|
|
|
|
|
// // confirmTextColor: Colors.blue,
|
|
|
|
|
|
// // buttonColor: Colors.white,
|
|
|
|
|
|
// // barrierDismissible: false,
|
|
|
|
|
|
// // radius: 10,
|
|
|
|
|
|
// // content: Column(
|
|
|
|
|
|
// // children: [
|
|
|
|
|
|
// // ],
|
|
|
|
|
|
// // ),
|
|
|
|
|
|
// // onConfirm: (){
|
|
|
|
|
|
// // int _id = indexController.currentFeature[0].properties!["location_id"];
|
|
|
|
|
|
// // Destination? d = destinationController.destinationById(_id);
|
|
|
|
|
|
// // print('--- des id is : ${d} -----');
|
|
|
|
|
|
// // if(d != null) {
|
|
|
|
|
|
// // //print('--- des id is : ${d.location_id} -----');
|
|
|
|
|
|
// // destinationController.deleteDestination(d);
|
|
|
|
|
|
// // Get.back();
|
|
|
|
|
|
// // Get.back();
|
|
|
|
|
|
// // Get.snackbar("追加した", "場所が削除されました");
|
|
|
|
|
|
// // }
|
|
|
|
|
|
// // }
|
|
|
|
|
|
// // );
|
|
|
|
|
|
// // return;
|
|
|
|
|
|
// // }
|
|
|
|
|
|
// // // show add to destination
|
|
|
|
|
|
// // Get.defaultDialog(
|
|
|
|
|
|
// // title: "この場所を登録してもよろしいですか",
|
|
|
|
|
|
// // middleText: "ロケーションがロガニング リストに追加されます",
|
|
|
|
|
|
// // backgroundColor: Colors.blue.shade300,
|
|
|
|
|
|
// // titleStyle: TextStyle(color: Colors.white),
|
|
|
|
|
|
// // middleTextStyle: TextStyle(color: Colors.white),
|
|
|
|
|
|
// // textConfirm: "はい",
|
|
|
|
|
|
// // textCancel: "いいえ",
|
|
|
|
|
|
// // cancelTextColor: Colors.white,
|
|
|
|
|
|
// // confirmTextColor: Colors.blue,
|
|
|
|
|
|
// // buttonColor: Colors.white,
|
|
|
|
|
|
// // barrierDismissible: false,
|
|
|
|
|
|
// // radius: 10,
|
|
|
|
|
|
// // content: Column(
|
|
|
|
|
|
// // children: [
|
|
|
|
|
|
// // ],
|
|
|
|
|
|
// // ),
|
|
|
|
|
|
// // onConfirm: (){
|
|
|
|
|
|
// // GeoJsonMultiPoint mp = indexController.currentFeature[0].geometry as GeoJsonMultiPoint;
|
|
|
|
|
|
// // LatLng pt = LatLng(mp.geoSerie!.geoPoints[0].latitude, mp.geoSerie!.geoPoints[0].longitude);
|
|
|
|
|
|
|
|
|
|
|
|
// // print("----- want to go sub location is ---- ${indexController.currentFeature[0].properties!["sub_loc_id"]} -----");
|
|
|
|
|
|
|
|
|
|
|
|
// // Destination dest = Destination(
|
|
|
|
|
|
// // name: indexController.currentFeature[0].properties!["location_name"],
|
|
|
|
|
|
// // address: indexController.currentFeature[0].properties!["address"],
|
|
|
|
|
|
// // phone: indexController.currentFeature[0].properties!["phone"],
|
|
|
|
|
|
// // email: indexController.currentFeature[0].properties!["email"],
|
|
|
|
|
|
// // webcontents: indexController.currentFeature[0].properties!["webcontents"],
|
|
|
|
|
|
// // videos: indexController.currentFeature[0].properties!["videos"],
|
|
|
|
|
|
// // category: indexController.currentFeature[0].properties!["category"],
|
|
|
|
|
|
// // series: 1,
|
|
|
|
|
|
// // lat: pt.latitude,
|
|
|
|
|
|
// // lon: pt.longitude,
|
|
|
|
|
|
// // sub_loc_id: indexController.currentFeature[0].properties!["sub_loc_id"],
|
|
|
|
|
|
// // location_id: indexController.currentFeature[0].properties!["location_id"],
|
|
|
|
|
|
// // list_order: 1,
|
|
|
|
|
|
// // photos: indexController.currentFeature[0].properties!["photos"],
|
|
|
|
|
|
// // checkin_radious: indexController.currentFeature[0].properties!["checkin_radius"],
|
|
|
|
|
|
// // auto_checkin: indexController.currentFeature[0].properties!["auto_checkin"] == true ? 1 : 0,
|
|
|
|
|
|
// // cp: indexController.currentFeature[0].properties!["cp"],
|
|
|
|
|
|
// // checkin_point: indexController.currentFeature[0].properties!["checkin_point"],
|
|
|
|
|
|
// // buy_point: indexController.currentFeature[0].properties!["buy_point"],
|
|
|
|
|
|
// // selected: false,
|
|
|
|
|
|
// // checkedin: false,
|
|
|
|
|
|
// // hidden_location: indexController.currentFeature[0].properties!["hidden_location"] == true ?1 : 0
|
|
|
|
|
|
// // );
|
|
|
|
|
|
// // destinationController.addDestinations(dest);
|
|
|
|
|
|
// // Get.back();
|
|
|
|
|
|
// // Get.back();
|
|
|
|
|
|
// // Get.snackbar("追加した", "場所が追加されました");
|
|
|
|
|
|
// // }
|
|
|
|
|
|
// // );
|
|
|
|
|
|
|
|
|
|
|
|
// // },
|
|
|
|
|
|
// // ):
|
|
|
|
|
|
// // Container(),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 8.0,
|
|
|
|
|
|
),
|
2024-08-22 14:35:09 +09:00
|
|
|
|
Obx((() => indexController.rogMode.value == 1
|
2023-09-03 23:37:41 +05:30
|
|
|
|
? ElevatedButton(
|
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
|
Destination dest =
|
|
|
|
|
|
indexController.currentDestinationFeature[0];
|
2024-08-22 14:35:09 +09:00
|
|
|
|
//print("~~~~ before checking button ~~~~");
|
2023-09-03 23:37:41 +05:30
|
|
|
|
//print("------ curent destination is ${dest!.checkedIn}-------");
|
|
|
|
|
|
destinationController.makeCheckin(
|
|
|
|
|
|
dest, !dest.checkedin!, "");
|
|
|
|
|
|
},
|
|
|
|
|
|
child: indexController
|
|
|
|
|
|
.currentDestinationFeature[0].checkedin ==
|
|
|
|
|
|
false
|
|
|
|
|
|
? const Text("チェックイン")
|
|
|
|
|
|
: const Text("チェックアウト"))
|
|
|
|
|
|
: Container())),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
2022-07-09 22:51:34 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-03 23:37:41 +05:30
|
|
|
|
Widget getCheckin(BuildContext context) {
|
2022-07-25 19:56:32 +05:30
|
|
|
|
//print("------ currentAction ----- ${indexController.currentAction}-----");
|
2022-07-09 22:51:34 +05:30
|
|
|
|
|
2022-06-27 12:15:54 +05:30
|
|
|
|
return Row(
|
2023-09-03 23:37:41 +05:30
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
|
children: [
|
|
|
|
|
|
Row(
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
|
children: [
|
|
|
|
|
|
indexController.currentAction[0][0]["checkin"] == false
|
|
|
|
|
|
? Column(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
Row(
|
|
|
|
|
|
mainAxisSize: MainAxisSize.max,
|
2022-07-14 23:10:24 +05:30
|
|
|
|
children: [
|
2023-09-03 23:37:41 +05:30
|
|
|
|
ElevatedButton(
|
|
|
|
|
|
child: const Text("Image"),
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
final ImagePicker picker = ImagePicker();
|
|
|
|
|
|
picker
|
|
|
|
|
|
.pickImage(source: ImageSource.camera)
|
|
|
|
|
|
.then((value) {
|
2022-07-25 19:56:32 +05:30
|
|
|
|
//print("----- image---- ${value!.path}");
|
2022-07-14 23:10:24 +05:30
|
|
|
|
});
|
|
|
|
|
|
},
|
2023-09-03 23:37:41 +05:30
|
|
|
|
)
|
2022-07-14 23:10:24 +05:30
|
|
|
|
],
|
2023-09-03 23:37:41 +05:30
|
|
|
|
),
|
2022-07-14 23:10:24 +05:30
|
|
|
|
ElevatedButton(
|
2023-09-03 23:37:41 +05:30
|
|
|
|
onPressed: () {
|
|
|
|
|
|
if (indexController.currentAction.isNotEmpty) {
|
|
|
|
|
|
//print(indexController.currentAction[0]);
|
|
|
|
|
|
indexController.currentAction[0][0]["checkin"] =
|
|
|
|
|
|
true;
|
|
|
|
|
|
Map<String, dynamic> temp =
|
|
|
|
|
|
Map<String, dynamic>.from(
|
|
|
|
|
|
indexController.currentAction[0][0]);
|
|
|
|
|
|
indexController.currentAction.clear();
|
|
|
|
|
|
//print("---temp---${temp}");
|
|
|
|
|
|
indexController.currentAction.add([temp]);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
child: Text("checkin".tr))
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
: ElevatedButton(
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
if (indexController.currentAction.isNotEmpty) {
|
|
|
|
|
|
//print(indexController.currentAction[0]);
|
|
|
|
|
|
indexController.currentAction[0][0]["checkin"] = false;
|
|
|
|
|
|
Map<String, dynamic> temp = Map<String, dynamic>.from(
|
|
|
|
|
|
indexController.currentAction[0][0]);
|
|
|
|
|
|
indexController.currentAction.clear();
|
|
|
|
|
|
//print("---temp---${temp}");
|
|
|
|
|
|
indexController.currentAction.add([temp]);
|
2022-07-15 21:50:14 +05:30
|
|
|
|
}
|
|
|
|
|
|
},
|
2023-09-03 23:37:41 +05:30
|
|
|
|
child: const Icon(Icons.favorite, color: Colors.red),
|
|
|
|
|
|
)
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
2022-06-27 12:15:54 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-22 14:35:09 +09:00
|
|
|
|
// 目的地の詳細情報(住所、電話番号、Webサイトなど)を表示するためのUIを構築するメソッドです。
|
|
|
|
|
|
// ラベルとテキストを受け取り、適切なアイコンとともに表示します。
|
|
|
|
|
|
//
|
2023-09-03 23:37:41 +05:30
|
|
|
|
Widget getDetails(BuildContext context, String label, String text,
|
|
|
|
|
|
{bool isurl = false}) {
|
|
|
|
|
|
return Row(
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
|
children: [
|
|
|
|
|
|
Text(label),
|
|
|
|
|
|
const SizedBox(
|
|
|
|
|
|
width: 10.0,
|
|
|
|
|
|
),
|
|
|
|
|
|
InkWell(
|
|
|
|
|
|
onTap: () {
|
|
|
|
|
|
if (isurl) {
|
2024-08-22 14:35:09 +09:00
|
|
|
|
if (indexController.rogMode.value == 0) {
|
2023-09-03 23:37:41 +05:30
|
|
|
|
_launchURL(indexController
|
|
|
|
|
|
.currentFeature[0].properties!["webcontents"]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
indexController.currentDestinationFeature[0].webcontents;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
child: SizedBox(
|
2024-08-22 14:35:09 +09:00
|
|
|
|
width: MediaQuery.of(context).size.width -
|
|
|
|
|
|
(MediaQuery.of(context).size.width * 0.35),
|
2023-09-03 23:37:41 +05:30
|
|
|
|
child: Text(
|
|
|
|
|
|
text,
|
2024-08-22 14:35:09 +09:00
|
|
|
|
textAlign: TextAlign.justify,
|
2023-09-03 23:37:41 +05:30
|
|
|
|
style: TextStyle(
|
|
|
|
|
|
color: isurl ? Colors.blue : Colors.black,
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|