fix: various improvements to events list
This commit is contained in:
parent
d0d881fbbe
commit
2052e618ac
|
@ -19,10 +19,21 @@ class EventsService {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// If the server did return a 200 OK response,
|
// If the server did return a 200 OK response,
|
||||||
// then parse the JSON.
|
// then parse the JSON.
|
||||||
|
try {
|
||||||
final eventsJson = jsonDecode(response.body);
|
final eventsJson = jsonDecode(response.body);
|
||||||
|
if (eventsJson["results"] != null) {
|
||||||
return (eventsJson["results"] as List<dynamic>).map((event) =>
|
return (eventsJson["results"] as List<dynamic>).map((event) =>
|
||||||
AthleticsEvent.fromJson(event)
|
AthleticsEvent.fromJson(event)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw
|
||||||
|
"Failed to parse athletics event data."
|
||||||
|
"\n"
|
||||||
|
"Exception: $e";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the server did not return a 200 OK response,
|
// If the server did not return a 200 OK response,
|
||||||
// then throw an exception.
|
// then throw an exception.
|
||||||
|
@ -37,14 +48,26 @@ class EventsService {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// If the server did return a 200 OK response,
|
// If the server did return a 200 OK response,
|
||||||
// then parse the JSON.
|
// then parse the JSON.
|
||||||
|
try {
|
||||||
final eventsJson = jsonDecode(response.body);
|
final eventsJson = jsonDecode(response.body);
|
||||||
|
if (eventsJson["results"] != null) {
|
||||||
return (eventsJson["results"] as List<dynamic>).map((event) =>
|
return (eventsJson["results"] as List<dynamic>).map((event) =>
|
||||||
ClpEvent.fromJson(event)
|
ClpEvent.fromJson(event)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw
|
||||||
|
"Failed to parse CLP event data."
|
||||||
|
"\n"
|
||||||
|
"Exception: $e";
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// If the server did not return a 200 OK response,
|
// If the server did not return a 200 OK response,
|
||||||
// then throw an exception.
|
// then throw an exception.
|
||||||
throw Exception('Failed to load athletics events.');
|
throw Exception('Failed to load CLP events.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:furman_now/src/services/events/event.dart';
|
import 'package:furman_now/src/services/events/event.dart';
|
||||||
import 'package:furman_now/src/utils/theme.dart';
|
import 'package:furman_now/src/utils/theme.dart';
|
||||||
import 'package:furman_now/src/widgets/events/event_modal.dart';
|
import 'package:furman_now/src/widgets/events/event_modal.dart';
|
||||||
|
import 'package:furman_now/src/widgets/text_with_icon.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class EventCard extends StatelessWidget {
|
class EventCard extends StatelessWidget {
|
||||||
|
@ -33,12 +34,6 @@ class EventCard extends StatelessWidget {
|
||||||
context,
|
context,
|
||||||
event,
|
event,
|
||||||
);
|
);
|
||||||
// showModalBottomSheet<void>(
|
|
||||||
// context: context,
|
|
||||||
// builder: (BuildContext context) {
|
|
||||||
// return EventModal(event: event);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
|
@ -53,8 +48,11 @@ class EventCard extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(eventHour, style: furmanTextStyle(const TextStyle(fontWeight: FontWeight.w700))),
|
Text(eventHour, style: furmanTextStyle(TextStyle(
|
||||||
Text(eventAmPm, style: Theme.of(context).textTheme.subtitle2),
|
color: Colors.grey[800],
|
||||||
|
fontWeight: FontWeight.w700
|
||||||
|
))),
|
||||||
|
Text(eventAmPm, style: Theme.of(context).textTheme.labelMedium),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -69,35 +67,19 @@ class EventCard extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(event.title, style: furmanTextStyle(const TextStyle(fontWeight: FontWeight.w600))),
|
Text(event.title, style: Theme.of(context).textTheme.titleSmall),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
RichText(text: TextSpan(
|
TextWithIcon(
|
||||||
style: Theme.of(context).textTheme.subtitle2,
|
icon: Icons.place_outlined,
|
||||||
children: [
|
text: event.location,
|
||||||
WidgetSpan(
|
size: TextWithIconSize.small,
|
||||||
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),
|
const SizedBox(height: 2),
|
||||||
RichText(text: TextSpan(
|
TextWithIcon(
|
||||||
style: Theme.of(context).textTheme.subtitle2,
|
icon: Icons.sell_outlined,
|
||||||
children: [
|
text: event.category,
|
||||||
WidgetSpan(
|
size: TextWithIconSize.small,
|
||||||
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),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:furman_now/src/services/events/event.dart';
|
import 'package:furman_now/src/services/events/event.dart';
|
||||||
import 'package:furman_now/src/services/events/events_service.dart';
|
import 'package:furman_now/src/services/events/events_service.dart';
|
||||||
|
import 'package:furman_now/src/widgets/text_with_icon.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
void showEventsModal(BuildContext context, Event event) {
|
void showEventsModal(BuildContext context, Event event) {
|
||||||
|
@ -31,16 +32,19 @@ class _EventModalState extends State<_EventModal> {
|
||||||
BoxConstraints? _parentConstraints;
|
BoxConstraints? _parentConstraints;
|
||||||
final _key = GlobalKey();
|
final _key = GlobalKey();
|
||||||
|
|
||||||
double _maxChildHeight = 0.75;
|
static const _maxDialogHeight = 0.8;
|
||||||
|
|
||||||
|
var _maxChildHeight = _maxDialogHeight;
|
||||||
|
|
||||||
void updateMaxHeight() {
|
void updateMaxHeight() {
|
||||||
if (_parentConstraints != null) {
|
if (_parentConstraints != null) {
|
||||||
var listHeight = _key.currentContext?.size?.height;
|
var listHeight = _key.currentContext?.size?.height;
|
||||||
var parentHeight = _parentConstraints?.maxHeight;
|
var parentHeight = _parentConstraints?.maxHeight;
|
||||||
if (listHeight != null && parentHeight != null) {
|
if (listHeight != null && parentHeight != null) {
|
||||||
var maxHeight = (listHeight + 50) / parentHeight;
|
var maxHeight = (listHeight + 70) / parentHeight;
|
||||||
setState(() {
|
setState(() {
|
||||||
_maxChildHeight = (maxHeight < 0.75) ? maxHeight : 0.75;
|
_maxChildHeight = (maxHeight < _maxDialogHeight)
|
||||||
|
? maxHeight : _maxDialogHeight;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,8 +82,10 @@ class _EventModalState extends State<_EventModal> {
|
||||||
child: CloseButton(),
|
child: CloseButton(),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: NotificationListener<OverscrollIndicatorNotification>(
|
child: NotificationListener
|
||||||
onNotification: (OverscrollIndicatorNotification overscroll) {
|
<OverscrollIndicatorNotification>(
|
||||||
|
onNotification:
|
||||||
|
(OverscrollIndicatorNotification overscroll) {
|
||||||
overscroll.disallowIndicator();
|
overscroll.disallowIndicator();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -123,120 +129,55 @@ class _EventModalContent extends StatelessWidget {
|
||||||
// Title
|
// Title
|
||||||
Text(
|
Text(
|
||||||
event.title,
|
event.title,
|
||||||
style: Theme.of(context).textTheme.headline1,
|
style: Theme.of(context).textTheme.headlineLarge,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
// Location
|
// Location
|
||||||
RichText(text: TextSpan(
|
TextWithIcon(
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
icon: Icons.place_outlined,
|
||||||
children: [
|
text: event.location,
|
||||||
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),
|
const SizedBox(height: 5),
|
||||||
if (event is ClpEvent) ...[
|
// Additional info for CLP events
|
||||||
|
if (event is ClpEvent) ...(() {
|
||||||
|
final clpEvent = event as ClpEvent;
|
||||||
|
return [
|
||||||
// Organization
|
// Organization
|
||||||
RichText(text: TextSpan(
|
TextWithIcon(
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
icon: Icons.group_outlined,
|
||||||
children: [
|
text: clpEvent.organization
|
||||||
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),
|
const SizedBox(height: 5),
|
||||||
// Time
|
// Time
|
||||||
RichText(text: TextSpan(
|
TextWithIcon(
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
icon: Icons.access_time_outlined,
|
||||||
children: [
|
text:
|
||||||
WidgetSpan(
|
"${DateFormat("EEEE, MMMM d").format(clpEvent.startTime)}"
|
||||||
alignment: PlaceholderAlignment.middle,
|
"\n"
|
||||||
child: Padding(
|
"${DateFormat.jm().format(clpEvent.startTime)} - ${DateFormat.jm().format(clpEvent.endTime)}",
|
||||||
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),
|
const SizedBox(height: 5),
|
||||||
// Description
|
// Description
|
||||||
Row(
|
TextWithIcon(
|
||||||
crossAxisAlignment: CrossAxisAlignment
|
icon: Icons.notes,
|
||||||
.start,
|
text: clpEvent.description
|
||||||
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)
|
// Additional info for Athletics Events
|
||||||
.description,
|
if (event is AthleticsEvent) ...(() {
|
||||||
style: Theme
|
final athleticsEvent = event as AthleticsEvent;
|
||||||
.of(context)
|
return [
|
||||||
.textTheme
|
// Time
|
||||||
.subtitle1,
|
TextWithIcon(
|
||||||
|
icon: Icons.access_time_outlined,
|
||||||
|
text:
|
||||||
|
"${DateFormat("EEEE, MMMM d").format(athleticsEvent.time)}"
|
||||||
|
"\n"
|
||||||
|
"${DateFormat.jm().format(athleticsEvent.time)}",
|
||||||
),
|
),
|
||||||
),
|
];
|
||||||
],
|
})(),
|
||||||
),
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,10 @@ class EventsList extends StatefulWidget {
|
||||||
}) {
|
}) {
|
||||||
if (dateRange == null) {
|
if (dateRange == null) {
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final today = DateTime(now.year, now.month, now.day);
|
// final today = DateTime(now.year, now.month, now.day);
|
||||||
final tonight = DateTime(now.year, now.month, now.day, 23, 59, 59);
|
final tonight = DateTime(now.year, now.month, now.day, 23, 59, 59);
|
||||||
dateRange = DateTimeRange(start: today, end: tonight);
|
// dateRange = DateTimeRange(start: today, end: tonight);
|
||||||
|
dateRange = DateTimeRange(start: now, end: tonight);
|
||||||
}
|
}
|
||||||
return EventsList._(
|
return EventsList._(
|
||||||
dateRange: dateRange,
|
dateRange: dateRange,
|
||||||
|
|
Loading…
Reference in New Issue