Compare commits
3 Commits
66ade1fe09
...
mapsix
| Author | SHA1 | Date | |
|---|---|---|---|
| f9a2bae9a9 | |||
| bdf6dd3c04 | |||
| 347861e5a1 |
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 60;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -398,11 +398,11 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 488;
|
||||
CURRENT_PROJECT_VERSION = 497;
|
||||
DEVELOPMENT_TEAM = UMNEWT25JR;
|
||||
ENABLE_BITCODE = NO;
|
||||
FLUTTER_BUILD_NAME = 4.8.8;
|
||||
FLUTTER_BUILD_NUMBER = 488;
|
||||
FLUTTER_BUILD_NAME = 4.8.17;
|
||||
FLUTTER_BUILD_NUMBER = 497;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "岐阜ナビ";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.healthcare-fitness";
|
||||
@ -411,7 +411,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 4.8.8;
|
||||
MARKETING_VERSION = 4.8.17;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunavi;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -539,11 +539,11 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 488;
|
||||
CURRENT_PROJECT_VERSION = 497;
|
||||
DEVELOPMENT_TEAM = UMNEWT25JR;
|
||||
ENABLE_BITCODE = NO;
|
||||
FLUTTER_BUILD_NAME = 4.8.8;
|
||||
FLUTTER_BUILD_NUMBER = 488;
|
||||
FLUTTER_BUILD_NAME = 4.8.17;
|
||||
FLUTTER_BUILD_NUMBER = 497;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "岐阜ナビ";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.healthcare-fitness";
|
||||
@ -552,7 +552,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 4.8.8;
|
||||
MARKETING_VERSION = 4.8.17;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunavi;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -571,11 +571,11 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 488;
|
||||
CURRENT_PROJECT_VERSION = 497;
|
||||
DEVELOPMENT_TEAM = UMNEWT25JR;
|
||||
ENABLE_BITCODE = NO;
|
||||
FLUTTER_BUILD_NAME = 4.8.8;
|
||||
FLUTTER_BUILD_NUMBER = 488;
|
||||
FLUTTER_BUILD_NAME = 4.8.17;
|
||||
FLUTTER_BUILD_NUMBER = 497;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "岐阜ナビ";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.healthcare-fitness";
|
||||
@ -584,7 +584,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 4.8.8;
|
||||
MARKETING_VERSION = 4.8.17;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dvox.gifunavi;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@ -11,6 +11,7 @@ import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
//import 'package:vm_service/vm_service.dart';
|
||||
//import 'package:dart_vm_info/dart_vm_info.dart';
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
|
||||
import 'package:rogapp/pages/settings/settings_controller.dart';
|
||||
|
||||
@ -152,6 +153,8 @@ void main() async {
|
||||
*/
|
||||
|
||||
try {
|
||||
tz.initializeTimeZones();
|
||||
|
||||
// ApiServiceを初期化
|
||||
//await Get.putAsync(() => ApiService().init());
|
||||
await initServices();
|
||||
|
||||
@ -239,6 +239,7 @@ class CameraPage extends StatelessWidget {
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(20),
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: destinationController.photos.isEmpty
|
||||
? Colors.red
|
||||
: Colors.grey[300],
|
||||
@ -294,7 +295,10 @@ class CameraPage extends StatelessWidget {
|
||||
? settingGoal.value == false
|
||||
? ElevatedButton(
|
||||
style:
|
||||
ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||
ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.red
|
||||
),
|
||||
onPressed: () async {
|
||||
// print(
|
||||
// "----- user isss ${indexController.currentUser[0]} -----");
|
||||
@ -339,7 +343,7 @@ class CameraPage extends StatelessWidget {
|
||||
isgoal: true);
|
||||
} else {
|
||||
//print("---- status ${value['status']} ---- ");
|
||||
Get.snackbar("目標が追加されていません", "please_try_again",
|
||||
Get.snackbar(value["detail"], "ERROR",
|
||||
backgroundColor: Colors.green,
|
||||
colorText: Colors.white
|
||||
);
|
||||
@ -359,7 +363,7 @@ class CameraPage extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
} else if (destinationController.isInRog.value &&
|
||||
} else if ((destinationController.isInRog.value || (destination.buy_point != null && destination.buy_point! > 0)) &&
|
||||
dbDest?.checkedin != null &&
|
||||
destination.cp != -1 &&
|
||||
dbDest?.checkedin == true) {
|
||||
@ -399,7 +403,7 @@ class CameraPage extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
} else if (destinationController.isInRog.value &&
|
||||
} else if ((destinationController.isInRog.value || (destination.buy_point != null && destination.buy_point! > 0)) &&
|
||||
dbDest?.checkedin != null &&
|
||||
destination.cp != -1 &&
|
||||
destination.use_qr_code == true &&
|
||||
@ -455,6 +459,7 @@ class CameraPage extends StatelessWidget {
|
||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||
onPressed: () async {
|
||||
// print(
|
||||
|
||||
// "##### current destination ${indexController.currentDestinationFeature[0].sub_loc_id} #######");
|
||||
await destinationController.makeCheckin(
|
||||
indexController.currentDestinationFeature[0],
|
||||
@ -502,7 +507,7 @@ class CameraPage extends StatelessWidget {
|
||||
|
||||
//}else if(destination.use_qr_code){
|
||||
// return QRCodeScannerPage(destination: destination);
|
||||
} else if (destinationController.isInRog.value) {
|
||||
} else if (destinationController.isInRog.value || (destination.buy_point != null && destination.buy_point! > 0)) {
|
||||
// isInRogがtrueの場合は、カメラページのUIを構築します。
|
||||
// AppBarには、目的地の情報を表示します。
|
||||
// ボディには、目的地の画像、タグ、アクションボタンを表示します。
|
||||
|
||||
@ -431,7 +431,7 @@ class DestinationController extends GetxController {
|
||||
debugPrint("* 目的地がない場合 ==> 検知半径=-1の場合");
|
||||
|
||||
// print("----- in location popup cp - ${d.cp}----");
|
||||
if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 24) {
|
||||
if ((d.cp == -1 || d.cp==0 ) && DateTime.now().difference(lastGoalAt).inHours >= 10) {
|
||||
debugPrint("**1: 開始CPで、最後にゴールしてから24時間経過していれば、");
|
||||
|
||||
chekcs = 1;
|
||||
@ -673,11 +673,11 @@ class DestinationController extends GetxController {
|
||||
|
||||
} else if (isInRog.value == false &&
|
||||
indexController.rogMode.value == 1 &&
|
||||
DateTime.now().difference(lastGoalAt).inHours >= 24) {
|
||||
DateTime.now().difference(lastGoalAt).inHours >= 10) {
|
||||
//start
|
||||
//print("---- in start -----");
|
||||
|
||||
debugPrint("**5 スタートの場合で最後のゴールから24時間経過している場合");
|
||||
debugPrint("**5 スタートの場合で最後のゴールから10時間経過している場合");
|
||||
|
||||
|
||||
chekcs = 6; // start point
|
||||
@ -825,7 +825,7 @@ class DestinationController extends GetxController {
|
||||
//print("is rog ---- ${is_in_rog.value} ----");
|
||||
if (d.hidden_location != null &&
|
||||
d.hidden_location == 0 &&
|
||||
isInRog.value == true &&
|
||||
(isInRog.value == true || (d.buy_point != null && d.buy_point! > 0)) &&
|
||||
d.cp != -1 && d.cp != 0 && d.cp != -2) {
|
||||
chekcs = 3;
|
||||
photos.clear();
|
||||
|
||||
@ -255,18 +255,17 @@ class DrawerPage extends StatelessWidget {
|
||||
Get.back(); // ドロワーを閉じる
|
||||
Get.toNamed(Routes.SETTINGS);
|
||||
},
|
||||
),
|
||||
|
||||
//ListTile(
|
||||
// leading: const Icon(Icons.developer_mode),
|
||||
// title: const Text('open_settings'),
|
||||
// onTap: () {
|
||||
// Get.back(); // ドロワーを閉じる
|
||||
// Get.toNamed('/debug'); // デバッグ画面に遷移
|
||||
// },
|
||||
//),
|
||||
|
||||
),
|
||||
/*
|
||||
ListTile(
|
||||
leading: const Icon(Icons.developer_mode),
|
||||
title: const Text('open_settings'),
|
||||
onTap: () {
|
||||
Get.back(); // ドロワーを閉じる
|
||||
Get.toNamed('/debug'); // デバッグ画面に遷移
|
||||
},
|
||||
),
|
||||
*/
|
||||
|
||||
// ListTile(
|
||||
// leading: const Icon(Icons.router),
|
||||
|
||||
@ -9,6 +9,8 @@ import 'package:rogapp/model/category.dart';
|
||||
import 'package:rogapp/services/api_service.dart';
|
||||
|
||||
import '../index/index_controller.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
|
||||
class EntryController extends GetxController {
|
||||
late ApiService _apiService;
|
||||
@ -92,8 +94,10 @@ class EntryController extends GetxController {
|
||||
|
||||
void updateTeam(Team? value) => selectedTeam.value = value;
|
||||
void updateCategory(NewCategory? value) => selectedCategory.value = value;
|
||||
void updateDate(DateTime value) => selectedDate.value = value;
|
||||
|
||||
//void updateDate(DateTime value) => selectedDate.value = value;
|
||||
void updateDate(DateTime value) {
|
||||
selectedDate.value = tz.TZDateTime.from(value, tz.getLocation('Asia/Tokyo'));
|
||||
}
|
||||
/*
|
||||
void updateDate(DateTime value){
|
||||
selectedDate.value = DateFormat('yyyy-MM-dd').format(value!) as DateTime?;
|
||||
@ -201,6 +205,7 @@ class EntryController extends GetxController {
|
||||
selectedEvent.value!.id,
|
||||
selectedCategory.value!.id,
|
||||
selectedDate.value!,
|
||||
currentEntry.value!.zekkenNumber,
|
||||
);
|
||||
final index = entries.indexWhere((entry) => entry.id == updatedEntry.id);
|
||||
if (index != -1) {
|
||||
|
||||
@ -8,6 +8,9 @@ import 'package:rogapp/model/category.dart';
|
||||
import 'package:rogapp/model/team.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
|
||||
class EntryDetailPage extends GetView<EntryController> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -70,7 +73,7 @@ class EntryDetailPage extends GetView<EntryController> {
|
||||
title: Text('日付'),
|
||||
subtitle: Text(
|
||||
controller.selectedDate.value != null
|
||||
? DateFormat('yyyy-MM-dd').format(controller.selectedDate.value!)
|
||||
? DateFormat('yyyy-MM-dd').format(tz.TZDateTime.from(controller.selectedDate.value!, tz.getLocation('Asia/Tokyo')))
|
||||
: '日付を選択してください',
|
||||
),
|
||||
onTap: () async {
|
||||
@ -78,14 +81,25 @@ class EntryDetailPage extends GetView<EntryController> {
|
||||
Get.snackbar('Error', 'Please select an event first');
|
||||
return;
|
||||
}
|
||||
final tz.TZDateTime now = tz.TZDateTime.now(tz.getLocation('Asia/Tokyo'));
|
||||
final tz.TZDateTime eventStart = tz.TZDateTime.from(controller.selectedEvent.value!.startDatetime, tz.getLocation('Asia/Tokyo'));
|
||||
final tz.TZDateTime eventEnd = tz.TZDateTime.from(controller.selectedEvent.value!.endDatetime, tz.getLocation('Asia/Tokyo'));
|
||||
|
||||
final tz.TZDateTime initialDate = controller.selectedDate.value != null
|
||||
? tz.TZDateTime.from(controller.selectedDate.value!, tz.getLocation('Asia/Tokyo'))
|
||||
: (now.isAfter(eventStart) ? now : eventStart);
|
||||
|
||||
// 選択可能な最初の日付を設定(今日かイベント開始日のうち、より後の日付)
|
||||
final tz.TZDateTime firstDate = now.isAfter(eventStart) ? now : eventStart;
|
||||
|
||||
final DateTime? picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: controller.selectedDate.value ?? controller.selectedEvent.value!.startDatetime,
|
||||
firstDate: controller.selectedEvent.value!.startDatetime,
|
||||
lastDate: controller.selectedEvent.value!.endDatetime,
|
||||
initialDate: initialDate.isAfter(firstDate) ? initialDate : firstDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: eventEnd,
|
||||
);
|
||||
if (picked != null) {
|
||||
controller.updateDate(picked);
|
||||
controller.updateDate(tz.TZDateTime.from(picked, tz.getLocation('Asia/Tokyo')));
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -96,6 +110,7 @@ class EntryDetailPage extends GetView<EntryController> {
|
||||
onPressed: () => controller.createEntry(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: Size(double.infinity, 50),
|
||||
),
|
||||
)
|
||||
@ -108,6 +123,7 @@ class EntryDetailPage extends GetView<EntryController> {
|
||||
onPressed: () => controller.deleteEntry(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: Size(0, 50),
|
||||
),
|
||||
),
|
||||
@ -119,6 +135,7 @@ class EntryDetailPage extends GetView<EntryController> {
|
||||
onPressed: () => controller.updateEntry(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.lightBlue,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: Size(0, 50),
|
||||
),
|
||||
),
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:rogapp/pages/entry/entry_controller.dart';
|
||||
import 'package:rogapp/routes/app_pages.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
|
||||
class EntryListPage extends GetView<EntryController> {
|
||||
@override
|
||||
@ -12,6 +13,12 @@ class EntryListPage extends GetView<EntryController> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('エントリー管理'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () => Get.toNamed(AppPages.ENTRY_DETAIL, arguments: {'mode': 'new'}),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Obx(() {
|
||||
if (controller.entries.isEmpty) {
|
||||
@ -54,7 +61,8 @@ class EntryListPage extends GetView<EntryController> {
|
||||
if (date == null) {
|
||||
return '日時未設定';
|
||||
}
|
||||
return DateFormat('yyyy-MM-dd').format(date);
|
||||
final jstDate = tz.TZDateTime.from(date, tz.getLocation('Asia/Tokyo'));
|
||||
return DateFormat('yyyy-MM-dd').format(jstDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@ import 'package:rogapp/pages/index/index_controller.dart';
|
||||
import 'package:rogapp/pages/destination/destination_controller.dart';
|
||||
import 'package:rogapp/services/api_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
|
||||
class EventEntriesController extends GetxController {
|
||||
final ApiService _apiService = Get.find<ApiService>();
|
||||
@ -14,9 +16,12 @@ class EventEntriesController extends GetxController {
|
||||
final filteredEntries = <Entry>[].obs;
|
||||
final showTodayEntries = true.obs;
|
||||
|
||||
static bool _timezoneInitialized = false;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_initializeTimezone();
|
||||
// DestinationControllerが登録されていない場合に備えて、lazyPutを使用
|
||||
Get.lazyPut<DestinationController>(() => DestinationController(), fenix: true);
|
||||
_destinationController = Get.find<DestinationController>();
|
||||
@ -24,6 +29,13 @@ class EventEntriesController extends GetxController {
|
||||
fetchEntries();
|
||||
}
|
||||
|
||||
void _initializeTimezone() {
|
||||
if (!_timezoneInitialized) {
|
||||
tz.initializeTimeZones();
|
||||
_timezoneInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchEntries() async {
|
||||
try {
|
||||
final fetchedEntries = await _apiService.getEntries();
|
||||
@ -44,6 +56,16 @@ class EventEntriesController extends GetxController {
|
||||
}
|
||||
|
||||
void filterEntriesForToday() {
|
||||
final now = tz.TZDateTime.now(tz.getLocation('Asia/Tokyo'));
|
||||
filteredEntries.assignAll(entries.where((entry) {
|
||||
final entryDate = tz.TZDateTime.from(entry.date!, tz.getLocation('Asia/Tokyo'));
|
||||
return entryDate.year == now.year &&
|
||||
entryDate.month == now.month &&
|
||||
entryDate.day == now.day;
|
||||
}));
|
||||
}
|
||||
|
||||
void filterEntriesForToday_old() {
|
||||
final now = DateTime.now();
|
||||
filteredEntries.assignAll(entries.where((entry) =>
|
||||
entry.date?.year == now.year &&
|
||||
@ -66,10 +88,12 @@ class EventEntriesController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> joinEvent(Entry entry) async {
|
||||
final now = DateTime.now();
|
||||
bool isToday = entry.date?.year == now.year &&
|
||||
entry.date?.month == now.month &&
|
||||
entry.date?.day == now.day;
|
||||
//final now = DateTime.now();
|
||||
final now = tz.TZDateTime.now(tz.getLocation('Asia/Tokyo'));
|
||||
final entryDate = tz.TZDateTime.from(entry.date!, tz.getLocation('Asia/Tokyo'));
|
||||
bool isToday = entryDate.year == now.year &&
|
||||
entryDate.month == now.month &&
|
||||
entryDate.day == now.day;
|
||||
|
||||
_indexController.setReferenceMode(!isToday);
|
||||
_indexController.setSelectedEventName(entry.event.eventName);
|
||||
@ -78,6 +102,7 @@ class EventEntriesController extends GetxController {
|
||||
|
||||
await _apiService.updateUserInfo(userid,entry);
|
||||
|
||||
_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;
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:rogapp/pages/entry/event_entries_controller.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
|
||||
class EventEntriesPage_old extends GetView<EventEntriesController> {
|
||||
@override
|
||||
@ -96,7 +97,8 @@ class EventEntriesPage extends GetView<EventEntriesController> {
|
||||
if (date == null) {
|
||||
return '日時未設定';
|
||||
}
|
||||
return DateFormat('yyyy-MM-dd').format(date);
|
||||
final jstDate = tz.TZDateTime.from(date, tz.getLocation('Asia/Tokyo'));
|
||||
return DateFormat('yyyy-MM-dd').format(jstDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,10 +23,14 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:rogapp/services/api_service.dart';
|
||||
import 'package:rogapp/model/user.dart';
|
||||
|
||||
import 'package:rogapp/model/rog.dart';
|
||||
|
||||
|
||||
import 'package:rogapp/main.dart';
|
||||
|
||||
import 'package:rogapp/widgets/helper_dialog.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
|
||||
class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
List<GeoJSONFeatureCollection> locations = <GeoJSONFeatureCollection>[].obs;
|
||||
@ -66,6 +70,7 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
//late final ApiService _apiService;
|
||||
final ApiService _apiService = Get.find<ApiService>();
|
||||
final DatabaseHelper _dbHelper = DatabaseHelper.instance;
|
||||
|
||||
// mode = 0 is map mode, mode = 1 list mode
|
||||
var mode = 0.obs;
|
||||
@ -237,6 +242,7 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
print('IndexController onInit called'); // デバッグ用の出力を追加
|
||||
|
||||
tz.initializeTimeZones();
|
||||
//teamController = Get.find<TeamController>();
|
||||
|
||||
}
|
||||
@ -489,7 +495,23 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
//
|
||||
void register(String email, String password, String password2, BuildContext context) {
|
||||
AuthService.register(email, password,password2).then((value) {
|
||||
if (value.isNotEmpty) {
|
||||
if (value is Map && value.containsKey("error")) {
|
||||
String err_message = value["error"];
|
||||
debugPrint("ユーザー登録失敗:${email}, ${password},${err_message}");
|
||||
logManager.addOperationLog("User failed to register new account : ${email} , ${password} ,${err_message}.");
|
||||
isLoading.value = false;
|
||||
Get.snackbar(
|
||||
'user_registration_failed_please_try_again'.tr, // ユーザー登録に失敗しました。
|
||||
err_message,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
|
||||
snackPosition: SnackPosition.TOP,
|
||||
duration: const Duration(seconds: 3),
|
||||
//backgroundColor: Colors.yellow,
|
||||
//icon:Image(image:AssetImage("assets/images/dora.png"))
|
||||
);
|
||||
}else{
|
||||
debugPrint("ユーザー登録成功:${email}, ${password}");
|
||||
logManager.addOperationLog("User tried to register new account : ${email} , ${password} .");
|
||||
|
||||
@ -508,22 +530,7 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
);
|
||||
|
||||
//Navigator.pop(context);
|
||||
Get.toNamed(AppPages.INDEX);
|
||||
} else {
|
||||
debugPrint("ユーザー登録失敗:${email}, ${password}");
|
||||
logManager.addOperationLog("User failed to register new account : ${email} , ${password} .");
|
||||
isLoading.value = false;
|
||||
Get.snackbar(
|
||||
'failed'.tr, // 失敗
|
||||
'user_registration_failed_please_try_again'.tr, // ユーザー登録に失敗しました。
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
icon: const Icon(Icons.error, size: 40.0, color: Colors.blue),
|
||||
snackPosition: SnackPosition.TOP,
|
||||
duration: const Duration(seconds: 3),
|
||||
//backgroundColor: Colors.yellow,
|
||||
//icon:Image(image:AssetImage("assets/images/dora.png"))
|
||||
);
|
||||
Get.toNamed(AppPages.LOGIN);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -561,6 +568,10 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
saveToDevice(currentUser[0]["token"]);
|
||||
}
|
||||
isLoading.value = false;
|
||||
|
||||
// ユーザーのイベント情報を取得
|
||||
await fetchUserEventInfo();
|
||||
|
||||
loadLocationsBound( currentUser[0]["user"]["event_code"]);
|
||||
if (currentUser.isNotEmpty) {
|
||||
rogMode.value = 0;
|
||||
@ -574,6 +585,58 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
Get.toNamed(AppPages.INDEX);
|
||||
}
|
||||
|
||||
Future<void> fetchUserEventInfo() async {
|
||||
try {
|
||||
final List<Entry> entries = await _apiService.getEntries();
|
||||
|
||||
if (entries.isNotEmpty) {
|
||||
final Entry latestEntry = entries.last;
|
||||
|
||||
final tokyo = tz.getLocation('Asia/Tokyo');
|
||||
final eventDate = latestEntry.date!.toUtc();
|
||||
//final eventDate = tz.TZDateTime.from(utcDate, tokyo);
|
||||
|
||||
final eventDateOnly = tz.TZDateTime(tokyo, eventDate.year, eventDate.month, eventDate.day);
|
||||
|
||||
currentUser[0]['user']['event_date'] = eventDateOnly.toIso8601String().split('T')[0];
|
||||
currentUser[0]['user']['event_code'] = latestEntry.event.eventName;
|
||||
currentUser[0]['user']['team_name'] = latestEntry.team.teamName;
|
||||
currentUser[0]['user']['group'] = latestEntry.team.category.categoryName;
|
||||
currentUser[0]['user']['zekken_number'] = latestEntry.zekkenNumber;
|
||||
|
||||
// 最後のゴール日時を取得
|
||||
final lastGoalTime = await getLastGoalTime();
|
||||
currentUser[0]['user']['last_goal_time'] = lastGoalTime?.toIso8601String();
|
||||
|
||||
print('Updated user event info: ${currentUser[0]['user']}');
|
||||
} else {
|
||||
print('No entries found for the user');
|
||||
_clearUserEventInfo();
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error fetching user event info: $e');
|
||||
_clearUserEventInfo();
|
||||
}
|
||||
}
|
||||
|
||||
Future<DateTime?> getLastGoalTime() async {
|
||||
try {
|
||||
final userId = currentUser[0]['user']['id'];
|
||||
return await _apiService.getLastGoalTime(userId);
|
||||
} catch (e) {
|
||||
print('Error getting last goal time: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _clearUserEventInfo() {
|
||||
currentUser[0]['user']['event_date'] = null;
|
||||
currentUser[0]['user']['event_code'] = null;
|
||||
currentUser[0]['user']['team_name'] = null;
|
||||
currentUser[0]['user']['group'] = null;
|
||||
currentUser[0]['user']['zekken_number'] = null;
|
||||
}
|
||||
|
||||
Future<void> fetchTeamData() async {
|
||||
try {
|
||||
Get.put(TeamController());
|
||||
@ -588,6 +651,8 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
loadUserDetailsForToken(String token) async {
|
||||
AuthService.userForToken(token).then((value) {
|
||||
print("----token val-- $value ------");
|
||||
|
||||
@ -36,24 +36,50 @@ class _IndexPageState extends State<IndexPage> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
//checkEntryAndShowHelper();
|
||||
//checkLoginAndShowDialog();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
void checkEntryAndShowHelper() async {
|
||||
final hasEntry = await checkIfUserHasEntry(); // この関数は実装する必要があります
|
||||
if (!hasEntry) {
|
||||
showHelperDialog(
|
||||
context,
|
||||
'イベントに参加するには、チーム登録・メンバー登録及びエントリーが必要になります。',
|
||||
'entry_helper',
|
||||
showDoNotShowAgain: true,
|
||||
void checkLoginAndShowDialog() {
|
||||
if (indexController.currentUser.isEmpty) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('ログインが必要です'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('1) ログインされていません。ロゲに参加するにはログインが必要です。'),
|
||||
SizedBox(height: 10),
|
||||
Text('2) ログイン後、個人情報入力、チーム登録、エントリー登録を行なってください。'),
|
||||
SizedBox(height: 10),
|
||||
Text('3) エントリー登録は場所と日にちごとに行なってください。'),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('キャンセル'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text('ログイン'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
Get.toNamed(AppPages.LOGIN);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// class IndexPage extends GetView<IndexController> {
|
||||
// IndexPage({Key? key}) : super(key: key);
|
||||
|
||||
@ -5,6 +5,8 @@ import 'package:rogapp/routes/app_pages.dart';
|
||||
import 'package:rogapp/widgets/helper_dialog.dart';
|
||||
import 'package:rogapp/services/api_service.dart';
|
||||
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
// 要検討:ログインボタンとサインアップボタンの配色を見直すことを検討してください。現在の配色では、ボタンの役割がわかりにくい可能性があります。
|
||||
// エラーメッセージをローカライズすることを検討してください。
|
||||
// ログイン処理中にエラーが発生した場合のエラーハンドリングを追加することをお勧めします。
|
||||
@ -22,6 +24,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
TextEditingController emailController = TextEditingController();
|
||||
TextEditingController passwordController = TextEditingController();
|
||||
bool _obscureText = true;
|
||||
String _version = ''; // バージョン情報を保持する変数
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -32,6 +35,15 @@ class _LoginPageState extends State<LoginPage> {
|
||||
'login_page'
|
||||
);
|
||||
});
|
||||
_getVersionInfo(); // バージョン情報を取得
|
||||
}
|
||||
|
||||
// バージョン情報を取得するメソッド
|
||||
Future<void> _getVersionInfo() async {
|
||||
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
setState(() {
|
||||
_version = packageInfo.version;
|
||||
});
|
||||
}
|
||||
|
||||
void _showResetPasswordDialog() {
|
||||
@ -124,6 +136,14 @@ class _LoginPageState extends State<LoginPage> {
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
// バージョン情報を表示
|
||||
Text(
|
||||
'Version: $_version',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
|
||||
@ -89,6 +89,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
ElevatedButton(
|
||||
onPressed: _handleRegister,
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.redAccent,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)),
|
||||
minimumSize: const Size(double.infinity, 60),
|
||||
@ -165,7 +166,7 @@ class _RegisterPageState extends State<RegisterPage> {
|
||||
context
|
||||
);
|
||||
// 登録が成功したと仮定し、ログインページに遷移
|
||||
Get.offNamed(AppPages.LOGIN);
|
||||
//Get.offNamed(AppPages.LOGIN);
|
||||
} catch (error) {
|
||||
_showErrorSnackbar("registration_error".tr, error.toString());
|
||||
} finally {
|
||||
|
||||
@ -91,6 +91,7 @@ class MemberController extends GetxController {
|
||||
lastname.value = value;
|
||||
}
|
||||
|
||||
|
||||
Future<bool> saveMember() async {
|
||||
if (!_validateInputs()) return false;
|
||||
|
||||
@ -139,8 +140,8 @@ class MemberController extends GetxController {
|
||||
return '${lastname.value} ${firstname.value}'.trim();
|
||||
}
|
||||
|
||||
Future<void> updateMember() async {
|
||||
if (member.value == null) return;
|
||||
Future<bool> updateMember() async {
|
||||
if (member.value == null) return false;
|
||||
int? memberId = member.value?.id;
|
||||
try {
|
||||
final updatedMember = await _apiService.updateTeamMember(
|
||||
@ -152,15 +153,17 @@ class MemberController extends GetxController {
|
||||
female.value,
|
||||
);
|
||||
member.value = updatedMember;
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error updating member: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteMember() async {
|
||||
Future<bool> deleteMember() async {
|
||||
if (member.value == null || member.value!.id == null) {
|
||||
Get.snackbar('エラー', 'メンバー情報が不正です', snackPosition: SnackPosition.BOTTOM);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
@ -168,11 +171,14 @@ class MemberController extends GetxController {
|
||||
await _apiService.deleteTeamMember(teamId, member.value!.id!);
|
||||
Get.snackbar('成功', 'メンバーが削除されました', snackPosition: SnackPosition.BOTTOM);
|
||||
member.value = null;
|
||||
isLoading.value = false;
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
print('Error deleting member: $e');
|
||||
Get.snackbar('エラー', 'メンバーの削除に失敗しました: ${e.toString()}', snackPosition: SnackPosition.BOTTOM);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,10 +257,10 @@ class MemberController extends GetxController {
|
||||
yearsFromSchoolStart--;
|
||||
}
|
||||
|
||||
if (yearsFromSchoolStart < 0) return '未就学';
|
||||
if (yearsFromSchoolStart < 6) return '小${yearsFromSchoolStart + 1}';
|
||||
if (yearsFromSchoolStart < 9) return '中${yearsFromSchoolStart - 5}';
|
||||
if (yearsFromSchoolStart < 12) return '高${yearsFromSchoolStart - 8}';
|
||||
if (yearsFromSchoolStart < 7) return '未就学';
|
||||
if (yearsFromSchoolStart < 13) return '小${yearsFromSchoolStart - 6}';
|
||||
if (yearsFromSchoolStart < 16) return '中${yearsFromSchoolStart - 12}';
|
||||
if (yearsFromSchoolStart < 19) return '高${yearsFromSchoolStart - 15}';
|
||||
return '成人';
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ import 'package:intl/intl.dart'; // この行を追加
|
||||
import 'package:flutter_localizations/flutter_localizations.dart'; // 追加
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import 'package:rogapp/routes/app_pages.dart';
|
||||
|
||||
class MemberDetailPage extends StatefulWidget {
|
||||
@override
|
||||
_MemberDetailPageState createState() => _MemberDetailPageState();
|
||||
@ -34,15 +36,18 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
}
|
||||
|
||||
void _initializeControllers() {
|
||||
_firstNameController = TextEditingController(text: controller.firstname.value);
|
||||
_lastNameController = TextEditingController(text: controller.lastname.value);
|
||||
_firstNameController =
|
||||
TextEditingController(text: controller.firstname.value);
|
||||
_lastNameController =
|
||||
TextEditingController(text: controller.lastname.value);
|
||||
_emailController = TextEditingController(text: controller.email.value);
|
||||
|
||||
controller.firstname.listen((value) {
|
||||
if (_firstNameController.text != value) {
|
||||
_firstNameController.value = TextEditingValue(
|
||||
text: value,
|
||||
selection: TextSelection.fromPosition(TextPosition(offset: value.length)),
|
||||
selection: TextSelection.fromPosition(
|
||||
TextPosition(offset: value.length)),
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -51,7 +56,8 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
if (_lastNameController.text != value) {
|
||||
_lastNameController.value = TextEditingValue(
|
||||
text: value,
|
||||
selection: TextSelection.fromPosition(TextPosition(offset: value.length)),
|
||||
selection: TextSelection.fromPosition(
|
||||
TextPosition(offset: value.length)),
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -60,12 +66,71 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
if (_emailController.text != value) {
|
||||
_emailController.value = TextEditingValue(
|
||||
text: value,
|
||||
selection: TextSelection.fromPosition(TextPosition(offset: value.length)),
|
||||
selection: TextSelection.fromPosition(
|
||||
TextPosition(offset: value.length)),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _handleSaveAndNavigateBack() async {
|
||||
bool success = await controller.saveMember();
|
||||
if (success) {
|
||||
Get.until((route) => Get.currentRoute == AppPages.TEAM_DETAIL);
|
||||
// スナックバーが表示されるのを待つ
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
|
||||
// 現在のスナックバーを安全に閉じる
|
||||
if (Get.isSnackbarOpen) {
|
||||
await Get.closeCurrentSnackbar();
|
||||
}
|
||||
|
||||
// リストページに戻る
|
||||
//Get.until((route) => Get.currentRoute == '/team');
|
||||
// または、リストページの具体的なルート名がある場合は以下を使用
|
||||
// Get.offNamed('/team');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> _handleDeleteAndNavigateBack() async {
|
||||
final confirmed = await Get.dialog<bool>(
|
||||
AlertDialog(
|
||||
title: Text('確認'),
|
||||
content: Text('このメンバーを削除してもよろしいですか?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('キャンセル'),
|
||||
onPressed: () => Get.back(result: false),
|
||||
),
|
||||
TextButton(
|
||||
child: Text('削除'),
|
||||
onPressed: () => Get.back(result: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (confirmed == true) {
|
||||
bool success = await controller.deleteMember();
|
||||
if (success) {
|
||||
// リストページに戻る
|
||||
//Get.offNamed(result: true);
|
||||
Get.until((route) => Get.currentRoute == AppPages.TEAM_DETAIL);
|
||||
|
||||
// スナックバーが表示されるのを待つ
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
|
||||
// 現在のスナックバーを安全に閉じる
|
||||
if (Get.isSnackbarOpen) {
|
||||
await Get.closeCurrentSnackbar();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final mode = Get.arguments['mode'] as String;
|
||||
@ -109,17 +174,9 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
children: [
|
||||
if (mode == 'new')
|
||||
TextFormField(
|
||||
controller: _emailController,
|
||||
onChanged: (value) => controller.updateEmail(value),
|
||||
decoration: InputDecoration(labelText: 'メールアドレス'),
|
||||
//onChanged: (value) => controller.email.value = value,
|
||||
onChanged: (value) {
|
||||
controller.email.value = value;
|
||||
// カーソル位置を更新
|
||||
emailController.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: value.length),
|
||||
);
|
||||
},
|
||||
controller: emailController,
|
||||
//controller: TextEditingController(text: controller.email.value),
|
||||
keyboardType: TextInputType.emailAddress, // メールアドレス用のキーボードを表示
|
||||
autocorrect: false, // 自動修正を無効化
|
||||
enableSuggestions: false,
|
||||
@ -129,16 +186,20 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
else
|
||||
Text('メールアドレス: ${controller.email.value}'),
|
||||
|
||||
if (controller.email.value.isEmpty || mode == 'edit') ...[
|
||||
if (controller.email.value.isEmpty || controller.isDummyEmail || mode == 'edit') ...[
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: '姓'),
|
||||
onChanged: (value) => controller.lastname.value = value,
|
||||
controller: TextEditingController(text: controller.lastname.value),
|
||||
controller: _lastNameController,
|
||||
onChanged: (value) => controller.updateLastName(value),
|
||||
|
||||
//controller: TextEditingController(text: controller.lastname.value),
|
||||
),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: '名'),
|
||||
onChanged: (value) => controller.firstname.value = value,
|
||||
controller: TextEditingController(text: controller.firstname.value),
|
||||
controller: _firstNameController,
|
||||
//onChanged: (value) => controller.firstname.value = value,
|
||||
onChanged: (value) => controller.updateFirstName(value),
|
||||
//controller: TextEditingController(text: controller.firstname.value),
|
||||
),
|
||||
// 生年月日
|
||||
if (controller.isDummyEmail || !controller.isOver18())
|
||||
@ -178,28 +239,7 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
children: [
|
||||
ElevatedButton(
|
||||
child: Text('削除'),
|
||||
onPressed: () async {
|
||||
final confirmed = await Get.dialog<bool>(
|
||||
AlertDialog(
|
||||
title: Text('確認'),
|
||||
content: Text('このメンバーを削除してもよろしいですか?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('キャンセル'),
|
||||
onPressed: () => Get.back(result: false),
|
||||
),
|
||||
TextButton(
|
||||
child: Text('削除'),
|
||||
onPressed: () => Get.back(result: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (confirmed == true) {
|
||||
await controller.deleteMember();
|
||||
Get.back(result: true);
|
||||
}
|
||||
},
|
||||
onPressed: _handleDeleteAndNavigateBack,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
@ -216,10 +256,7 @@ class _MemberDetailPageState extends State<MemberDetailPage> {
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text('保存・招待'),
|
||||
onPressed: () async {
|
||||
await controller.saveMember();
|
||||
Get.back(result: true);
|
||||
},
|
||||
onPressed: _handleSaveAndNavigateBack,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
|
||||
@ -175,9 +175,9 @@ class _TeamDetailPageState extends State<TeamDetailPage> {
|
||||
AppPages.MEMBER_DETAIL,
|
||||
arguments: {'mode': 'edit', 'member': member, 'teamId': controller.selectedTeam.value?.id},
|
||||
);
|
||||
if (result == true) {
|
||||
await controller.fetchTeamMembers(controller.selectedTeam.value!.id);
|
||||
}
|
||||
|
||||
await controller.fetchTeamMembers(controller.selectedTeam.value!.id);
|
||||
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@ -363,7 +363,7 @@ class ApiService extends GetxService{
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final decodedResponse = utf8.decode(response.bodyBytes);
|
||||
return User.fromJson(json.decode(decodedResponse));
|
||||
} else {
|
||||
@ -511,6 +511,8 @@ class ApiService extends GetxService{
|
||||
|
||||
return Entry.fromJson(json.decode(decodedResponse));
|
||||
} else {
|
||||
final decodedResponse = utf8.decode(response.bodyBytes);
|
||||
print("decodedResponse = $decodedResponse");
|
||||
throw Exception('Failed to create entry');
|
||||
}
|
||||
}
|
||||
@ -552,7 +554,7 @@ class ApiService extends GetxService{
|
||||
}
|
||||
|
||||
|
||||
Future<Entry> updateEntry(int entryId, int teamId, int eventId, int categoryId, DateTime date) async {
|
||||
Future<Entry> updateEntry(int entryId, int teamId, int eventId, int categoryId, DateTime date,int zekken_number) async {
|
||||
init();
|
||||
getToken();
|
||||
|
||||
@ -572,6 +574,7 @@ class ApiService extends GetxService{
|
||||
'event': eventId,
|
||||
'category': categoryId,
|
||||
'date': formattedDate,
|
||||
'zekken_number': zekken_number,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -580,6 +583,9 @@ class ApiService extends GetxService{
|
||||
|
||||
return Entry.fromJson(json.decode(decodedResponse));
|
||||
} else {
|
||||
final decodedResponse = utf8.decode(response.bodyBytes);
|
||||
final blk = json.decode(decodedResponse);
|
||||
|
||||
throw Exception('Failed to update entry');
|
||||
}
|
||||
}
|
||||
@ -659,4 +665,29 @@ class ApiService extends GetxService{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<DateTime?> getLastGoalTime(int userId) async {
|
||||
try {
|
||||
final response = await http.get(
|
||||
Uri.parse('$baseUrl/users/$userId/last-goal/'),
|
||||
headers: {
|
||||
'Authorization': 'Token $token',
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decodedResponse = json.decode(utf8.decode(response.bodyBytes));
|
||||
if (decodedResponse['last_goal_time'] != null) {
|
||||
return DateTime.parse(decodedResponse['last_goal_time']).toLocal();
|
||||
}
|
||||
} else {
|
||||
print('Failed to get last goal time. Status code: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error in getLastGoalTime: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -164,9 +164,10 @@ class AuthService {
|
||||
},
|
||||
body: jsonEncode(<String, String>{'email': email, 'password': password, 'password2': password2}),
|
||||
);
|
||||
//print(response.body);
|
||||
cats = json.decode(utf8.decode(response.bodyBytes));
|
||||
print("result=$cats");
|
||||
if (response.statusCode == 201) {
|
||||
cats = json.decode(utf8.decode(response.bodyBytes));
|
||||
}else{
|
||||
}
|
||||
return cats;
|
||||
}
|
||||
|
||||
@ -202,6 +202,7 @@ class ExternalService {
|
||||
colorText: Colors.white
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
Get.snackbar("サーバーエラーがおきました", "サーバーと通信できませんでした",
|
||||
@ -273,7 +274,8 @@ class ExternalService {
|
||||
Get.find<DestinationController>();
|
||||
|
||||
// チームIDを取得
|
||||
int teamId = indexController.currentUser[0]["user"]["team"]["id"];
|
||||
|
||||
//int teamId = indexController.currentUser[0]["user"]["team"]["id"];
|
||||
|
||||
debugPrint("== goal Rogaining ==");
|
||||
|
||||
@ -283,7 +285,7 @@ class ExternalService {
|
||||
id: 1,
|
||||
team_name: teamname,
|
||||
event_code: eventcode,
|
||||
user_id: teamId, //userId,
|
||||
user_id: userId, // 中身はteamid
|
||||
cp_number: -1,
|
||||
checkintime: DateTime.now().toUtc().microsecondsSinceEpoch,
|
||||
image: image,
|
||||
@ -305,7 +307,7 @@ class ExternalService {
|
||||
},
|
||||
// 'id', 'user', 'goalimage', 'goaltime', 'team_name', 'event_code','cp_number'
|
||||
body: jsonEncode(<String, String>{
|
||||
'user': teamId.toString(), //userId.toString(),
|
||||
'user': userId.toString(), //userId.toString(),
|
||||
'team_name': teamname,
|
||||
'event_code': eventcode,
|
||||
'goaltime': goalTime,
|
||||
@ -318,34 +320,42 @@ class ExternalService {
|
||||
String url = '$serverUrl/gifuroge/goal_from_rogapp';
|
||||
//print('++++++++$url');
|
||||
if (response.statusCode == 201) {
|
||||
Map<String, dynamic> res = json.decode(utf8.decode(response.bodyBytes));
|
||||
// print('----_res : $res ----');
|
||||
// print('---- image url ${res["goalimage"]} ----');
|
||||
final http.Response response2 = await http.post(
|
||||
Uri.parse(url),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
},
|
||||
body: jsonEncode(<String, String>{
|
||||
try {
|
||||
Map<String, dynamic> res = json.decode(utf8.decode(response.bodyBytes));
|
||||
// print('----_res : $res ----');
|
||||
// print('---- image url ${res["goalimage"]} ----');
|
||||
final http.Response response2 = await http.post(
|
||||
Uri.parse(url),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
},
|
||||
body: jsonEncode(<String, String>{
|
||||
'team_name': teamname,
|
||||
'event_code': eventcode,
|
||||
'goal_time': goalTime,
|
||||
'image': res["goalimage"].toString().replaceAll(
|
||||
'http://localhost:8100', serverUrl)
|
||||
//'http://rogaining.sumasen.net')
|
||||
}),
|
||||
);
|
||||
String rec = jsonEncode(<String, String>{
|
||||
'team_name': teamname,
|
||||
'event_code': eventcode,
|
||||
'goal_time': goalTime,
|
||||
'image': res["goalimage"].toString().replaceAll(
|
||||
'http://localhost:8100', serverUrl) //'http://rogaining.sumasen.net')
|
||||
}),
|
||||
);
|
||||
String rec = jsonEncode(<String, String>{
|
||||
'team_name': teamname,
|
||||
'event_code': eventcode,
|
||||
'goal_time': goalTime,
|
||||
'image': res["goalimage"]
|
||||
.toString()
|
||||
.replaceAll('http://localhost:8100', serverUrl) //'http://rogaining.sumasen.net')
|
||||
});
|
||||
//print("-- json -- $rec");
|
||||
//print('----- response2 is $response2 --------');
|
||||
if (response2.statusCode == 200) {
|
||||
res2 = json.decode(utf8.decode(response2.bodyBytes));
|
||||
'image': res["goalimage"]
|
||||
.toString()
|
||||
.replaceAll('http://localhost:8100', serverUrl)
|
||||
//'http://rogaining.sumasen.net')
|
||||
});
|
||||
//print("-- json -- $rec");
|
||||
//print('----- response2 is $response2 --------');
|
||||
if (response2.statusCode == 200) {
|
||||
res2 = json.decode(utf8.decode(response2.bodyBytes));
|
||||
} else {
|
||||
res2 = json.decode(utf8.decode(response2.bodyBytes));
|
||||
}
|
||||
} catch(e){
|
||||
print( "Error {$e}" );
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
@ -122,10 +122,10 @@ class LocationService {
|
||||
var grp = event_code; //indexController.currentUser[0]['user']['event_code'];
|
||||
print("Group=$grp");
|
||||
url =
|
||||
'$serverUrl/api/inbound?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat';
|
||||
'$serverUrl/api/inbound2?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat';
|
||||
} else {
|
||||
url =
|
||||
'$serverUrl/api/inbound?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat';
|
||||
'$serverUrl/api/inbound2?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4&cat=$cat';
|
||||
}
|
||||
} else {
|
||||
if (indexController.currentUser.isNotEmpty) {
|
||||
@ -134,10 +134,10 @@ class LocationService {
|
||||
var grp = indexController.currentUser[0]['user']['event_code'];
|
||||
print("-------- requested user group $grp -------------");
|
||||
url =
|
||||
'$serverUrl/api/inbound?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4';
|
||||
'$serverUrl/api/inbound2?rog=$r&grp=$grp&ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4';
|
||||
} else {
|
||||
url =
|
||||
'$serverUrl/api/inbound?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4';
|
||||
'$serverUrl/api/inbound2?ln1=$lon1&la1=$lat1&ln2=$lon2&la2=$lat2&ln3=$lon3&la3=$lat3&ln4=$lon4&la4=$lat4';
|
||||
}
|
||||
print('++++++++$url');
|
||||
final response = await http.get(
|
||||
|
||||
@ -21,6 +21,10 @@ import 'package:rogapp/widgets/bottom_sheet_controller.dart';
|
||||
import 'package:rogapp/widgets/debug_widget.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
import 'package:get/get.dart';
|
||||
|
||||
// BottomSheetNewは、StatelessWidgetを継承したクラスで、目的地の詳細情報を表示するボトムシートのUIを構築します。
|
||||
// コンストラクタでは、destination(目的地オブジェクト)とisAlreadyCheckedIn(すでにチェックイン済みかどうかのフラグ)を受け取ります。
|
||||
// buildメソッドでは、detailsSheetメソッドを呼び出して、目的地の詳細情報を表示します。
|
||||
@ -38,6 +42,15 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
|
||||
final RxBool isButtonDisabled = false.obs;
|
||||
|
||||
static bool _timezoneInitialized = false;
|
||||
|
||||
void _initializeTimezone() {
|
||||
if (!_timezoneInitialized) {
|
||||
tz.initializeTimeZones();
|
||||
_timezoneInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 目的地の画像を取得するためのメソッドです。
|
||||
// indexController.rogModeの値に基づいて、適切な画像を返します。画像が見つからない場合は、デフォルトの画像を返します。
|
||||
//
|
||||
@ -146,6 +159,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
// ボタンがタップされたときの処理も含まれています。
|
||||
//
|
||||
Widget getActionButton(BuildContext context, Destination destination) {
|
||||
_initializeTimezone(); // タイムゾーンの初期化
|
||||
/*
|
||||
debugPrint("getActionButton ${destinationController.rogainingCounted.value}");
|
||||
debugPrint("getActionButton ${destinationController.distanceToStart()}");
|
||||
@ -181,6 +195,51 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
onPressed: destinationController.isInRog.value
|
||||
? null
|
||||
: () async {
|
||||
// Check if the event is for today
|
||||
bool isEventToday = await checkIfEventIsToday();
|
||||
if (!isEventToday) {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: Text("警告"),
|
||||
content: Text("参加したエントリーは別日のものですので、ロゲの開始はできません。当日のエントリーを選択するか、エントリーを今日に変更してからロゲ開始を行ってください。"),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: Text("OK"),
|
||||
onPressed: () {
|
||||
Get.back(); // Close the dialog
|
||||
Get.back(); // Close the bottom sheet
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user has already completed a rogaining event today
|
||||
bool hasCompletedToday = await checkIfCompletedToday();
|
||||
if (hasCompletedToday) {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: Text("警告"),
|
||||
content: Text("すでにロゲの参加を行いゴールをしています。ロゲは1日1回に制限されています。ご了承ください。"),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: Text("OK"),
|
||||
onPressed: () {
|
||||
Get.back(); // Close the dialog
|
||||
Get.back(); // Close the bottom sheet
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
destinationController.isInRog.value = true;
|
||||
|
||||
|
||||
@ -250,12 +309,17 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
//goal
|
||||
|
||||
return ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.red
|
||||
),
|
||||
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(
|
||||
@ -318,7 +382,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
? "in_game".tr
|
||||
: isAlreadyCheckedIn == true
|
||||
? "in_game".tr
|
||||
: destinationController.isInRog.value == true
|
||||
: (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),
|
||||
@ -328,6 +392,62 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
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] != null &&
|
||||
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: Text('エラー'),
|
||||
content: Text('イベント日付の確認中にエラーが発生しました。\nアプリを再起動するか、管理者にお問い合わせください。'),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: 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) {
|
||||
@ -444,7 +564,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
//checkin or remove checkin
|
||||
destinationController.isInRog.value == true
|
||||
(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
|
||||
|
||||
@ -92,6 +92,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
|
||||
//LoginPage({Key? key}) : super(key: key);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
||||
@ -1266,6 +1266,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
timezone:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4"
|
||||
transparent_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 4.8.6+486
|
||||
version: 4.8.17+497
|
||||
|
||||
environment:
|
||||
sdk: ">=3.2.0 <4.0.0"
|
||||
@ -41,6 +41,7 @@ dependencies:
|
||||
geolocator: ^10.1.0
|
||||
permission_handler: ^11.3.1
|
||||
logging: ^1.0.2
|
||||
timezone: ^0.9.1
|
||||
|
||||
# flutter_dev_tools: ^0.0.2
|
||||
# permission_handler: ^11.1.0 <== older
|
||||
|
||||
Reference in New Issue
Block a user