From adaa340df01b5d588a251f442266806684576f98 Mon Sep 17 00:00:00 2001 From: nico Date: Thu, 11 Jun 2026 14:27:16 +0200 Subject: [PATCH 1/8] feat(campus): add campus heilbronn event widget Co-authored-by: Alexandros Stathakopoulos --- assets/translations/de.json | 3 +- assets/translations/en.json | 3 +- .../model/heilbronn_event.dart | 85 ++++++++++++++ lib/campusComponent/screen/campus_screen.dart | 2 + .../service/heilbronn_event_service.dart | 13 +++ .../heilbronn_event_card_view.dart | 62 ++++++++++ .../heilbronn_events_widget_view.dart | 110 ++++++++++++++++++ .../viewmodel/heilbronn_events_viewmodel.dart | 59 ++++++++++ 8 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 lib/campusComponent/model/heilbronn_event.dart create mode 100644 lib/campusComponent/service/heilbronn_event_service.dart create mode 100644 lib/campusComponent/view/heilbronnEvents/heilbronn_event_card_view.dart create mode 100644 lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart create mode 100644 lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart diff --git a/assets/translations/de.json b/assets/translations/de.json index 6b8c9d67..66e8a345 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -244,5 +244,6 @@ "visibility": "Sichtbarkeit", "utilizationAt": "Auslastung bei {}%", "showStudentCardPicture": "Student Card Bild zeigen", - "add_contact": "Zu Kontakten hinzufügen" + "add_contact": "Zu Kontakten hinzufügen", + "noUpcomingEvents": "Keine bevorstehenden Events" } diff --git a/assets/translations/en.json b/assets/translations/en.json index c1c49833..828ee134 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -244,5 +244,6 @@ "visibility": "Visibility", "utilizationAt": "Utilization at {}%", "showStudentCardPicture": "Show Student Card Picture", - "add_contact": "Add to contacts" + "add_contact": "Add to contacts", + "noUpcomingEvents": "No upcoming events" } diff --git a/lib/campusComponent/model/heilbronn_event.dart b/lib/campusComponent/model/heilbronn_event.dart new file mode 100644 index 00000000..da20ba00 --- /dev/null +++ b/lib/campusComponent/model/heilbronn_event.dart @@ -0,0 +1,85 @@ +import 'package:intl/intl.dart'; +import 'package:xml/xml.dart'; + +class HeilbronnEvent { + final String title; + final String link; + final String description; + final DateTime? publishedAt; + final DateTime? startDate; + final DateTime? endDate; + final String? time; + final String? location; + + const HeilbronnEvent({ + required this.title, + required this.link, + required this.description, + this.publishedAt, + this.startDate, + this.endDate, + this.time, + this.location, + }); + + DateTime? get eventDate => startDate ?? publishedAt; + + static final _timeRegExp = RegExp( + r'Time:\s*(.*?)(?=\s*(?:Date:|Time:|Location:|$))', + caseSensitive: false, + ); + static final _locationRegExp = RegExp( + r'Location:\s*(.*?)(?=\s*(?:Date:|Time:|Location:|$))', + caseSensitive: false, + ); + + static List listFromRss(String rss) { + try { + final document = XmlDocument.parse(rss); + final events = document + .findAllElements('item') + .map((item) { + final description = _elementText(item, 'description'); + final pubDate = _parsePubDate(_elementText(item, 'pubDate')); + + return HeilbronnEvent( + title: _elementText(item, 'title'), + link: _elementText(item, 'link'), + description: description, + publishedAt: pubDate, + startDate: DateTime.tryParse(_elementText(item, 'startDate')) ?? + DateTime.tryParse(_elementText(item, 'start-date')), + endDate: DateTime.tryParse(_elementText(item, 'endDate')) ?? + DateTime.tryParse(_elementText(item, 'end-date')), + time: _timeRegExp.firstMatch(description)?.group(1)?.trim(), + location: + _locationRegExp.firstMatch(description)?.group(1)?.trim(), + ); + }) + .where((event) => event.title.isNotEmpty) + .toList(); + + events.sort((a, b) { + final firstDate = a.eventDate ?? DateTime(0); + final secondDate = b.eventDate ?? DateTime(0); + return firstDate.compareTo(secondDate); + }); + return events; + } catch (_) { + return []; + } + } + + static String _elementText(XmlElement item, String name) { + final elements = item.findElements(name); + return elements.isEmpty ? '' : elements.first.innerText.trim(); + } + + static DateTime? _parsePubDate(String value) { + try { + return DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US').parse(value); + } catch (_) { + return null; + } + } +} diff --git a/lib/campusComponent/screen/campus_screen.dart b/lib/campusComponent/screen/campus_screen.dart index d7f70766..ec00a4e8 100644 --- a/lib/campusComponent/screen/campus_screen.dart +++ b/lib/campusComponent/screen/campus_screen.dart @@ -1,4 +1,5 @@ import 'package:campus_flutter/campusComponent/view/studentClub/student_club_widget_view.dart'; +import 'package:campus_flutter/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart'; import 'package:campus_flutter/campusComponent/view/movie/movies_widget_view.dart'; import 'package:campus_flutter/campusComponent/view/news/news_widget_view.dart'; import 'package:flutter/material.dart'; @@ -32,6 +33,7 @@ class CampusScreen extends StatelessWidget { child: Column( children: [ NewsWidgetView(), + HeilbronnEventsWidgetView(), StudentClubWidgetView(), MovieWidgetView(), ], diff --git a/lib/campusComponent/service/heilbronn_event_service.dart b/lib/campusComponent/service/heilbronn_event_service.dart new file mode 100644 index 00000000..f18851a8 --- /dev/null +++ b/lib/campusComponent/service/heilbronn_event_service.dart @@ -0,0 +1,13 @@ +import 'package:campus_flutter/campusComponent/model/heilbronn_event.dart'; +import 'package:dio/dio.dart'; + +class HeilbronnEventService { + static const feedUrl = 'https://hn.fs.tum.de/events/index.xml'; + + static final _dio = Dio(); + + static Future> fetchEvents() async { + final response = await _dio.get(feedUrl); + return HeilbronnEvent.listFromRss(response.data ?? ''); + } +} diff --git a/lib/campusComponent/view/heilbronnEvents/heilbronn_event_card_view.dart b/lib/campusComponent/view/heilbronnEvents/heilbronn_event_card_view.dart new file mode 100644 index 00000000..236b4506 --- /dev/null +++ b/lib/campusComponent/view/heilbronnEvents/heilbronn_event_card_view.dart @@ -0,0 +1,62 @@ +import 'package:campus_flutter/base/extensions/context.dart'; +import 'package:campus_flutter/base/util/string_parser.dart'; +import 'package:campus_flutter/base/util/url_launcher.dart'; +import 'package:campus_flutter/campusComponent/model/heilbronn_event.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class HeilbronnEventCardView extends ConsumerWidget { + const HeilbronnEventCardView({super.key, required this.event}); + + final HeilbronnEvent event; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () => UrlLauncher.urlString(event.link, ref), + child: Card( + margin: EdgeInsets.zero, + clipBehavior: Clip.hardEdge, + child: Padding( + padding: EdgeInsets.all(context.halfPadding * 1.5), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + event.title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w500, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + if (event.eventDate != null) + Text( + StringParser.dateFormatter(event.eventDate!, context), + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + if (event.time != null) + Text( + event.time!, + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + if (event.location != null) + Text( + event.location!, + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart new file mode 100644 index 00000000..fd65b792 --- /dev/null +++ b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart @@ -0,0 +1,110 @@ +import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; +import 'package:campus_flutter/base/errorHandling/error_handling_router.dart'; +import 'package:campus_flutter/base/extensions/context.dart'; +import 'package:campus_flutter/base/util/delayed_loading_indicator.dart'; +import 'package:campus_flutter/base/util/grid_utility.dart'; +import 'package:campus_flutter/campusComponent/model/heilbronn_event.dart'; +import 'package:campus_flutter/campusComponent/view/heilbronnEvents/heilbronn_event_card_view.dart'; +import 'package:campus_flutter/campusComponent/viewmodel/heilbronn_events_viewmodel.dart'; +import 'package:campus_flutter/homeComponent/view/widget/widget_frame_view.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class HeilbronnEventsWidgetView extends ConsumerStatefulWidget { + const HeilbronnEventsWidgetView({super.key}); + + @override + ConsumerState createState() => + _HeilbronnEventsWidgetViewState(); +} + +class _HeilbronnEventsWidgetViewState + extends ConsumerState { + @override + void initState() { + ref.read(heilbronnEventsViewModel).fetch(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: ref.watch(heilbronnEventsViewModel).isNearHeilbronn, + builder: (context, nearbySnapshot) { + if (nearbySnapshot.data == false) { + return const SizedBox.shrink(); + } + + return StreamBuilder( + stream: ref.watch(heilbronnEventsViewModel).events, + builder: (context, eventsSnapshot) { + return WidgetFrameView( + titleWidget: Text( + 'Campus Heilbronn Events', + style: Theme.of(context).textTheme.titleMedium, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + child: _body(eventsSnapshot), + ); + }, + ); + }, + ); + } + + Widget _body(AsyncSnapshot?> snapshot) { + if (snapshot.hasData) { + if (snapshot.data!.isEmpty) { + return AspectRatio( + aspectRatio: 2, + child: Card( + child: Center( + child: Text( + 'noUpcomingEvents'.tr(), + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + ), + ); + } + return Padding( + padding: EdgeInsets.symmetric(horizontal: context.padding), + child: GridView.count( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + crossAxisCount: 1, + mainAxisSpacing: context.padding, + crossAxisSpacing: context.padding, + childAspectRatio: 3.25, + children: [ + for (final event in snapshot.data!.take( + GridUtility.campusNumberOfItems(context), + )) + HeilbronnEventCardView(event: event), + ], + ), + ); + } else if (snapshot.hasError) { + return AspectRatio( + aspectRatio: 2, + child: Card( + child: ErrorHandlingRouter( + error: snapshot.error, + errorHandlingViewType: ErrorHandlingViewType.textOnly, + retry: (() => ref.read(heilbronnEventsViewModel).fetch()), + ), + ), + ); + } else { + return const AspectRatio( + aspectRatio: 2, + child: Card( + child: DelayedLoadingIndicator(name: 'Campus Heilbronn Events'), + ), + ); + } + } +} diff --git a/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart b/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart new file mode 100644 index 00000000..d6626205 --- /dev/null +++ b/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart @@ -0,0 +1,59 @@ +import 'package:campus_flutter/base/services/location_service.dart'; +import 'package:campus_flutter/campusComponent/model/heilbronn_event.dart'; +import 'package:campus_flutter/campusComponent/service/heilbronn_event_service.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:rxdart/rxdart.dart'; + +final heilbronnEventsViewModel = Provider( + (ref) => HeilbronnEventsViewModel(), +); + +class HeilbronnEventsViewModel { + static const _heilbronnLatitude = 49.1472; + static const _heilbronnLongitude = 9.2165; + static const _heilbronnRadiusMeters = 100000.0; + + final BehaviorSubject?> events = + BehaviorSubject.seeded(null); + final BehaviorSubject isNearHeilbronn = BehaviorSubject.seeded(null); + + Future fetch() async { + final position = await LocationService.getLastKnown().onError( + (error, stackTrace) => null, + ); + if (position == null || + !_isWithinRadius(position.latitude, position.longitude)) { + isNearHeilbronn.add(false); + events.add([]); + return; + } + + isNearHeilbronn.add(true); + try { + final fetchedEvents = await HeilbronnEventService.fetchEvents(); + fetchedEvents.removeWhere((event) { + final eventDate = event.eventDate; + return eventDate != null && eventDate.isBefore(_today()); + }); + events.add(fetchedEvents); + } catch (error) { + events.addError(error); + } + } + + bool _isWithinRadius(double latitude, double longitude) { + return Geolocator.distanceBetween( + latitude, + longitude, + _heilbronnLatitude, + _heilbronnLongitude, + ) <= + _heilbronnRadiusMeters; + } + + DateTime _today() { + final now = DateTime.now(); + return DateTime(now.year, now.month, now.day); + } +} From e89cf3071e2838aa94ece1b061d1c981787a026e Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 17:08:20 +0200 Subject: [PATCH 2/8] fix: change rss events feed with user language --- lib/campusComponent/service/heilbronn_event_service.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/campusComponent/service/heilbronn_event_service.dart b/lib/campusComponent/service/heilbronn_event_service.dart index f18851a8..cb3237a2 100644 --- a/lib/campusComponent/service/heilbronn_event_service.dart +++ b/lib/campusComponent/service/heilbronn_event_service.dart @@ -2,12 +2,14 @@ import 'package:campus_flutter/campusComponent/model/heilbronn_event.dart'; import 'package:dio/dio.dart'; class HeilbronnEventService { - static const feedUrl = 'https://hn.fs.tum.de/events/index.xml'; + static String feedUrl(String languageCode) => languageCode == 'de' + ? 'https://hn.fs.tum.de/de/events/index.xml' + : 'https://hn.fs.tum.de/events/index.xml'; static final _dio = Dio(); - static Future> fetchEvents() async { - final response = await _dio.get(feedUrl); + static Future> fetchEvents(String languageCode) async { + final response = await _dio.get(feedUrl(languageCode)); return HeilbronnEvent.listFromRss(response.data ?? ''); } } From 6797d578dda9bb2581a5ae2382898ea745677f52 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 17:12:22 +0200 Subject: [PATCH 3/8] fix: use fresh GPS for Heilbronn location check --- .../viewmodel/heilbronn_events_viewmodel.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart b/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart index d6626205..edf6d4f5 100644 --- a/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart +++ b/lib/campusComponent/viewmodel/heilbronn_events_viewmodel.dart @@ -18,10 +18,13 @@ class HeilbronnEventsViewModel { BehaviorSubject.seeded(null); final BehaviorSubject isNearHeilbronn = BehaviorSubject.seeded(null); - Future fetch() async { - final position = await LocationService.getLastKnown().onError( - (error, stackTrace) => null, - ); + Future fetch(String languageCode) async { + Position? position; + try { + position = await LocationService.determinePosition(); + } catch (_) { + position = null; + } if (position == null || !_isWithinRadius(position.latitude, position.longitude)) { isNearHeilbronn.add(false); @@ -31,7 +34,9 @@ class HeilbronnEventsViewModel { isNearHeilbronn.add(true); try { - final fetchedEvents = await HeilbronnEventService.fetchEvents(); + final fetchedEvents = await HeilbronnEventService.fetchEvents( + languageCode, + ); fetchedEvents.removeWhere((event) { final eventDate = event.eventDate; return eventDate != null && eventDate.isBefore(_today()); From 027c66e919211b2cc1a4c5dbcfb1758e6f6ab95a Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 18:53:38 +0200 Subject: [PATCH 4/8] fix: run initial Heilbronn events fetch in post-frame callback with local --- .../heilbronnEvents/heilbronn_events_widget_view.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart index fd65b792..b74d2e11 100644 --- a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart +++ b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart @@ -23,8 +23,11 @@ class _HeilbronnEventsWidgetViewState extends ConsumerState { @override void initState() { - ref.read(heilbronnEventsViewModel).fetch(); super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + ref.read(heilbronnEventsViewModel).fetch(context.locale.languageCode); + }); } @override @@ -94,7 +97,9 @@ class _HeilbronnEventsWidgetViewState child: ErrorHandlingRouter( error: snapshot.error, errorHandlingViewType: ErrorHandlingViewType.textOnly, - retry: (() => ref.read(heilbronnEventsViewModel).fetch()), + retry: (() => ref + .read(heilbronnEventsViewModel) + .fetch(context.locale.languageCode)), ), ), ); From 008557a97c0cd475ec281620937a3632641406b4 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 22:18:04 +0200 Subject: [PATCH 5/8] fix: refetch Heilbronn events on language change --- .../heilbronn_events_widget_view.dart | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart index b74d2e11..07689203 100644 --- a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart +++ b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart @@ -21,13 +21,15 @@ class HeilbronnEventsWidgetView extends ConsumerStatefulWidget { class _HeilbronnEventsWidgetViewState extends ConsumerState { + String? _languageCode; + @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!mounted) return; - ref.read(heilbronnEventsViewModel).fetch(context.locale.languageCode); - }); + void didChangeDependencies() { + super.didChangeDependencies(); + final languageCode = context.locale.languageCode; + if (_languageCode == languageCode) return; + _languageCode = languageCode; + ref.read(heilbronnEventsViewModel).fetch(languageCode); } @override @@ -78,7 +80,7 @@ class _HeilbronnEventsWidgetViewState shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, - crossAxisCount: 1, + crossAxisCount: GridUtility.campusEventsCrossAxisCount(context), mainAxisSpacing: context.padding, crossAxisSpacing: context.padding, childAspectRatio: 3.25, From 043cdb5bfaacbc2a321f30bde52b44bc328a828d Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 22:21:02 +0200 Subject: [PATCH 6/8] fix: use 2 col Heilbronn events grid on tablet --- lib/base/util/grid_utility.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/base/util/grid_utility.dart b/lib/base/util/grid_utility.dart index a0dd39a3..11a9a787 100644 --- a/lib/base/util/grid_utility.dart +++ b/lib/base/util/grid_utility.dart @@ -25,6 +25,10 @@ class GridUtility { } } + static int campusEventsCrossAxisCount(BuildContext context) { + return DeviceService.getType(context) == Device.phone ? 1 : 2; + } + static int campusNumberOfItems(BuildContext context) { switch (DeviceService.getType(context)) { case Device.landscapeTablet: From 9ea6b52ef518efe48332e7ec20501a154cd7baf3 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 22:49:10 +0200 Subject: [PATCH 7/8] fix: remove regex parsing --- .../model/heilbronn_event.dart | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lib/campusComponent/model/heilbronn_event.dart b/lib/campusComponent/model/heilbronn_event.dart index da20ba00..3e9cdd60 100644 --- a/lib/campusComponent/model/heilbronn_event.dart +++ b/lib/campusComponent/model/heilbronn_event.dart @@ -24,15 +24,6 @@ class HeilbronnEvent { DateTime? get eventDate => startDate ?? publishedAt; - static final _timeRegExp = RegExp( - r'Time:\s*(.*?)(?=\s*(?:Date:|Time:|Location:|$))', - caseSensitive: false, - ); - static final _locationRegExp = RegExp( - r'Location:\s*(.*?)(?=\s*(?:Date:|Time:|Location:|$))', - caseSensitive: false, - ); - static List listFromRss(String rss) { try { final document = XmlDocument.parse(rss); @@ -47,13 +38,10 @@ class HeilbronnEvent { link: _elementText(item, 'link'), description: description, publishedAt: pubDate, - startDate: DateTime.tryParse(_elementText(item, 'startDate')) ?? - DateTime.tryParse(_elementText(item, 'start-date')), - endDate: DateTime.tryParse(_elementText(item, 'endDate')) ?? - DateTime.tryParse(_elementText(item, 'end-date')), - time: _timeRegExp.firstMatch(description)?.group(1)?.trim(), - location: - _locationRegExp.firstMatch(description)?.group(1)?.trim(), + startDate: DateTime.tryParse(_elementText(item, 'startDate')), + endDate: DateTime.tryParse(_elementText(item, 'endDate')), + time: _nullableText(item, 'time'), + location: _nullableText(item, 'location'), ); }) .where((event) => event.title.isNotEmpty) @@ -75,6 +63,11 @@ class HeilbronnEvent { return elements.isEmpty ? '' : elements.first.innerText.trim(); } + static String? _nullableText(XmlElement item, String name) { + final text = _elementText(item, name); + return text.isEmpty ? null : text; + } + static DateTime? _parsePubDate(String value) { try { return DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US').parse(value); From 692f51ef0113bde5c14a15b2fc403575dab37eb8 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 19 Jun 2026 23:49:07 +0200 Subject: [PATCH 8/8] fix: box overflow error with different text size --- .../heilbronn_events_widget_view.dart | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart index 07689203..449f797d 100644 --- a/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart +++ b/lib/campusComponent/view/heilbronnEvents/heilbronn_events_widget_view.dart @@ -74,22 +74,25 @@ class _HeilbronnEventsWidgetViewState ), ); } + final events = snapshot.data! + .take(GridUtility.campusNumberOfItems(context)) + .toList(); + final textScale = MediaQuery.textScalerOf(context).scale(1); return Padding( padding: EdgeInsets.symmetric(horizontal: context.padding), - child: GridView.count( + child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, - crossAxisCount: GridUtility.campusEventsCrossAxisCount(context), - mainAxisSpacing: context.padding, - crossAxisSpacing: context.padding, - childAspectRatio: 3.25, - children: [ - for (final event in snapshot.data!.take( - GridUtility.campusNumberOfItems(context), - )) - HeilbronnEventCardView(event: event), - ], + itemCount: events.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: GridUtility.campusEventsCrossAxisCount(context), + mainAxisSpacing: context.padding, + crossAxisSpacing: context.padding, + mainAxisExtent: 128 * textScale, + ), + itemBuilder: (context, index) => + HeilbronnEventCardView(event: events[index]), ), ); } else if (snapshot.hasError) {