168 lines
6.8 KiB
Dart
168 lines
6.8 KiB
Dart
// lib/pages/entry/entry_detail_page.dart
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:rogapp/pages/entry/entry_controller.dart';
|
|
import 'package:rogapp/model/event.dart';
|
|
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) {
|
|
final Map<String, dynamic> arguments = Get.arguments ?? {};
|
|
final mode = Get.arguments['mode'] as String? ?? 'new';
|
|
final entry = Get.arguments['entry'];
|
|
|
|
if (mode == 'edit' && entry != null) {
|
|
controller.initializeEditMode(entry);
|
|
}
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(mode == 'new' ? 'エントリー登録' : 'エントリー詳細'),
|
|
),
|
|
body: Obx(() {
|
|
if (controller.isLoading.value) {
|
|
return Center(child: CircularProgressIndicator());
|
|
}
|
|
return Padding(
|
|
padding: EdgeInsets.all(16.0),
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_buildDropdown<Event>(
|
|
label: 'イベント',
|
|
items: controller.events,
|
|
selectedId: controller.selectedEvent.value?.id,
|
|
onChanged: (eventId) => controller.updateEvent(
|
|
controller.events.firstWhere((e) => e.id == eventId)
|
|
),
|
|
getDisplayName: (event) => event.eventName,
|
|
getId: (event) => event.id,
|
|
),
|
|
SizedBox(height: 16),
|
|
_buildDropdown<Team>(
|
|
label: 'チーム',
|
|
items: controller.teams,
|
|
selectedId: controller.selectedTeam.value?.id,
|
|
onChanged: (teamId) => controller.updateTeam(
|
|
controller.teams.firstWhere((t) => t.id == teamId)
|
|
),
|
|
getDisplayName: (team) => team.teamName,
|
|
getId: (team) => team.id,
|
|
),
|
|
SizedBox(height: 16),
|
|
_buildDropdown<NewCategory>(
|
|
label: 'カテゴリ',
|
|
items: controller.categories,
|
|
selectedId: controller.selectedCategory.value?.id,
|
|
onChanged: (categoryId) => controller.updateCategory(
|
|
controller.categories.firstWhere((c) => c.id == categoryId)
|
|
),
|
|
getDisplayName: (category) => category.categoryName,
|
|
getId: (category) => category.id,
|
|
),
|
|
SizedBox(height: 16),
|
|
ListTile(
|
|
title: Text('日付'),
|
|
subtitle: Text(
|
|
controller.selectedDate.value != null
|
|
? DateFormat('yyyy-MM-dd').format(tz.TZDateTime.from(controller.selectedDate.value!, tz.getLocation('Asia/Tokyo')))
|
|
: '日付を選択してください',
|
|
),
|
|
onTap: () async {
|
|
if (controller.selectedEvent.value == null) {
|
|
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 DateTime? picked = await showDatePicker(
|
|
context: context,
|
|
initialDate: initialDate,
|
|
firstDate: eventStart,
|
|
lastDate: eventEnd,
|
|
);
|
|
if (picked != null) {
|
|
controller.updateDate(tz.TZDateTime.from(picked, tz.getLocation('Asia/Tokyo')));
|
|
}
|
|
},
|
|
),
|
|
SizedBox(height: 32),
|
|
if (mode == 'new')
|
|
ElevatedButton(
|
|
child: Text('エントリーを作成'),
|
|
onPressed: () => controller.createEntry(),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.blue,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: Size(double.infinity, 50),
|
|
),
|
|
)
|
|
else
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: ElevatedButton(
|
|
child: Text('エントリーを削除'),
|
|
onPressed: () => controller.deleteEntry(),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.red,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: Size(0, 50),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 16),
|
|
Expanded(
|
|
child: ElevatedButton(
|
|
child: Text('エントリーを更新'),
|
|
onPressed: () => controller.updateEntry(),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.lightBlue,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: Size(0, 50),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
Widget _buildDropdown<T>({
|
|
required String label,
|
|
required List<T> items,
|
|
required int? selectedId,
|
|
required void Function(int?) onChanged,
|
|
required String Function(T) getDisplayName,
|
|
required int Function(T) getId,
|
|
}) {
|
|
return DropdownButtonFormField<int>(
|
|
decoration: InputDecoration(labelText: label),
|
|
value: selectedId,
|
|
items: items.map((item) => DropdownMenuItem<int>(
|
|
value: getId(item),
|
|
child: Text(getDisplayName(item)),
|
|
)).toList(),
|
|
onChanged: onChanged,
|
|
);
|
|
}
|
|
} |