-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
旅詳細ページのUI実装 #89
旅詳細ページのUI実装 #89
Changes from 5 commits
a30d44d
0fa5fb7
bfa8130
88e6823
6075682
640f977
8314f84
4767cf1
2380e30
3c2b791
7316b43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import 'package:collection/collection.dart'; | ||
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/exception/app_exception.dart'; | ||
import 'package:trip_app_nativeapp/core/extensions/build_context.dart'; | ||
import 'package:trip_app_nativeapp/features/trips/controller/trip_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/trip_belonging_list.dart'; | ||
import 'package:trip_app_nativeapp/view/widgets/trips/trip_overview_card.dart'; | ||
import 'package:trip_app_nativeapp/view/widgets/trips/trip_schedule.dart'; | ||
|
||
final tabStateProvider = StateProvider<int>((ref) => 0); | ||
|
||
class TripDetailPage extends HookConsumerWidget { | ||
const TripDetailPage(this.id, {super.key}); | ||
|
||
static const path = ':id'; | ||
static const scheduleTabIndex = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こうするのいいね!👍 |
||
final int id; | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
final tabIndex = useState(scheduleTabIndex); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こうしたことなかった!ためになる! |
||
final backgroundImageHeight = context.displaySize.width / 16 * 9; | ||
return Scaffold( | ||
body: SafeArea( | ||
top: false, | ||
child: ref.watch(tripsProvider).when( | ||
data: (trips) { | ||
final trip = trips.firstWhereOrNull((trip) => trip.id == id); | ||
if (trip == null) { | ||
return const Center( | ||
child: ErrorCat( | ||
AppException( | ||
code: 'not_found', | ||
message: '選択した旅の予定が見つかりませんでした。', | ||
), | ||
null, | ||
), | ||
); | ||
} | ||
|
||
return NestedScrollView( | ||
headerSliverBuilder: | ||
(BuildContext context, bool innerBoxIsScrolled) { | ||
return <Widget>[ | ||
SliverAppBar( | ||
// TODO(seigi0714): スクロールした場合のみ表示したい。 | ||
title: Text( | ||
trip.title.value, | ||
style: context.textTheme.titleLarge, | ||
), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
expandedHeight: | ||
backgroundImageHeight + TripOverviewCard.height / 2, | ||
flexibleSpace: FlexibleSpaceBar( | ||
background: SizedBox( | ||
height: backgroundImageHeight + | ||
TripOverviewCard.height / 2, | ||
child: Stack( | ||
alignment: Alignment.topCenter, | ||
children: [ | ||
SizedBox( | ||
height: backgroundImageHeight, | ||
child: Container( | ||
decoration: const BoxDecoration( | ||
image: DecorationImage( | ||
image: NetworkImage( | ||
'https://tsunagutabi.com/wp-content/uploads/2020/04/%E6%97%85%E8%A1%8C%E3%83%96%E3%83%AD%E3%82%B0%E3%81%AB%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E7%94%BB%E5%83%8F%EF%BC%86%E7%B4%A0%E6%9D%90%E3%82%B5%E3%82%A4%E3%83%88%E3%81%BE%E3%81%A8%E3%82%81.jpg', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [memo] |
||
), | ||
fit: BoxFit.cover, | ||
), | ||
), | ||
), | ||
), | ||
Positioned( | ||
top: backgroundImageHeight - | ||
TripOverviewCard.height / 2, | ||
child: TripOverviewCard(trip), | ||
), | ||
], | ||
), | ||
), | ||
), | ||
pinned: true, | ||
bottom: PreferredSize( | ||
preferredSize: const Size.fromHeight(48), | ||
child: TabBar( | ||
controller: TabController( | ||
length: 2, | ||
vsync: Scaffold.of(context), | ||
initialIndex: tabIndex.value, | ||
), | ||
labelColor: Colors.black, | ||
tabs: const [ | ||
Tab( | ||
text: '🗓️日程', | ||
), | ||
Tab( | ||
text: '🧳持ち物', | ||
) | ||
], | ||
onTap: (i) => tabIndex.value = i, | ||
), | ||
), | ||
), | ||
]; | ||
}, | ||
body: tabIndex.value == scheduleTabIndex | ||
? const TripSchedule() | ||
: const TripBelongingList(), | ||
); | ||
}, | ||
error: ErrorCat.new, | ||
loading: CarDrivingLoading.new, | ||
), | ||
), | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||
|
||
class TripBelongingList extends HookConsumerWidget { | ||
const TripBelongingList({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
return const Center( | ||
child: Text('持ち物リスト'), | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import 'dart:developer'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:trip_app_nativeapp/core/extensions/build_context.dart'; | ||
import 'package:trip_app_nativeapp/core/extensions/datetime.dart'; | ||
import 'package:trip_app_nativeapp/features/trips/domain/entity/trip/trip.dart'; | ||
|
||
class TripOverviewCard extends StatelessWidget { | ||
const TripOverviewCard(this.trip, {super.key}); | ||
|
||
final ExistingTrip trip; | ||
static const height = 150.0; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Center( | ||
child: SizedBox( | ||
height: height, | ||
width: context.displaySize.width * 0.95, | ||
child: Card( | ||
shape: RoundedRectangleBorder( | ||
borderRadius: BorderRadius.circular(12), | ||
), | ||
elevation: 4, | ||
child: Padding( | ||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), | ||
child: Column( | ||
mainAxisAlignment: MainAxisAlignment.spaceAround, | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
Expanded( | ||
child: Container( | ||
alignment: Alignment.centerLeft, | ||
child: Text( | ||
trip.title.value, | ||
maxLines: 1, | ||
overflow: TextOverflow.ellipsis, | ||
style: context.textTheme.headlineMedium, | ||
), | ||
), | ||
), | ||
Row( | ||
crossAxisAlignment: CrossAxisAlignment.end, | ||
children: [ | ||
Expanded( | ||
child: Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
Text( | ||
'🛫 ${trip.period.fromDate.toJsonDateString()}', | ||
style: context.textTheme.titleMedium, | ||
), | ||
Text( | ||
'${trip.period.endDate.toJsonDateString()} 🔚', | ||
style: context.textTheme.titleMedium, | ||
), | ||
], | ||
), | ||
), | ||
SizedBox( | ||
width: 36, | ||
height: 36, | ||
child: IconButton( | ||
onPressed: () => log('share'), | ||
icon: const Icon( | ||
Icons.share, | ||
), | ||
), | ||
), | ||
SizedBox( | ||
width: 36, | ||
height: 36, | ||
child: IconButton( | ||
onPressed: () => log('edit'), | ||
icon: const Icon( | ||
Icons.edit, | ||
), | ||
), | ||
), | ||
], | ||
), | ||
], | ||
), | ||
), | ||
), | ||
), | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
class TripSchedule extends StatelessWidget { | ||
const TripSchedule({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return const Center( | ||
child: Text('スケジュール'), | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
デザインめっちゃ良い感じだと思う!🧑🎨