From afa7401f9495f4069d6d515bd18984401ddefbc3 Mon Sep 17 00:00:00 2001 From: seigibus Date: Sun, 28 May 2023 14:48:56 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E9=85=8D=E5=88=97=E3=81=AE=E8=A6=81?= =?UTF-8?q?=E7=B4=A0=E5=A4=89=E6=9B=B4=E3=81=99=E3=82=8B=E3=83=A1=E3=82=BD?= =?UTF-8?q?=E3=83=83=E3=83=89=E3=82=92=E7=B4=94=E9=96=A2=E6=95=B0=E3=81=AB?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/trip_belonging_controller.dart | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/features/trips/controller/trip_belonging_controller.dart b/lib/features/trips/controller/trip_belonging_controller.dart index fcd908ce..8f149e1a 100644 --- a/lib/features/trips/controller/trip_belonging_controller.dart +++ b/lib/features/trips/controller/trip_belonging_controller.dart @@ -42,17 +42,15 @@ class TripBelongingsController extends _$TripBelongingsController { .read(tripInteractorProvider) .changeBelongingCheckStatus(belonging: belonging); - _changeSome(result); + state = AsyncValue.data(_changeSome(result)); } - void _changeSome(AddedTripBelonging newBelonging) { - state = AsyncValue.data( - state.value?.map( - (belonging) { - return belonging.id == newBelonging.id ? newBelonging : belonging; - }, - ).toList() ?? - [], - ); + List _changeSome(AddedTripBelonging newBelonging) { + return state.value?.map( + (belonging) { + return belonging.id == newBelonging.id ? newBelonging : belonging; + }, + ).toList() ?? + []; } } From f5e4a959d82eabf83d5b51e16189a5679638f905 Mon Sep 17 00:00:00 2001 From: seigibus Date: Sun, 28 May 2023 14:50:26 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=8C=81=E3=81=A1=E7=89=A9?= =?UTF-8?q?=E4=B8=80=E8=A6=A7=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AEUI?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/trips/trip_belonging_item.dart | 228 ++++++++++++++++++ .../widgets/trips/trip_belonging_list.dart | 38 ++- 2 files changed, 242 insertions(+), 24 deletions(-) create mode 100644 lib/view/widgets/trips/trip_belonging_item.dart diff --git a/lib/view/widgets/trips/trip_belonging_item.dart b/lib/view/widgets/trips/trip_belonging_item.dart new file mode 100644 index 00000000..3b04d74d --- /dev/null +++ b/lib/view/widgets/trips/trip_belonging_item.dart @@ -0,0 +1,228 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:trip_app_nativeapp/core/extensions/build_context.dart'; +import 'package:trip_app_nativeapp/features/trips/controller/trip_belonging_controller.dart'; +import 'package:trip_app_nativeapp/features/trips/domain/entity/trip/trip_belonging.dart'; + +class TripBelongingItem extends HookConsumerWidget { + const TripBelongingItem({ + required this.tripId, + required this.belonging, + super.key, + }); + + final int tripId; + final AddedTripBelonging belonging; + @override + Widget build(BuildContext context, WidgetRef ref) { + final isEditMode = useState(false); + final nameEditingController = + useTextEditingController(text: belonging.name.value); + final numOfEditingController = + useTextEditingController(text: belonging.numOf.value.toString()); + + return GestureDetector( + onTap: () { + if (isEditMode.value) return; + ref + .read(tripBelongingsControllerProvider(tripId: tripId).notifier) + .changeCheckStatus(belonging); + }, + onLongPress: () => isEditMode.value = true, + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: context.theme.dividerColor, + ), + ), + ), + child: Column( + children: [ + Row( + children: [ + _LeadingArea( + isChecked: belonging.isChecked, + isEditMode: isEditMode.value, + onDelete: () { + // TODO(seigi0714): controllerのdeleteメソッド呼び出し + }, + ), + const Gap(8), + Expanded( + child: _NameField( + controller: nameEditingController, + isEditMode: isEditMode.value, + ), + ), + const Gap(8), + SizedBox( + width: 42, + child: Row( + children: [ + _NumOfField( + isEditMode: isEditMode.value, + controller: numOfEditingController, + ), + ], + ), + ), + ], + ), + if (isEditMode.value) + _ActionButtonRow( + onClose: () { + nameEditingController.text = belonging.name.value; + numOfEditingController.text = + belonging.numOf.value.toString(); + isEditMode.value = false; + }, + onUpdate: () { + isEditMode.value = false; + // TODO(seigi0714): controllerのupdateメソッド呼び出し + }, + ), + ], + ), + ), + ); + } +} + +class _LeadingArea extends StatelessWidget { + const _LeadingArea({ + required this.isChecked, + required this.isEditMode, + required this.onDelete, + }); + + final bool isChecked; + final bool isEditMode; + final void Function() onDelete; + + @override + Widget build(BuildContext context) { + if (isEditMode) { + return IconButton( + onPressed: onDelete, + icon: Icon( + Icons.delete, + color: context.theme.colorScheme.error, + ), + ); + } else { + return Icon( + isChecked ? Icons.check_circle_outline : Icons.circle_outlined, + color: isChecked + ? context.theme.primaryColor + : context.theme.unselectedWidgetColor, + ); + } + } +} + +class _NameField extends StatelessWidget { + const _NameField({required this.controller, required this.isEditMode}); + final TextEditingController controller; + final bool isEditMode; + @override + Widget build(BuildContext context) { + return isEditMode + ? TextField( + controller: controller, + style: context.textTheme.titleMedium, + ) + : Text(controller.text, style: context.textTheme.titleMedium); + } +} + +class _NumOfField extends StatelessWidget { + const _NumOfField({required this.controller, required this.isEditMode}); + final TextEditingController controller; + final bool isEditMode; + @override + Widget build(BuildContext context) { + return SizedBox( + width: 42, + child: Row( + children: [ + Text( + 'x', + style: context.textTheme.labelMedium, + ), + if (isEditMode) + SizedBox( + width: 24, + child: TextField( + decoration: const InputDecoration( + contentPadding: EdgeInsets.zero, + ), + controller: controller, + keyboardType: TextInputType.number, + style: context.textTheme.labelMedium, + ), + ) + else + Text( + controller.text, + style: context.textTheme.labelMedium, + ), + ], + ), + ); + } +} + +class _ActionButtonRow extends StatelessWidget { + const _ActionButtonRow({ + required this.onClose, + required this.onUpdate, + }); + + final void Function() onUpdate; + final void Function() onClose; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton( + style: ButtonStyle( + padding: MaterialStateProperty.all( + const EdgeInsets.only(top: 8), + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + iconSize: 28, + onPressed: onClose, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + icon: Icon( + Icons.highlight_off, + color: context.theme.colorScheme.error, + ), + ), + IconButton( + style: ButtonStyle( + padding: MaterialStateProperty.all( + const EdgeInsets.only(top: 8, right: 8), + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + iconSize: 28, + onPressed: onUpdate, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + icon: Icon( + Icons.check_circle, + color: context.theme.primaryColor, + ), + ), + ], + ); + } +} diff --git a/lib/view/widgets/trips/trip_belonging_list.dart b/lib/view/widgets/trips/trip_belonging_list.dart index fd834bfc..f5425eb5 100644 --- a/lib/view/widgets/trips/trip_belonging_list.dart +++ b/lib/view/widgets/trips/trip_belonging_list.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:trip_app_nativeapp/core/extensions/build_context.dart'; import 'package:trip_app_nativeapp/features/trips/controller/trip_belonging_controller.dart'; import 'package:trip_app_nativeapp/view/widgets/common/car_driving_loading.dart'; import 'package:trip_app_nativeapp/view/widgets/common/error_cat.dart'; import 'package:trip_app_nativeapp/view/widgets/trips/add_trip_belonging_sheet.dart'; +import 'package:trip_app_nativeapp/view/widgets/trips/trip_belonging_item.dart'; class TripBelongingList extends HookConsumerWidget { const TripBelongingList(this.tripId, {super.key}); @@ -20,35 +20,25 @@ class TripBelongingList extends HookConsumerWidget { child: ListView.builder( itemCount: belongings.length, itemBuilder: (BuildContext context, int index) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'isCheck: ${belongings[index].isChecked} ', - style: context.textTheme.titleSmall, - ), - Text( - belongings[index].name.value, - style: context.textTheme.titleMedium, - ), - Text( - ' isShare: ${belongings[index].isShareAmongMember}', - style: context.textTheme.titleSmall, - ), - ], + return TripBelongingItem( + tripId: tripId, + belonging: belongings[index], ); }, ), ), - Padding( + Container( + width: 52, padding: const EdgeInsets.all(8), - child: FloatingActionButton( - onPressed: () => showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) => AddTripBelongingSheet(tripId), + child: FittedBox( + child: FloatingActionButton( + onPressed: () => showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => AddTripBelongingSheet(tripId), + ), + child: const Icon(Icons.add, color: Colors.white), ), - child: const Icon(Icons.add, color: Colors.white), ), ), ],