-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #112 from seigi0714/feature/add_belonging
持ち物追加処理を実装
- Loading branch information
Showing
5 changed files
with
402 additions
and
6 deletions.
There are no files selected for viewing
30 changes: 27 additions & 3 deletions
30
lib/features/trips/controller/trip_belonging_controller.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,39 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||
import 'package:trip_app_nativeapp/core/exception/exception_handler.dart'; | ||
import 'package:trip_app_nativeapp/features/trips/domain/entity/trip/trip_belonging.dart'; | ||
import 'package:trip_app_nativeapp/features/trips/domain/interactor/trip_interactor.dart'; | ||
import 'package:trip_app_nativeapp/view/widgets/common/loading.dart'; | ||
|
||
part 'trip_belonging_controller.g.dart'; | ||
|
||
@riverpod | ||
class TripBelongingsController extends _$TripBelongingsController { | ||
@override | ||
FutureOr<List<AddedTripBelonging>> build({required int tripId}) async { | ||
return ref | ||
.read(tripInteractorProvider) | ||
.fetchTripBelongings(tripId); | ||
return ref.read(tripInteractorProvider).fetchTripBelongings(tripId); | ||
} | ||
|
||
Future<void> addBelonging({ | ||
required int tripId, | ||
required String name, | ||
required int numOf, | ||
required bool isShareAmongMember, | ||
VoidCallback? onFinished, | ||
}) async { | ||
try { | ||
final result = await ref.read(tripInteractorProvider).addTripBelonging( | ||
tripId: tripId, | ||
name: name, | ||
numOf: numOf, | ||
isShareAmongMember: isShareAmongMember, | ||
); | ||
state = AsyncValue.data([result, ...state.value ?? []]); | ||
} on Exception catch (e) { | ||
ref.read(exceptionHandlerProvider).handleException(e); | ||
} finally { | ||
ref.read(overlayLoadingProvider.notifier).endLoading(); | ||
onFinished?.call(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_hooks/flutter_hooks.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'; | ||
|
||
class AddTripBelongingSheet extends HookConsumerWidget { | ||
const AddTripBelongingSheet(this.tripId, {super.key}); | ||
|
||
final int tripId; | ||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
final titleEditingController = useTextEditingController(); | ||
final numOfEditingController = useTextEditingController(); | ||
|
||
final isTitleEmpty = useState<bool>(true); | ||
final isNumOfEmpty = useState<bool>(true); | ||
final isShareAmongMember = useState<bool>(false); | ||
|
||
useEffect( | ||
() { | ||
titleEditingController.addListener( | ||
() => isTitleEmpty.value = titleEditingController.text.isEmpty, | ||
); | ||
numOfEditingController.addListener( | ||
() => isNumOfEmpty.value = numOfEditingController.text.isEmpty, | ||
); | ||
return null; | ||
}, | ||
[titleEditingController, numOfEditingController], | ||
); | ||
|
||
return Container( | ||
padding: EdgeInsets.only( | ||
bottom: MediaQuery.of(context).viewInsets.bottom, | ||
), | ||
height: 280, | ||
child: Column( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: [ | ||
_TitleTextField( | ||
controller: titleEditingController, | ||
isTitleEmpty: isTitleEmpty, | ||
), | ||
_NumOfForm( | ||
controller: numOfEditingController, | ||
isNumEmpty: isNumOfEmpty, | ||
), | ||
_IsShareCheckBoxRow(isShareAmongMember: isShareAmongMember), | ||
_CreateButton( | ||
tripId: tripId, | ||
titleEditingController: titleEditingController, | ||
numOfEditingController: numOfEditingController, | ||
isTitleEmpty: isTitleEmpty, | ||
isNumOfEmpty: isNumOfEmpty, | ||
isShareAmongMember: isShareAmongMember, | ||
), | ||
], | ||
), | ||
); | ||
} | ||
} | ||
|
||
class _TitleTextField extends StatelessWidget { | ||
const _TitleTextField({ | ||
required this.controller, | ||
required this.isTitleEmpty, | ||
}); | ||
|
||
final TextEditingController controller; | ||
final ValueNotifier<bool> isTitleEmpty; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Padding( | ||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), | ||
child: DecoratedBox( | ||
decoration: BoxDecoration( | ||
borderRadius: BorderRadius.circular(16), | ||
border: Border.all( | ||
color: isTitleEmpty.value | ||
? context.theme.colorScheme.secondaryContainer | ||
: context.theme.colorScheme.primary, | ||
), | ||
), | ||
child: TextField( | ||
autofocus: true, | ||
controller: controller, | ||
decoration: const InputDecoration( | ||
hintText: '持ち物名🧳', | ||
border: InputBorder.none, | ||
contentPadding: EdgeInsets.all(16), | ||
), | ||
style: TextStyle( | ||
color: context.theme.colorScheme.primary, | ||
), | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class _NumOfForm extends HookWidget { | ||
const _NumOfForm({ | ||
required this.controller, | ||
required this.isNumEmpty, | ||
}); | ||
|
||
final TextEditingController controller; | ||
final ValueNotifier<bool> isNumEmpty; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Padding( | ||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), | ||
child: DecoratedBox( | ||
decoration: BoxDecoration( | ||
borderRadius: BorderRadius.circular(16), | ||
border: Border.all( | ||
color: isNumEmpty.value | ||
? context.theme.colorScheme.secondaryContainer | ||
: context.theme.colorScheme.primary, | ||
), | ||
), | ||
child: TextField( | ||
controller: controller, | ||
keyboardType: TextInputType.number, | ||
decoration: const InputDecoration( | ||
hintText: '個数', | ||
border: InputBorder.none, | ||
contentPadding: EdgeInsets.all(16), | ||
), | ||
style: TextStyle( | ||
color: context.theme.colorScheme.primary, | ||
), | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class _IsShareCheckBoxRow extends HookWidget { | ||
const _IsShareCheckBoxRow({ | ||
required this.isShareAmongMember, | ||
}); | ||
|
||
final ValueNotifier<bool> isShareAmongMember; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Row( | ||
children: [ | ||
Checkbox( | ||
value: isShareAmongMember.value, | ||
onChanged: (value) => isShareAmongMember.value = value ?? false, | ||
fillColor: context.theme.checkboxTheme.checkColor, | ||
), | ||
InkWell( | ||
child: const Text('他のメンバーと共有する?'), | ||
onTap: () => isShareAmongMember.value = !isShareAmongMember.value, | ||
), | ||
], | ||
); | ||
} | ||
} | ||
|
||
class _CreateButton extends ConsumerWidget { | ||
const _CreateButton({ | ||
required this.tripId, | ||
required this.titleEditingController, | ||
required this.numOfEditingController, | ||
required this.isTitleEmpty, | ||
required this.isNumOfEmpty, | ||
required this.isShareAmongMember, | ||
}); | ||
|
||
final int tripId; | ||
final TextEditingController titleEditingController; | ||
final TextEditingController numOfEditingController; | ||
final ValueNotifier<bool> isTitleEmpty; | ||
final ValueNotifier<bool> isNumOfEmpty; | ||
final ValueNotifier<bool> isShareAmongMember; | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
return SizedBox( | ||
width: context.displaySize.width * 0.2, | ||
child: ElevatedButton( | ||
onPressed: isTitleEmpty.value || isNumOfEmpty.value | ||
? null | ||
: () { | ||
ref | ||
.read( | ||
tripBelongingsControllerProvider(tripId: tripId).notifier, | ||
) | ||
.addBelonging( | ||
tripId: tripId, | ||
name: titleEditingController.text, | ||
numOf: int.parse(numOfEditingController.text), | ||
isShareAmongMember: isShareAmongMember.value, | ||
onFinished: () => Navigator.pop(context), | ||
); | ||
}, | ||
child: const Text('作成'), | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.