From 7ca45d2f7017e4db21b1e90683598b29db405354 Mon Sep 17 00:00:00 2001 From: Michael Thomas Date: Sat, 3 Sep 2022 13:14:02 -0400 Subject: [PATCH] Show event information in bottom modal --- lib/src/screens/events/index.dart | 2 +- lib/src/screens/home/index.dart | 2 +- lib/src/utils/theme.dart | 10 + lib/src/widgets/events/event_card.dart | 111 ++++++++ lib/src/widgets/events/event_modal.dart | 245 ++++++++++++++++++ .../{home => }/events/events_list.dart | 0 lib/src/widgets/home/events/event_card.dart | 97 ------- 7 files changed, 368 insertions(+), 99 deletions(-) create mode 100644 lib/src/widgets/events/event_card.dart create mode 100644 lib/src/widgets/events/event_modal.dart rename lib/src/widgets/{home => }/events/events_list.dart (100%) delete mode 100644 lib/src/widgets/home/events/event_card.dart diff --git a/lib/src/screens/events/index.dart b/lib/src/screens/events/index.dart index 9c4878b..3c2af3e 100644 --- a/lib/src/screens/events/index.dart +++ b/lib/src/screens/events/index.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:furman_now/src/utils/date_range.dart'; import 'package:furman_now/src/utils/theme.dart'; import 'package:furman_now/src/widgets/header.dart'; -import 'package:furman_now/src/widgets/home/events/events_list.dart'; +import 'package:furman_now/src/widgets/events/events_list.dart'; import 'package:furman_now/src/widgets/scroll_view_height.dart'; import 'package:intl/intl.dart'; diff --git a/lib/src/screens/home/index.dart b/lib/src/screens/home/index.dart index 26e1162..2c136e1 100644 --- a/lib/src/screens/home/index.dart +++ b/lib/src/screens/home/index.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:furman_now/src/utils/greeting.dart'; import 'package:furman_now/src/utils/theme.dart'; import 'package:furman_now/src/widgets/header.dart'; -import 'package:furman_now/src/widgets/home/events/events_list.dart'; +import 'package:furman_now/src/widgets/events/events_list.dart'; import 'package:furman_now/src/widgets/home/restaurants/restaurants_list.dart'; import 'package:furman_now/src/widgets/home/transportation/transportation_card.dart'; import 'package:furman_now/src/widgets/scroll_view_height.dart'; diff --git a/lib/src/utils/theme.dart b/lib/src/utils/theme.dart index c0b8189..adc98f5 100644 --- a/lib/src/utils/theme.dart +++ b/lib/src/utils/theme.dart @@ -8,6 +8,16 @@ ThemeData _baseTheme = ThemeData( unselectedItemColor: Colors.grey[500], ), textTheme: TextTheme( + headline1: TextStyle( + color: Colors.grey[800], + fontWeight: FontWeight.w900, + fontSize: 22, + ), + subtitle1: TextStyle( + color: Colors.grey[500], + fontWeight: FontWeight.w500, + fontSize: 16, + ), subtitle2: TextStyle( color: Colors.grey[500], fontWeight: FontWeight.w500, diff --git a/lib/src/widgets/events/event_card.dart b/lib/src/widgets/events/event_card.dart new file mode 100644 index 0000000..2893b88 --- /dev/null +++ b/lib/src/widgets/events/event_card.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'package:furman_now/src/services/events/event.dart'; +import 'package:furman_now/src/utils/theme.dart'; +import 'package:furman_now/src/widgets/events/event_modal.dart'; +import 'package:intl/intl.dart'; + +class EventCard extends StatelessWidget { + const EventCard + ( + this.event, + { + Key? key + } + ) : super(key: key); + + final Event event; + + String get eventHour { + var formatter = DateFormat('hh:mm'); + return formatter.format(event.time); + } + + String get eventAmPm { + var formatter = DateFormat('a'); + return formatter.format(event.time); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + showEventsModal( + context, + event, + ); + // showModalBottomSheet( + // context: context, + // builder: (BuildContext context) { + // return EventModal(event: event); + // } + // ); + }, + child: Container( + decoration: const BoxDecoration( + color: Color(0xfff9f9fb), + borderRadius: BorderRadius.all(Radius.circular(10)) + ), + child: IntrinsicHeight( + child: Row( + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(eventHour, style: furmanTextStyle(const TextStyle(fontWeight: FontWeight.w700))), + Text(eventAmPm, style: Theme.of(context).textTheme.subtitle2), + ], + ), + ), + VerticalDivider( + width: 2, + thickness: 2, + color: Colors.grey[200], + ), + Flexible( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(event.title, style: furmanTextStyle(const TextStyle(fontWeight: FontWeight.w600))), + const SizedBox(height: 6), + RichText(text: TextSpan( + style: Theme.of(context).textTheme.subtitle2, + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(right: 5.0), + child: Icon(Icons.place_outlined, size: 20, color: Colors.grey[500]) + ), + ), + TextSpan(text: event.location), + ], + )), + const SizedBox(height: 2), + RichText(text: TextSpan( + style: Theme.of(context).textTheme.subtitle2, + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(left: 1.0, right: 6.0), + child: Icon(Icons.sell_outlined, size: 18, color: Colors.grey[500]) + ), + ), + TextSpan(text: event.category), + ], + )), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/widgets/events/event_modal.dart b/lib/src/widgets/events/event_modal.dart new file mode 100644 index 0000000..aea94d8 --- /dev/null +++ b/lib/src/widgets/events/event_modal.dart @@ -0,0 +1,245 @@ +import 'package:flutter/material.dart'; +import 'package:furman_now/src/services/events/event.dart'; +import 'package:furman_now/src/services/events/events_service.dart'; +import 'package:intl/intl.dart'; + +void showEventsModal(BuildContext context, Event event) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) { + return _EventModal(event: event); + }, + ); +} + +class _EventModal extends StatefulWidget { + final Event event; + + const _EventModal({ + required this.event, + Key? key, + }) : super(key: key); + + @override + State<_EventModal> createState() => _EventModalState(); +} + +class _EventModalState extends State<_EventModal> { + var childSize = Size.zero; + BoxConstraints? _parentConstraints; + final _key = GlobalKey(); + + double _maxChildHeight = 0.75; + + void updateMaxHeight() { + if (_parentConstraints != null) { + print(_key.currentContext?.size?.height); + var listHeight = _key.currentContext?.size?.height; + var parentHeight = _parentConstraints?.maxHeight; + if (listHeight != null && parentHeight != null) { + setState(() { + _maxChildHeight = (listHeight + 150) / parentHeight; + }); + } + } + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance + .addPostFrameCallback((_) => updateMaxHeight()); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + color: const Color.fromRGBO(0, 0, 0, 0.001), + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + _parentConstraints = constraints; + return GestureDetector( + onTap: () {}, + child: DraggableScrollableSheet( + initialChildSize: _maxChildHeight, + minChildSize: 0.1, + maxChildSize: _maxChildHeight, + builder: (_, controller) { + return Container( + color: Colors.grey.shade100, + margin: const EdgeInsets.only( + bottom: kBottomNavigationBarHeight), + child: Column( + children: [ + const Align( + alignment: Alignment.topRight, + child: CloseButton(), + ), + Flexible( + child: NotificationListener( + onNotification: (OverscrollIndicatorNotification overscroll) { + overscroll.disallowIndicator(); + return true; + }, + child: _EventModalContent( + key: _key, + controller: controller, + event: widget.event, + ), + ), + ), + ], + ), + ); + } + ), + ); + } + ), + ), + ); + } +} + +class _EventModalContent extends StatelessWidget { + final ScrollController controller; + final Event event; + + const _EventModalContent({ + required this.controller, + required this.event, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ListView( + shrinkWrap: true, + padding: const EdgeInsets.symmetric(horizontal: 40), + controller: controller, + children: [ + // Title + Text( + event.title, + style: Theme.of(context).textTheme.headline1, + ), + const SizedBox(height: 10), + // Location + RichText(text: TextSpan( + style: Theme.of(context).textTheme.subtitle1, + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(right: 5.0), + child: Icon( + Icons.place_outlined, size: 24, + color: Colors.grey[500]) + ), + ), + TextSpan(text: event.location), + ], + )), + const SizedBox(height: 5), + if (event is ClpEvent) ...[ + // Organization + RichText(text: TextSpan( + style: Theme.of(context).textTheme.subtitle1, + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(right: 5.0), + child: Icon( + Icons.group_outlined, + size: 24, + color: Colors.grey[500] + ), + ), + ), + TextSpan(text: (event as ClpEvent).organization), + ], + )), + const SizedBox(height: 5), + // Time + RichText(text: TextSpan( + style: Theme.of(context).textTheme.subtitle1, + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Padding( + padding: const EdgeInsets.only( + right: 5.0), + child: Icon( + Icons.access_time_outlined, + size: 24, + color: Colors.grey[500]) + ), + ), + WidgetSpan( + alignment: PlaceholderAlignment.top, + child: Column( + crossAxisAlignment: CrossAxisAlignment + .start, + children: [ + Text( + DateFormat("EEEE, MMMM d") + .format( + (event as ClpEvent) + .startTime), + style: Theme + .of(context) + .textTheme + .subtitle1, + ), + Text( + "${DateFormat.jm().format( + (event as ClpEvent) + .startTime)} - ${DateFormat + .jm().format( + (event as ClpEvent) + .endTime)}", + style: Theme + .of(context) + .textTheme + .subtitle1, + ), + ], + ) + ), + ], + )), + const SizedBox(height: 5), + // Description + Row( + crossAxisAlignment: CrossAxisAlignment + .start, + children: [ + Padding( + padding: const EdgeInsets.only( + right: 5.0), + child: Icon(Icons.notes, size: 24, + color: Colors + .grey[500]) + ), + Flexible( + child: Text( + (event as ClpEvent) + .description, + style: Theme + .of(context) + .textTheme + .subtitle1, + ), + ), + ], + ), + ] + ], + ); + } +} diff --git a/lib/src/widgets/home/events/events_list.dart b/lib/src/widgets/events/events_list.dart similarity index 100% rename from lib/src/widgets/home/events/events_list.dart rename to lib/src/widgets/events/events_list.dart diff --git a/lib/src/widgets/home/events/event_card.dart b/lib/src/widgets/home/events/event_card.dart deleted file mode 100644 index 4e57950..0000000 --- a/lib/src/widgets/home/events/event_card.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:furman_now/src/services/events/event.dart'; -import 'package:furman_now/src/utils/theme.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:intl/intl.dart'; - -class EventCard extends StatelessWidget { - const EventCard - ( - this.event, - { - Key? key - } - ) : super(key: key); - - final Event event; - - String get eventHour { - var formatter = DateFormat('hh:mm'); - return formatter.format(event.time); - } - - String get eventAmPm { - var formatter = DateFormat('a'); - return formatter.format(event.time); - } - - @override - Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - color: Color(0xfff9f9fb), - borderRadius: BorderRadius.all(Radius.circular(10)) - ), - child: IntrinsicHeight( - child: Row( - children: [ - Container( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(eventHour, style: furmanTextStyle(const TextStyle(fontWeight: FontWeight.w700))), - Text(eventAmPm, style: Theme.of(context).textTheme.subtitle2), - ], - ), - ), - VerticalDivider( - width: 2, - thickness: 2, - color: Colors.grey[200], - ), - Flexible( - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(event.title, style: furmanTextStyle(const TextStyle(fontWeight: FontWeight.w600))), - const SizedBox(height: 6), - RichText(text: TextSpan( - style: Theme.of(context).textTheme.subtitle2, - children: [ - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(right: 5.0), - child: Icon(Icons.place_outlined, size: 20, color: Colors.grey[500]) - ), - ), - TextSpan(text: event.location), - ], - )), - const SizedBox(height: 2), - RichText(text: TextSpan( - style: Theme.of(context).textTheme.subtitle2, - children: [ - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(left: 1.0, right: 6.0), - child: Icon(Icons.sell_outlined, size: 18, color: Colors.grey[500]) - ), - ), - TextSpan(text: event.category), - ], - )), - ], - ), - ), - ), - ], - ), - ), - ); - } -} \ No newline at end of file