diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 3b0c70d5..ef21ba25 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,18 +4,15 @@ + + + + + + \ No newline at end of file diff --git a/logging/log-2025-12-13_14-00.txt b/logging/log-2025-12-13_14-00.txt new file mode 100644 index 00000000..9a969866 --- /dev/null +++ b/logging/log-2025-12-13_14-00.txt @@ -0,0 +1,3681 @@ +Performing hot restart... +Syncing files to device Windows... +Restarted application in 792ms. +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 _initializeLogger (package:moonforge/main.dart:127:12) +#2 main (package:moonforge/main.dart:30:3) +#3 _runMain. (dart:ui/hooks.dart:343:23) +💡 Logger initialized with contexts: {LogContext.general, LogContext.sync, LogContext.database} +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:26:7) +#3 DashboardService.fetchStats (package:moonforge/features/home/services/dashboard_service.dart:50:12) +💡 [DashboardService] fetchStats started + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during layout: +A RenderFlex overflowed by 81 pixels on the right. + +The relevant error-causing widget was: + Row Row:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/button_group_m3e-0.3.1/lib/src/button_group_m3e_widget.dart:479:24 +: To inspect this widget in Flutter DevTools, visit: http://127.0.0.1:9100/#/inspector?uri=http%3A%2F%2F127.0.0.1%3A62183%2FTEQGxANBOW4%3D%2F&inspectorRef=inspector-0 +The overflowing RenderFlex has an orientation of Axis.horizontal. +The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and black striped pattern. This is usually caused by the contents being too big for the RenderFlex. + +Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size. +This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView. + +The specific RenderFlex in question is: RenderFlex#6374f relayoutBoundary=up9 OVERFLOWING +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=393.0, 0.0<=h<=56.0) +... size: Size(393.0, 40.0) +... direction: horizontal +... mainAxisAlignment: end +... mainAxisSize: max +... crossAxisAlignment: center +... textDirection: ltr +... verticalDirection: down +... spacing: 0.0 +◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤ +==================================================================================================== +#0 ConditionalLogger.w (package:moonforge/core/utils/logger.dart:105:15) +#1 _AppStateInitializerState.initState. (package:moonforge/core/widgets/app_state_initializer.dart:31:16) +#2 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#3 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1361:11) +! SyncCoordinator provider not registered in AppStateInitializer. +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:28:7) +#3 +💡 [DashboardService] fetchStats completed +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +🐛 Saved last_visited_route to storage box: moonforge_storage +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +🐛 Saved current_campaign_id to storage box: moonforge_storage +dynamic_color: Accent color detected. +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:26:7) +#3 DashboardService.fetchStats (package:moonforge/features/home/services/dashboard_service.dart:50:12) +💡 [DashboardService] fetchStats started +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:28:7) +#3 +💡 [DashboardService] fetchStats completed +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:26:7) +#3 DashboardService.fetchStats (package:moonforge/features/home/services/dashboard_service.dart:50:12) +💡 [DashboardService] fetchStats started +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:28:7) +#3 +💡 [DashboardService] fetchStats completed +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:26:7) +#3 DashboardService.fetchStats (package:moonforge/features/home/services/dashboard_service.dart:50:12) +💡 [DashboardService] fetchStats started +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:28:7) +#3 +💡 [DashboardService] fetchStats completed +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:26:7) +#3 DashboardService.fetchStats (package:moonforge/features/home/services/dashboard_service.dart:50:12) +💡 [DashboardService] fetchStats started + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderCustomMultiChildLayoutBox object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderCustomMultiChildLayoutBox were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Scaffold Scaffold:file:///D:/Nextcloud/04%20BruckCode/Projekte/Moonforge/moonforge/lib/features/open5e_browser/views/open5e_browser_view.dart:361:12 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:419:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#32 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#33 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#34 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#35 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#45 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#46 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#49 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#50 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#77 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#78 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#79 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#84 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#85 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#86 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#87 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#88 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#89 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#90 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#91 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#92 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#93 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#94 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#95 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#96 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#97 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#98 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#99 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#100 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#101 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#102 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#103 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#104 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#105 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#106 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#107 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#108 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#109 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#110 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#111 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#112 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#113 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#114 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#115 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#116 _invoke (dart:ui/hooks.dart:356:13) +#117 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#118 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderCustomMultiChildLayoutBox#b410d relayoutBoundary=up41 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: RenderCustomMultiChildLayoutBox#b410d relayoutBoundary=up41 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child 1: RenderFlex#afbf5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body +... constraints: MISSING +... size: MISSING +... direction: vertical +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... verticalDirection: down +... spacing: 0.0 +... child 1: RenderPadding#c01c9 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=null; fit=null +... constraints: MISSING +... size: MISSING +... padding: EdgeInsets.all(16.0) +... textDirection: ltr +... child: RenderFlex#1bb2c NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... direction: vertical +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... verticalDirection: down +... spacing: 0.0 +... child 1: RenderFlex#95248 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=null; fit=null +... constraints: MISSING +... size: MISSING +... direction: horizontal +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... textDirection: ltr +... verticalDirection: down +... spacing: 0.0 +... child 2: RenderConstrainedBox#4912e NEEDS-LAYOUT NEEDS-PAINT +... parentData: offset=Offset(0.0, 0.0); flex=null; fit=null +... constraints: MISSING +... size: MISSING +... additionalConstraints: BoxConstraints(0.0<=w<=Infinity, h=16.0) +... child 3: RenderMouseRegion#ca93e NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=null; fit=null +... constraints: MISSING +... size: MISSING +... behavior: opaque +... listeners: enter, exit +... cursor: SystemMouseCursor(text) +... child 2: RenderPositionedBox#db9f1 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight +... constraints: MISSING +... size: MISSING +... alignment: Alignment.center +... textDirection: ltr +... widthFactor: expand +... heightFactor: expand +... child: RenderSemanticsAnnotations#36478 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... child: RenderConstrainedBox#ef86c NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... size: MISSING +... additionalConstraints: BoxConstraints(36.0<=w<=Infinity, 36.0<=h<=Infinity) +... child 2: RenderConstrainedBox#f54ce NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.appBar +... constraints: MISSING +... size: MISSING +... additionalConstraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=56.0) +... child: RenderSemanticsAnnotations#b47fc NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... semantic boundary +... size: MISSING +... child: RenderAnnotatedRegion#a187c NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: +... constraints: MISSING +... size: MISSING +... child: RenderPhysicalModel#34639 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... size: MISSING +... elevation: 0.0 +... color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shape: BoxShape.rectangle +... borderRadius: BorderRadius.zero +... child 3: RenderStack#1f202 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.floatingActionButton +... constraints: MISSING +... size: MISSING +... alignment: Alignment.centerRight +... textDirection: ltr +... fit: loose +... child 1: RenderTransform#89b22 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... transform matrix: [0] 0.0,0.0,0.0,0.0 +[1] 0.0,0.0,0.0,0.0 +[2] 0.0,0.0,1.0,0.0 +[3] 0.0,0.0,0.0,1.0 +... origin: null +... alignment: Alignment.center +... textDirection: ltr +... transformHitTests: true +... child: RenderTransform#e0fd0 NEEDS-LAYOUT NEEDS-PAINT +... parentData: +... constraints: MISSING +... size: MISSING +... transform matrix: [0] 0.7,0.7,0.0,0.0 +[1] -0.7,0.7,0.0,0.0 +[2] 0.0,0.0,1.0,0.0 +[3] 0.0,0.0,0.0,1.0 +... origin: null +... alignment: Alignment.center +... textDirection: ltr +... transformHitTests: true +==================================================================================================== +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +🐛 Saved last_visited_route to storage box: moonforge_storage + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderInkFeatures object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderInkFeatures were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Scaffold Scaffold:file:///D:/Nextcloud/04%20BruckCode/Projekte/Moonforge/moonforge/lib/features/open5e_browser/views/open5e_browser_view.dart:361:12 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#32 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#33 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#45 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#46 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#47 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#48 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#70 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#71 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#77 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#78 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#79 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#84 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#85 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#86 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#87 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#88 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#89 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#90 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#91 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#92 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#93 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#94 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#95 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#96 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#97 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#98 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#99 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#100 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#101 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#102 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#103 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#104 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#105 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#106 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#107 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#108 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#109 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#110 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#111 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#112 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#113 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#114 _invoke (dart:ui/hooks.dart:356:13) +#115 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#116 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderInkFeatures#1340d relayoutBoundary=up40 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: _RenderInkFeatures#1340d relayoutBoundary=up40 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: RenderCustomMultiChildLayoutBox#b410d relayoutBoundary=up41 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child 1: RenderFlex#afbf5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body +... constraints: MISSING +... size: MISSING +... direction: vertical +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... verticalDirection: down +... spacing: 0.0 +... child 1: RenderPadding#c01c9 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=null; fit=null +... constraints: MISSING +... size: MISSING +... padding: EdgeInsets.all(16.0) +... textDirection: ltr +... child: RenderFlex#1bb2c NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... direction: vertical +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... verticalDirection: down +... spacing: 0.0 +... child 2: RenderPositionedBox#db9f1 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight +... constraints: MISSING +... size: MISSING +... alignment: Alignment.center +... textDirection: ltr +... widthFactor: expand +... heightFactor: expand +... child: RenderSemanticsAnnotations#36478 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... child 2: RenderConstrainedBox#f54ce NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.appBar +... constraints: MISSING +... size: MISSING +... additionalConstraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=56.0) +... child: RenderSemanticsAnnotations#b47fc NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... semantic boundary +... size: MISSING +... child: RenderAnnotatedRegion#a187c NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: +... constraints: MISSING +... size: MISSING +... child 3: RenderStack#1f202 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.floatingActionButton +... constraints: MISSING +... size: MISSING +... alignment: Alignment.centerRight +... textDirection: ltr +... fit: loose +... child 1: RenderTransform#89b22 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... transform matrix: [0] 0.0,0.0,0.0,0.0 +[1] 0.0,0.0,0.0,0.0 +[2] 0.0,0.0,1.0,0.0 +[3] 0.0,0.0,0.0,1.0 +... origin: null +... alignment: Alignment.center +... textDirection: ltr +... transformHitTests: true +... child: RenderTransform#e0fd0 NEEDS-LAYOUT NEEDS-PAINT +... parentData: +... constraints: MISSING +... size: MISSING +... transform matrix: [0] 0.7,0.7,0.0,0.0 +[1] -0.7,0.7,0.0,0.0 +[2] 0.0,0.0,1.0,0.0 +[3] 0.0,0.0,0.0,1.0 +... origin: null +... alignment: Alignment.center +... textDirection: ltr +... transformHitTests: true +==================================================================================================== +#0 ConditionalLogger.i (package:moonforge/core/utils/logger.dart:92:15) +#1 BaseService.logInfo (package:moonforge/core/services/base_service.dart:12:12) +#2 BaseService.execute (package:moonforge/core/services/base_service.dart:28:7) +#3 +💡 [DashboardService] fetchStats completed + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderPhysicalModel object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderPhysicalModel were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Scaffold Scaffold:file:///D:/Nextcloud/04%20BruckCode/Projekte/Moonforge/moonforge/lib/features/open5e_browser/views/open5e_browser_view.dart:361:12 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#6 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#7 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#31 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#39 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#40 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#45 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#46 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#68 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#69 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#70 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#71 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#77 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#78 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#79 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#84 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#85 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#86 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#87 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#88 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#89 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#90 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#91 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#92 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#93 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#94 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#95 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#96 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#97 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#98 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#99 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#100 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#101 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#102 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#103 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#104 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#105 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#106 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#107 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#108 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#109 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#110 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#111 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#112 _invoke (dart:ui/hooks.dart:356:13) +#113 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#114 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderPhysicalModel#bf64a relayoutBoundary=up39 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... elevation: 0.0 +... color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shape: BoxShape.rectangle +... borderRadius: BorderRadius.zero +RenderObject: RenderPhysicalModel#bf64a relayoutBoundary=up39 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + elevation: 0.0 + color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) + shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) + shape: BoxShape.rectangle + borderRadius: BorderRadius.zero +... child: _RenderInkFeatures#1340d relayoutBoundary=up40 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderCustomMultiChildLayoutBox#b410d relayoutBoundary=up41 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child 1: RenderFlex#afbf5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body +... constraints: MISSING +... size: MISSING +... direction: vertical +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... verticalDirection: down +... spacing: 0.0 +... child 1: RenderPadding#c01c9 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=null; fit=null +... constraints: MISSING +... size: MISSING +... padding: EdgeInsets.all(16.0) +... textDirection: ltr +... child 2: RenderPositionedBox#db9f1 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight +... constraints: MISSING +... size: MISSING +... alignment: Alignment.center +... textDirection: ltr +... widthFactor: expand +... heightFactor: expand +... child 2: RenderConstrainedBox#f54ce NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.appBar +... constraints: MISSING +... size: MISSING +... additionalConstraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=56.0) +... child: RenderSemanticsAnnotations#b47fc NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... semantic boundary +... size: MISSING +... child 3: RenderStack#1f202 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.floatingActionButton +... constraints: MISSING +... size: MISSING +... alignment: Alignment.centerRight +... textDirection: ltr +... fit: loose +... child 1: RenderTransform#89b22 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... transform matrix: [0] 0.0,0.0,0.0,0.0 +[1] 0.0,0.0,0.0,0.0 +[2] 0.0,0.0,1.0,0.0 +[3] 0.0,0.0,0.0,1.0 +... origin: null +... alignment: Alignment.center +... textDirection: ltr +... transformHitTests: true +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderSemanticsAnnotations object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderSemanticsAnnotations were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#22 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#23 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#28 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#32 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#33 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#34 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#35 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#42 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#43 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#60 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#61 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#62 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#63 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#64 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#72 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#73 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#74 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#75 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#76 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#77 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#79 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#80 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#81 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#84 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#85 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#86 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#87 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#88 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#89 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#90 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#91 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#92 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#93 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#94 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#95 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#96 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#97 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#98 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#99 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#100 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#101 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#102 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#103 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#104 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#105 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#106 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#107 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#108 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#109 _invoke (dart:ui/hooks.dart:356:13) +#110 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#111 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderSemanticsAnnotations#149f2 relayoutBoundary=up38 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: RenderSemanticsAnnotations#149f2 relayoutBoundary=up38 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: RenderPhysicalModel#bf64a relayoutBoundary=up39 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... elevation: 0.0 +... color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shape: BoxShape.rectangle +... borderRadius: BorderRadius.zero +... child: _RenderInkFeatures#1340d relayoutBoundary=up40 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderCustomMultiChildLayoutBox#b410d relayoutBoundary=up41 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child 1: RenderFlex#afbf5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.body +... constraints: MISSING +... size: MISSING +... direction: vertical +... mainAxisAlignment: start +... mainAxisSize: max +... crossAxisAlignment: center +... verticalDirection: down +... spacing: 0.0 +... child 2: RenderConstrainedBox#f54ce NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.appBar +... constraints: MISSING +... size: MISSING +... additionalConstraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=56.0) +... child 3: RenderStack#1f202 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.floatingActionButton +... constraints: MISSING +... size: MISSING +... alignment: Alignment.centerRight +... textDirection: ltr +... fit: loose +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderRepaintBoundary object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderRepaintBoundary were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#26 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#32 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#33 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#40 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#41 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#60 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#61 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#62 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#72 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#73 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#74 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#75 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#76 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#77 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#79 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#82 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#83 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#84 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#85 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#86 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#87 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#88 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#89 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#90 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#91 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#92 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#93 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#94 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#95 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#96 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#97 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#98 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#99 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#100 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#101 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#102 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#103 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#104 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#105 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#106 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#107 _invoke (dart:ui/hooks.dart:356:13) +#108 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#109 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderRepaintBoundary#90593 relayoutBoundary=up37 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +RenderObject: RenderRepaintBoundary#90593 relayoutBoundary=up37 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + needs compositing + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + usefulness ratio: no metrics collected yet (never painted) +... child: RenderSemanticsAnnotations#149f2 relayoutBoundary=up38 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderPhysicalModel#bf64a relayoutBoundary=up39 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... elevation: 0.0 +... color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shape: BoxShape.rectangle +... borderRadius: BorderRadius.zero +... child: _RenderInkFeatures#1340d relayoutBoundary=up40 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderCustomMultiChildLayoutBox#b410d relayoutBoundary=up41 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderIgnorePointer object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderIgnorePointer were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#24 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#38 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#39 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#60 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#72 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#73 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#74 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#75 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#76 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#77 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#78 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#79 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#80 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#81 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#84 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#85 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#86 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#87 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#88 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#89 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#90 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#91 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#92 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#93 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#94 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#95 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#96 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#97 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#98 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#99 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#100 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#101 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#102 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#103 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#104 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#105 _invoke (dart:ui/hooks.dart:356:13) +#106 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#107 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderIgnorePointer#e4bc5 relayoutBoundary=up36 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +RenderObject: RenderIgnorePointer#e4bc5 relayoutBoundary=up36 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + ignoring: false + ignoringSemantics: null +... child: RenderRepaintBoundary#90593 relayoutBoundary=up37 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... child: RenderSemanticsAnnotations#149f2 relayoutBoundary=up38 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderPhysicalModel#bf64a relayoutBoundary=up39 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... elevation: 0.0 +... color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shape: BoxShape.rectangle +... borderRadius: BorderRadius.zero +... child: _RenderInkFeatures#1340d relayoutBoundary=up40 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderSnapshotWidget object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderSnapshotWidget were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#22 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#23 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#24 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#36 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#37 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#58 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#72 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#73 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#74 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#75 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#77 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#78 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#79 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#84 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#85 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#86 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#87 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#88 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#89 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#90 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#91 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#92 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#93 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#94 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#95 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#96 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#97 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#98 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#99 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#100 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#101 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#102 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#103 _invoke (dart:ui/hooks.dart:356:13) +#104 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#105 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderSnapshotWidget#42be5 relayoutBoundary=up35 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: _RenderSnapshotWidget#42be5 relayoutBoundary=up35 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: RenderIgnorePointer#e4bc5 relayoutBoundary=up36 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +... child: RenderRepaintBoundary#90593 relayoutBoundary=up37 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... child: RenderSemanticsAnnotations#149f2 relayoutBoundary=up38 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderPhysicalModel#bf64a relayoutBoundary=up39 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... elevation: 0.0 +... color: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shadowColor: Color(alpha: 1.0000, red: 0.0902, green: 0.0706, blue: 0.0863, colorSpace: ColorSpace.sRGB) +... shape: BoxShape.rectangle +... borderRadius: BorderRadius.zero +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderSnapshotWidget object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderSnapshotWidget were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#20 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#21 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#22 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#23 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#24 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#27 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#34 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#35 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#56 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#72 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#73 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#76 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#77 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#78 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#79 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#82 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#83 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#84 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#85 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#86 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#87 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#88 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#89 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#90 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#91 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#92 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#93 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#94 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#95 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#96 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#97 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#98 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#99 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#100 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#101 _invoke (dart:ui/hooks.dart:356:13) +#102 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#103 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderSnapshotWidget#b0a35 relayoutBoundary=up34 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: _RenderSnapshotWidget#b0a35 relayoutBoundary=up34 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#42be5 relayoutBoundary=up35 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderIgnorePointer#e4bc5 relayoutBoundary=up36 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +... child: RenderRepaintBoundary#90593 relayoutBoundary=up37 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... child: RenderSemanticsAnnotations#149f2 relayoutBoundary=up38 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +#3 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:178:9) +🐛 Saved https://api.open5e.com/v2/creatures/?format=api_page_1 to storage box: open5e_cache +#0 ConditionalLogger.e (package:moonforge/core/utils/logger.dart:118:13) +#1 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:200:14) +#2 +#3 BestiaryProvider._loadCachedData (package:moonforge/core/providers/bestiary_provider.dart:39:24) +⛔ Failed to fetch from Open5e: FormatException: Unexpected character (at line 5, character 1) +⛔ +⛔ ^ +⛔ + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderSnapshotWidget object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderSnapshotWidget were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#18 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#22 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#23 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#24 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#25 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#32 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#33 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#74 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#75 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#77 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#78 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#79 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#80 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#81 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#82 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#83 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#84 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#85 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#86 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#87 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#88 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#89 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#90 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#91 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#92 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#93 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#94 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#95 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#96 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#97 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#98 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#99 _invoke (dart:ui/hooks.dart:356:13) +#100 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#101 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderSnapshotWidget#0be80 relayoutBoundary=up33 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: _RenderSnapshotWidget#0be80 relayoutBoundary=up33 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#b0a35 relayoutBoundary=up34 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#42be5 relayoutBoundary=up35 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderIgnorePointer#e4bc5 relayoutBoundary=up36 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +... child: RenderRepaintBoundary#90593 relayoutBoundary=up37 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderSnapshotWidget object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderSnapshotWidget were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#16 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#22 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#23 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#30 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#31 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#70 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#71 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#72 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#73 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#76 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#77 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#78 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#79 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#80 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#81 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#82 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#83 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#84 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#85 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#86 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#87 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#88 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#89 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#90 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#91 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#92 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#93 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#94 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#95 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#96 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#97 _invoke (dart:ui/hooks.dart:356:13) +#98 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#99 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderSnapshotWidget#a94dc relayoutBoundary=up32 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: _RenderSnapshotWidget#a94dc relayoutBoundary=up32 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#0be80 relayoutBoundary=up33 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#b0a35 relayoutBoundary=up34 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#42be5 relayoutBoundary=up35 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderIgnorePointer#e4bc5 relayoutBoundary=up36 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderRepaintBoundary object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderRepaintBoundary were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#14 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#28 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#29 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#68 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#69 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#70 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#71 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#76 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#77 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#78 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#79 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#80 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#81 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#82 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#83 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#84 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#85 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#86 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#87 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#88 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#89 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#90 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#91 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#92 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#93 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#94 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#95 _invoke (dart:ui/hooks.dart:356:13) +#96 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#97 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderRepaintBoundary#e1319 relayoutBoundary=up31 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +RenderObject: RenderRepaintBoundary#e1319 relayoutBoundary=up31 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + needs compositing + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + usefulness ratio: no metrics collected yet (never painted) +... child: _RenderSnapshotWidget#a94dc relayoutBoundary=up32 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#0be80 relayoutBoundary=up33 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#b0a35 relayoutBoundary=up34 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#42be5 relayoutBoundary=up35 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderSemanticsAnnotations object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderSemanticsAnnotations were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#12 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#26 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#27 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#66 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#67 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#68 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#69 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#70 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#71 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#74 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#75 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#76 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#77 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#79 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#80 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#81 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#82 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#83 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#84 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#85 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#86 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#87 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#88 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#89 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#90 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#91 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#92 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#93 _invoke (dart:ui/hooks.dart:356:13) +#94 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#95 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderSemanticsAnnotations#aecc0 relayoutBoundary=up30 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: RenderSemanticsAnnotations#aecc0 relayoutBoundary=up30 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: RenderRepaintBoundary#e1319 relayoutBoundary=up31 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... child: _RenderSnapshotWidget#a94dc relayoutBoundary=up32 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#0be80 relayoutBoundary=up33 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#b0a35 relayoutBoundary=up34 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderOffstage object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderOffstage were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#6 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#7 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#10 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#24 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#25 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#58 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#60 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#63 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#64 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#65 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#66 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#67 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#68 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#69 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#70 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#71 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#72 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#73 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#74 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#75 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#76 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#77 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#79 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#80 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#81 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#82 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#83 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#84 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#85 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#86 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#87 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#88 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#89 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#90 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#91 _invoke (dart:ui/hooks.dart:356:13) +#92 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#93 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderOffstage#10e96 relayoutBoundary=up29 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +RenderObject: RenderOffstage#10e96 relayoutBoundary=up29 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + offstage: false +... child: RenderSemanticsAnnotations#aecc0 relayoutBoundary=up30 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderRepaintBoundary#e1319 relayoutBoundary=up31 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... child: _RenderSnapshotWidget#a94dc relayoutBoundary=up32 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: _RenderSnapshotWidget#0be80 relayoutBoundary=up33 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderSemanticsAnnotations object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderSemanticsAnnotations were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1084:13) +#7 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1420:7) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#21 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#22 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#23 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#24 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#32 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#33 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#34 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#35 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#36 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#37 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#38 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#39 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#40 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#60 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#61 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#62 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#63 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#64 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#69 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#70 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#71 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#76 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#77 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#79 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#80 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#81 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#82 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#83 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#84 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#85 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#86 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#87 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#88 _invoke (dart:ui/hooks.dart:356:13) +#89 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#90 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderSemanticsAnnotations#c17aa relayoutBoundary=up28 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: RenderSemanticsAnnotations#c17aa relayoutBoundary=up28 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: RenderOffstage#10e96 relayoutBoundary=up29 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... child: RenderSemanticsAnnotations#aecc0 relayoutBoundary=up30 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderRepaintBoundary#e1319 relayoutBoundary=up31 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... child: _RenderSnapshotWidget#a94dc relayoutBoundary=up32 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderTheater object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderTheater were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1422:7) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#11 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#18 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#19 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#45 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#46 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#60 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#61 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#62 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#63 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#64 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#65 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#66 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#67 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#68 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#72 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#73 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#74 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#75 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#76 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#77 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#78 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#79 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#80 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#81 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#82 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#83 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#84 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#85 _invoke (dart:ui/hooks.dart:356:13) +#86 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#87 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderTheater#e93ca relayoutBoundary=up27 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... skipCount: 0 +... textDirection: ltr +RenderObject: _RenderTheater#e93ca relayoutBoundary=up27 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + skipCount: 0 + textDirection: ltr +... onstage 1: RenderIgnorePointer#241c5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... ignoring: false +... ignoringSemantics: null +... child: RenderBlockSemantics#59afa NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... blocks semantics of earlier render objects below the common boundary +... size: MISSING +... blocking: true +... child: RenderExcludeSemantics#8dfcf NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... size: MISSING +... excluding: true +... child: RenderSemanticsGestureHandler#ab3fa NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... size: MISSING +... behavior: opaque +... gestures: +... onstage 2: RenderSemanticsAnnotations#c17aa relayoutBoundary=up28 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderOffstage#10e96 relayoutBoundary=up29 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... child: RenderSemanticsAnnotations#aecc0 relayoutBoundary=up30 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderRepaintBoundary#e1319 relayoutBoundary=up31 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... usefulness ratio: no metrics collected yet (never painted) +... no offstage children +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderAbsorbPointer object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderAbsorbPointer were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#9 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#16 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#17 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#39 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#40 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#45 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#46 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#58 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#59 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#60 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#61 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#62 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#63 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#64 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#65 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#66 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#71 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#72 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#73 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#74 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#75 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#76 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#77 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#78 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#79 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#80 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#81 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#82 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#83 _invoke (dart:ui/hooks.dart:356:13) +#84 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#85 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderAbsorbPointer#3b03d relayoutBoundary=up26 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... absorbing: false +... ignoringSemantics: null +RenderObject: RenderAbsorbPointer#3b03d relayoutBoundary=up26 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + absorbing: false + ignoringSemantics: null +... child: _RenderTheater#e93ca relayoutBoundary=up27 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... skipCount: 0 +... textDirection: ltr +... onstage 1: RenderIgnorePointer#241c5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... ignoring: false +... ignoringSemantics: null +... child: RenderBlockSemantics#59afa NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... blocks semantics of earlier render objects below the common boundary +... size: MISSING +... blocking: true +... child: RenderExcludeSemantics#8dfcf NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... size: MISSING +... excluding: true +... onstage 2: RenderSemanticsAnnotations#c17aa relayoutBoundary=up28 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderOffstage#10e96 relayoutBoundary=up29 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... child: RenderSemanticsAnnotations#aecc0 relayoutBoundary=up30 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... no offstage children +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderPointerListener object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderPointerListener were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Navigator-[LabeledGlobalKey#ed6e7] Navigator:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/builder.dart:460:16 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#14 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#15 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#37 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#38 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#39 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#40 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#45 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#46 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#53 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#55 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#56 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#57 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#60 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#61 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#62 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#63 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#64 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#68 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#69 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#70 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#71 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#72 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#73 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#74 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#75 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#76 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#77 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#78 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#79 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#80 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#81 _invoke (dart:ui/hooks.dart:356:13) +#82 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#83 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderPointerListener#29e3f relayoutBoundary=up25 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... behavior: deferToChild +... listeners: down, up, cancel +RenderObject: RenderPointerListener#29e3f relayoutBoundary=up25 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + behavior: deferToChild + listeners: down, up, cancel +... child: RenderAbsorbPointer#3b03d relayoutBoundary=up26 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... absorbing: false +... ignoringSemantics: null +... child: _RenderTheater#e93ca relayoutBoundary=up27 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... skipCount: 0 +... textDirection: ltr +... onstage 1: RenderIgnorePointer#241c5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... ignoring: false +... ignoringSemantics: null +... child: RenderBlockSemantics#59afa NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: +... constraints: MISSING +... blocks semantics of earlier render objects below the common boundary +... size: MISSING +... blocking: true +... onstage 2: RenderSemanticsAnnotations#c17aa relayoutBoundary=up28 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderOffstage#10e96 relayoutBoundary=up29 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... no offstage children +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderOffstage object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderOffstage were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + Offstage Offstage:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/route.dart:1671:12 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#6 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#7 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#12 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#13 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#25 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#26 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#27 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#28 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#29 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#35 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#36 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#37 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#38 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#39 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#40 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#41 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#42 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#43 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#44 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#45 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#46 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#51 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#53 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#54 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#55 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#56 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#57 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#60 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#61 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#62 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#68 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#69 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#70 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#71 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#72 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#73 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#74 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#75 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#76 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#77 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#78 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#79 _invoke (dart:ui/hooks.dart:356:13) +#80 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#81 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderOffstage#7f2d8 relayoutBoundary=up24 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +RenderObject: RenderOffstage#7f2d8 relayoutBoundary=up24 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + offstage: false +... child: RenderPointerListener#29e3f relayoutBoundary=up25 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... behavior: deferToChild +... listeners: down, up, cancel +... child: RenderAbsorbPointer#3b03d relayoutBoundary=up26 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... absorbing: false +... ignoringSemantics: null +... child: _RenderTheater#e93ca relayoutBoundary=up27 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... skipCount: 0 +... textDirection: ltr +... onstage 1: RenderIgnorePointer#241c5 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) +... constraints: MISSING +... size: MISSING +... ignoring: false +... ignoringSemantics: null +... onstage 2: RenderSemanticsAnnotations#c17aa relayoutBoundary=up28 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... no offstage children +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +RenderIgnorePointer object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the RenderIgnorePointer were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + IndexedStack IndexedStack:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/route.dart:1663:12 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#7 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#8 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#9 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#10 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#22 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#23 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#24 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#48 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#49 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#50 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#51 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#52 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#57 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#58 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#59 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#60 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#61 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#62 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#63 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#64 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#65 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#66 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#67 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#68 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#69 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#70 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#71 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#72 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#73 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#74 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#75 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#76 _invoke (dart:ui/hooks.dart:356:13) +#77 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#78 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: RenderIgnorePointer#51c8f relayoutBoundary=up23 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +RenderObject: RenderIgnorePointer#51c8f relayoutBoundary=up23 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) + ignoring: false + ignoringSemantics: null +... child: RenderOffstage#7f2d8 relayoutBoundary=up24 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... child: RenderPointerListener#29e3f relayoutBoundary=up25 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... behavior: deferToChild +... listeners: down, up, cancel +... child: RenderAbsorbPointer#3b03d relayoutBoundary=up26 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... absorbing: false +... ignoringSemantics: null +... child: _RenderTheater#e93ca relayoutBoundary=up27 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... skipCount: 0 +... textDirection: ltr +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +_RenderVisibility object was given an infinite size during layout. + +This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size. +The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#9527a relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 0.0<=h<=655.0) +... size: MISSING +... offset: Offset(0.0, -0.0) +The constraints that applied to the _RenderVisibility were: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +The exact size it was given was: Size(964.0, Infinity) + +See https://flutter.dev/to/unbounded-constraints for more information. + +The relevant error-causing widget was: + IndexedStack IndexedStack:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/route.dart:1663:12 +When the exception was thrown, this was the stack: +#0 RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:2620:9) +#1 RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:2771:6) +#2 RenderBox.size=. (package:flutter/src/rendering/box.dart:2363:7) +#3 RenderBox.size= (package:flutter/src/rendering/box.dart:2365:6) +#4 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:114:5) +#5 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#6 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#7 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:645:43) +#8 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#9 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#10 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#11 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#12 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#13 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#14 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#15 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#16 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#17 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#18 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#19 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#20 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#21 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#22 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#23 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#24 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#30 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#31 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#32 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#33 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#41 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#46 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#47 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#48 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#49 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#50 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#51 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#52 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#55 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#56 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#57 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#60 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#61 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#62 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#63 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#64 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#65 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#66 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#67 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#68 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#69 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#70 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#71 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#72 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#73 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#74 _invoke (dart:ui/hooks.dart:356:13) +#75 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#76 _drawFrame (dart:ui/hooks.dart:328:31) +The following RenderObject was being processed when the exception was fired: _RenderVisibility#5b9bb relayoutBoundary=up22 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +RenderObject: _RenderVisibility#5b9bb relayoutBoundary=up22 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) + constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) + size: Size(964.0, Infinity) +... child: RenderIgnorePointer#51c8f relayoutBoundary=up23 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +... child: RenderOffstage#7f2d8 relayoutBoundary=up24 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... child: RenderPointerListener#29e3f relayoutBoundary=up25 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... behavior: deferToChild +... listeners: down, up, cancel +... child: RenderAbsorbPointer#3b03d relayoutBoundary=up26 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... absorbing: false +... ignoringSemantics: null +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during performLayout(): +A Stack requires bounded constraints from its parent. This error commonly occurs when a Stack is placed inside a widget like Column, ListView, or other widgets that do not constrain their children. To fix this, wrap the Stack in a widget that provides finite height and width constraints, such as a SizedBox or ConstrainedBox. Use Expanded only if the parent is a Flex widget like Row or Column. +'package:flutter/src/rendering/stack.dart': +Failed assertion: line 664 pos 7: 'size.isFinite' + + +Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause. +In either case, please report this assertion by filing a bug on GitHub: + https://github.com/flutter/flutter/issues/new?template=02_bug.yml + +The relevant error-causing widget was: + IndexedStack IndexedStack:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/go_router-16.3.0/lib/src/route.dart:1663:12 +When the exception was thrown, this was the stack: +#2 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:664:7) +#3 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:680:12) +#4 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#5 RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14) +#6 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#7 _RenderSingleChildViewport.performLayout (package:flutter/src/widgets/single_child_scroll_view.dart:502:14) +#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#17 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#18 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#19 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#21 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#23 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#24 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11) +#25 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#26 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#27 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#28 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#32 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#33 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#34 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#35 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#36 _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:450:14) +#37 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#38 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#39 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#40 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#41 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#42 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#43 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11) +#44 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:1203:26) +#45 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1257:32) +#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#47 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#49 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#50 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1112:7) +#51 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#52 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#53 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#54 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#55 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#56 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#57 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#58 RenderObject.layout (package:flutter/src/rendering/object.dart:2775:7) +#59 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#60 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2623:7) +#61 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:18) +#62 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1183:15) +#63 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:629:23) +#64 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1264:13) +#65 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#66 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#67 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#68 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1200:5) +#69 _invoke (dart:ui/hooks.dart:356:13) +#70 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:444:5) +#71 _drawFrame (dart:ui/hooks.dart:328:31) +(elided 2 frames from class _AssertionError) +The following RenderObject was being processed when the exception was fired: RenderIndexedStack#5e5cf relayoutBoundary=up21 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(w=964.0, 655.0<=h<=Infinity) +... size: Size(964.0, 655.0) +... alignment: AlignmentDirectional.topStart +... textDirection: ltr +... fit: loose +... index: 3 +RenderObject: RenderIndexedStack#5e5cf relayoutBoundary=up21 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE + needs compositing + parentData: (can use size) + constraints: BoxConstraints(w=964.0, 655.0<=h<=Infinity) + size: Size(964.0, 655.0) + alignment: AlignmentDirectional.topStart + textDirection: ltr + fit: loose + index: 3 +... child 1: _RenderVisibility#4dcc3 relayoutBoundary=up22 NEEDS-PAINT +... needs compositing +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... child: RenderIgnorePointer#99e30 relayoutBoundary=up23 NEEDS-PAINT +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... ignoring: false +... ignoringSemantics: null +... child: RenderOffstage#0304a NEEDS-PAINT +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... offstage: true +... child: RenderPointerListener#11ae2 NEEDS-PAINT +... needs compositing +... parentData: +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, 496.0) +... behavior: deferToChild +... listeners: down, up, cancel +... child 2: _RenderVisibility#0341d relayoutBoundary=up22 NEEDS-PAINT +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... child: RenderIgnorePointer#91c9a relayoutBoundary=up23 NEEDS-PAINT +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... ignoring: false +... ignoringSemantics: null +... child: RenderOffstage#de3a4 NEEDS-PAINT +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... offstage: true +... child: RenderConstrainedBox#c4ff4 NEEDS-PAINT +... parentData: +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... additionalConstraints: BoxConstraints(w=0.0, h=0.0) +... child 3: _RenderVisibility#708b4 relayoutBoundary=up22 NEEDS-PAINT +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... child: RenderIgnorePointer#32bc8 relayoutBoundary=up23 NEEDS-PAINT +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... ignoring: false +... ignoringSemantics: null +... child: RenderOffstage#d8c3c NEEDS-PAINT +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... offstage: true +... child: RenderConstrainedBox#a92d4 NEEDS-PAINT +... parentData: +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... additionalConstraints: BoxConstraints(w=0.0, h=0.0) +... child 4: _RenderVisibility#5b9bb relayoutBoundary=up22 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... child: RenderIgnorePointer#51c8f relayoutBoundary=up23 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... ignoring: false +... ignoringSemantics: null +... child: RenderOffstage#7f2d8 relayoutBoundary=up24 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... offstage: false +... child: RenderPointerListener#29e3f relayoutBoundary=up25 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(964.0, Infinity) +... behavior: deferToChild +... listeners: down, up, cancel +... child 5: _RenderVisibility#408fe relayoutBoundary=up22 NEEDS-PAINT +... parentData: not positioned; offset=Offset(0.0, 0.0) (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... child: RenderIgnorePointer#135cc relayoutBoundary=up23 NEEDS-PAINT +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... ignoring: false +... ignoringSemantics: null +... child: RenderOffstage#05a31 NEEDS-PAINT +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... offstage: true +... child: RenderConstrainedBox#98334 NEEDS-PAINT +... parentData: +... constraints: BoxConstraints(0.0<=w<=964.0, 0.0<=h<=Infinity) +... size: Size(0.0, 0.0) +... additionalConstraints: BoxConstraints(w=0.0, h=0.0) +==================================================================================================== + +======== Exception caught by rendering library ===================================================== +The following assertion was thrown during layout: +A RenderFlex overflowed by 81 pixels on the right. + +The relevant error-causing widget was: + Row Row:file:///C:/Users/emily/AppData/Local/Pub/Cache/hosted/pub.dev/button_group_m3e-0.3.1/lib/src/button_group_m3e_widget.dart:479:24 +: To inspect this widget in Flutter DevTools, visit: http://127.0.0.1:9100/#/inspector?uri=http%3A%2F%2F127.0.0.1%3A62183%2FTEQGxANBOW4%3D%2F&inspectorRef=inspector-468 +The overflowing RenderFlex has an orientation of Axis.horizontal. +The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and black striped pattern. This is usually caused by the contents being too big for the RenderFlex. + +Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size. +This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView. + +The specific RenderFlex in question is: RenderFlex#77491 relayoutBoundary=up9 OVERFLOWING +... needs compositing +... parentData: (can use size) +... constraints: BoxConstraints(0.0<=w<=393.0, 0.0<=h<=56.0) +... size: Size(393.0, 40.0) +... direction: horizontal +... mainAxisAlignment: end +... mainAxisSize: max +... crossAxisAlignment: center +... textDirection: ltr +... verticalDirection: down +... spacing: 0.0 +◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤ +==================================================================================================== +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +#3 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:178:9) +🐛 Saved https://api.open5e.com/v2/creatures/?format=api_page_1 to storage box: open5e_cache +#0 ConditionalLogger.e (package:moonforge/core/utils/logger.dart:118:13) +#1 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:200:14) +#2 +#3 BestiaryProvider._loadCachedData (package:moonforge/core/providers/bestiary_provider.dart:39:24) +⛔ Failed to fetch from Open5e: FormatException: Unexpected character (at line 5, character 1) +⛔ +⛔ ^ +⛔ +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +#3 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:178:9) +🐛 Saved https://api.open5e.com/v2/creatures/?format=api_page_1 to storage box: open5e_cache +#0 ConditionalLogger.e (package:moonforge/core/utils/logger.dart:118:13) +#1 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:200:14) +#2 +#3 BestiaryProvider._loadCachedData (package:moonforge/core/providers/bestiary_provider.dart:39:24) +⛔ Failed to fetch from Open5e: FormatException: Unexpected character (at line 5, character 1) +⛔ +⛔ ^ +⛔ +#0 ConditionalLogger.d (package:moonforge/core/utils/logger.dart:79:15) +#1 PersistenceService.write (package:moonforge/core/services/persistence_service.dart:62:14) +#2 +#3 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:178:9) +🐛 Saved https://api.open5e.com/v2/creatures/?format=api_page_1_limit_50_gs_5e-2024 to storage box: open5e_cache +#0 ConditionalLogger.e (package:moonforge/core/utils/logger.dart:118:13) +#1 Open5eClient.fetchList (package:moonforge/core/services/open5e/open5e_service_v2.dart:200:14) +#2 +#3 _Open5eBrowserViewState._loadData (package:moonforge/features/open5e_browser/views/open5e_browser_view.dart:137:22) +⛔ Failed to fetch from Open5e: FormatException: Unexpected character (at line 5, character 1) +⛔ +⛔ ^ +⛔ diff --git a/moonforge/lib/core/providers/bestiary_provider.dart b/moonforge/lib/core/providers/bestiary_provider.dart index a6b13f83..f733f382 100644 --- a/moonforge/lib/core/providers/bestiary_provider.dart +++ b/moonforge/lib/core/providers/bestiary_provider.dart @@ -1,24 +1,22 @@ import 'package:moonforge/core/models/async_state.dart'; import 'package:moonforge/core/providers/base_async_provider.dart'; -import 'package:moonforge/core/services/bestiary_service.dart'; +import 'package:moonforge/core/services/open5e/index.dart'; import 'package:moonforge/core/services/persistence_service.dart'; import 'package:moonforge/core/utils/logger.dart'; -import 'package:moonforge/data/models/monster.dart'; -/// Provider for managing bestiary data -class BestiaryProvider extends BaseAsyncProvider> { - final BestiaryService _bestiaryService; +/// Provider for managing bestiary data using Open5e API v2 +class BestiaryProvider extends BaseAsyncProvider> { + final Open5eService _open5eService; DateTime? _lastSync; - BestiaryProvider({BestiaryService? bestiaryService}) - : _bestiaryService = - bestiaryService ?? BestiaryService(PersistenceService()) { + BestiaryProvider({Open5eService? open5eService}) + : _open5eService = open5eService ?? Open5eService(PersistenceService()) { // Load cached data on initialization _loadCachedData(); } - /// Get all monsters - List get monsters => state.dataOrNull ?? const []; + /// Get all creatures + List get creatures => state.dataOrNull ?? const []; /// Check if data is currently loading bool get isLoading => state.isLoading; @@ -32,39 +30,53 @@ class BestiaryProvider extends BaseAsyncProvider> { /// Get last sync timestamp DateTime? get lastSync => _lastSync; - /// Check if data is cached locally - bool get isCached => _bestiaryService.isCached(); + /// Check if we have attempted to load data (not necessarily that cache exists) + bool get hasLoadedData => creatures.isNotEmpty || _lastSync != null; /// Load cached data without triggering sync Future _loadCachedData() async { - if (!_bestiaryService.isCached()) return; - try { - final cached = await _bestiaryService.getAll(ensureFresh: false); - updateState(AsyncState.data(cached)); - _lastSync = _bestiaryService.getLastSyncTime(); + final response = await _open5eService.getCreatures( + options: Open5eQueryOptions(page: 1), + useCache: true, + ); + + if (response != null && response.results.isNotEmpty) { + updateState(AsyncState.data(response.results)); + _lastSync = DateTime.now(); + } } catch (e) { - // Silent failure is acceptable for cached data loading during initialization - // The user can still trigger a manual load later - logger.d('Failed to load cached bestiary data during initialization: $e'); + // If cache is corrupted, clear it and continue + logger.d('Failed to load cached bestiary data, clearing cache: $e', + context: LogContext.network); + // Clear potentially corrupted cache + try { + await clearCache(); + } catch (clearError) { + logger.w('Failed to clear cache: $clearError', + context: LogContext.database); + } } } - /// Load monsters with optional fresh sync - Future loadMonsters({bool forceSync = false}) async { + /// Load creatures with optional query options + Future loadCreatures({ + Open5eQueryOptions? options, + bool forceSync = false, + }) async { updateState(const AsyncState.loading()); try { - if (forceSync) { - final success = await _bestiaryService.forceSync(); - if (!success) { - updateState(const AsyncState.error('Failed to sync bestiary data')); - return; - } - } + final response = await _open5eService.getCreatures( + options: options ?? Open5eQueryOptions(page: 1), + useCache: !forceSync, + ); - final monsters = await _bestiaryService.getAll(ensureFresh: !forceSync); - updateState(AsyncState.data(monsters)); - _lastSync = _bestiaryService.getLastSyncTime(); + if (response != null) { + updateState(AsyncState.data(response.results)); + _lastSync = DateTime.now(); + } else { + updateState(const AsyncState.error('Failed to load creatures')); + } } catch (e, st) { updateState(AsyncState.error(e, st)); } finally { @@ -74,19 +86,19 @@ class BestiaryProvider extends BaseAsyncProvider> { } } - /// Get a specific monster by name - Future getMonsterByName(String name) { - return _bestiaryService.getByName(name); + /// Get a specific creature by key + Future getCreatureByKey(String key) { + return _open5eService.getCreatureByKey(key); } /// Force refresh from remote Future refresh() async { - await loadMonsters(forceSync: true); + await loadCreatures(forceSync: true); } /// Clear cached data Future clearCache() async { - await _bestiaryService.clearCache(); + await _open5eService.clearCache(); reset(); _lastSync = null; } diff --git a/moonforge/lib/core/repositories/menu_registry.dart b/moonforge/lib/core/repositories/menu_registry.dart index a66ed90f..54fae323 100644 --- a/moonforge/lib/core/repositories/menu_registry.dart +++ b/moonforge/lib/core/repositories/menu_registry.dart @@ -156,7 +156,7 @@ class MenuRegistry { // Read last visited route from persistence final persistenceService = PersistenceService(); final lastRoute = persistenceService.read('last_visited_route'); - + if (lastRoute != null && lastRoute.isNotEmpty) { // Navigate to the persisted route ctx.go(lastRoute); diff --git a/moonforge/lib/core/services/bestiary_service.dart b/moonforge/lib/core/services/bestiary_service.dart deleted file mode 100644 index 356621f9..00000000 --- a/moonforge/lib/core/services/bestiary_service.dart +++ /dev/null @@ -1,344 +0,0 @@ -import 'dart:convert'; - -import 'package:http/http.dart' show Client; -import 'package:moonforge/core/services/persistence_service.dart'; -import 'package:moonforge/core/utils/logger.dart'; -import 'package:moonforge/data/models/monster.dart'; - -/// Service for managing DND 5e bestiary data via Open5e with local caching -class BestiaryService { - static const String _base = 'https://api.open5e.com'; - static const String _monstersEndpoint = 'https://api.open5e.com/v1/monsters/'; - static const String _apiRootManifest = 'https://api.open5e.com/?format=json'; - - static const String _boxName = 'bestiary'; - static const String _manifestKey = - 'open5e_manifest_json'; // stores monsters page/manifest (results) - static const String _apiManifestKey = - 'open5e_api_manifest_json'; // stores api root mapping - - final PersistenceService _persistence; - final Duration staleThreshold; - final Client _client; - - BestiaryService( - this._persistence, { - this.staleThreshold = const Duration(hours: 24), - Client? httpClient, - }) : _client = httpClient ?? Client(); - - /// Get monsters (all pages by default). If page is provided, returns single page. - /// If ensureFresh is true a background sync may be triggered when data is stale. - Future> getAll({ - bool ensureFresh = true, - int? page, - int? pageSize, - }) async { - // If specific page requested, try to fetch that page and return results - if (page != null) { - final key = _listCacheKey(page, pageSize); - final cached = _persistence.read(key, boxName: _boxName); - if (cached != null) { - if (ensureFresh) _maybeBackgroundSync(); - return _parseMonstersFromBody(cached); - } - - final success = await _fetchMonstersPageAndStore( - page: page, - pageSize: pageSize, - ); - if (!success) return []; - final stored = _persistence.read(key, boxName: _boxName); - if (stored == null) return []; - return _parseMonstersFromBody(stored); - } - - // No page requested: try to return cached manifest list if we have one - final cached = _persistence.read(_manifestKey, boxName: _boxName); - if (cached != null) { - if (ensureFresh) _maybeBackgroundSync(); - final decoded = jsonDecode(cached); - if (decoded is Map && decoded.containsKey('results')) { - final results = decoded['results'] as List; - return results - .whereType>() - .map((m) => Monster.fromOpen5eJson(m)) - .toList(); - } - } - - // Fallback: fetch first page and store manifest key - final success = await _fetchMonstersPageAndStore( - page: 1, - pageSize: pageSize, - storeAsManifest: true, - ); - if (!success) return []; - final stored = _persistence.read(_manifestKey, boxName: _boxName); - if (stored == null) return []; - final decoded = jsonDecode(stored); - if (decoded is Map && decoded.containsKey('results')) { - final results = decoded['results'] as List; - return results - .whereType>() - .map((m) => Monster.fromOpen5eJson(m)) - .toList(); - } - - return []; - } - - /// Fetch and cache Open5e API root manifest (mapping of resource names to endpoints) - Future?> getApiManifest({bool force = false}) async { - final cached = _persistence.read( - _apiManifestKey, - boxName: _boxName, - ); - if (cached != null && !force) { - try { - final decoded = jsonDecode(cached) as Map; - return decoded; - } catch (_) {} - } - - try { - final uri = Uri.parse(_apiRootManifest); - final response = await _client.get(uri); - if (response.statusCode == 200) { - await _persistence.write( - _apiManifestKey, - response.body, - boxName: _boxName, - ); - return jsonDecode(response.body) as Map?; - } - } catch (e) { - logger.w('Failed to fetch Open5e API manifest: $e'); - } - return null; - } - - Future getByName(String name) async { - // Use search endpoint - try { - final uri = Uri.parse( - '$_monstersEndpoint?search=${Uri.encodeQueryComponent(name)}', - ); - final response = await _client.get(uri); - if (response.statusCode == 200) { - final decoded = jsonDecode(response.body); - if (decoded is Map && decoded.containsKey('results')) { - final results = decoded['results'] as List; - for (final r in results) { - if (r is Map && (r['name'] as String?) == name) { - return Monster.fromOpen5eJson(r); - } - } - } - } - } catch (e) { - logger.w('getByName failed: $e'); - } - return null; - } - - Future getBySlug(String slug) async { - final key = _singleCacheKey(slug); - final cached = _persistence.read(key, boxName: _boxName); - if (cached != null) { - try { - final decoded = jsonDecode(cached) as Map; - return Monster.fromOpen5eJson(decoded); - } catch (e) { - logger.w('Failed to parse cached monster $slug: $e'); - } - } - - try { - final url = Uri.parse('$_monstersEndpoint$slug/?format=json'); - final etag = _persistence.read( - _etagKeyForSlug(slug), - boxName: _boxName, - ); - final headers = {}; - if (etag != null) headers['If-None-Match'] = etag; - final response = await _client.get(url, headers: headers); - if (response.statusCode == 200) { - await _persistence.write(key, response.body, boxName: _boxName); - final newEtag = response.headers['etag']; - if (newEtag != null) - await _persistence.write( - _etagKeyForSlug(slug), - newEtag, - boxName: _boxName, - ); - return Monster.fromOpen5eJson( - jsonDecode(response.body) as Map, - ); - } else if (response.statusCode == 304 && cached != null) { - return Monster.fromOpen5eJson( - jsonDecode(cached) as Map, - ); - } - } catch (e) { - logger.w('Failed to fetch monster $slug: $e'); - } - return null; - } - - Future forceSync() async { - // Fetch first page and replace manifest (monsters list) - // Also refresh API manifest mapping - await getApiManifest(force: true); - return _fetchMonstersPageAndStore( - page: 1, - storeAsManifest: true, - force: true, - ); - } - - Future _maybeBackgroundSync() async { - final lastSyncMillis = _persistence.read( - '${_lastSyncKey}', - boxName: _boxName, - ); - if (lastSyncMillis == null || - DateTime.now().difference( - DateTime.fromMillisecondsSinceEpoch(lastSyncMillis), - ) > - staleThreshold) { - // fire and forget - _fetchMonstersPageAndStore(page: 1, storeAsManifest: true) - .then((_) => logger.d('Background Open5e bestiary sync completed')) - .catchError( - (e) => logger.w('Background Open5e bestiary sync failed: $e'), - ); - } - } - - Future _fetchMonstersPageAndStore({ - required int page, - int? pageSize, - bool storeAsManifest = false, - bool force = false, - String resourceName = 'monsters', - }) async { - final key = storeAsManifest ? _manifestKey : _listCacheKey(page, pageSize); - try { - // Prefer API manifest mapping if available - String endpoint = _monstersEndpoint; - final apiManifest = await getApiManifest(); - if (apiManifest != null && apiManifest.containsKey(resourceName)) { - endpoint = apiManifest[resourceName] as String? ?? endpoint; - } - - final uri = Uri.parse( - '$endpoint?format=json&page=$page${pageSize != null ? '&page_size=$pageSize' : ''}', - ); - final etagKey = _etagKeyForList(page, pageSize); - final etag = _persistence.read(etagKey, boxName: _boxName); - final headers = {}; - if (etag != null && !force) headers['If-None-Match'] = etag; - - logger.d('Fetching Open5e monsters page $page from $endpoint'); - final response = await _client.get(uri, headers: headers); - if (response.statusCode == 200) { - await _persistence.write(key, response.body, boxName: _boxName); - final newEtag = - response.headers['etag'] ?? _computeLocalEtag(response.body); - if (newEtag != null) - await _persistence.write(etagKey, newEtag, boxName: _boxName); - await _persistence.write( - _lastSyncKey, - DateTime.now().millisecondsSinceEpoch, - boxName: _boxName, - ); - logger.i('Open5e monsters page $page fetched and stored'); - return true; - } else if (response.statusCode == 304) { - // not modified - await _persistence.write( - _lastSyncKey, - DateTime.now().millisecondsSinceEpoch, - boxName: _boxName, - ); - logger.d('Open5e monsters page $page not modified (304)'); - return true; - } else { - logger.e('Open5e fetch failed: HTTP ${response.statusCode}'); - return false; - } - } catch (e) { - logger.e('Failed to fetch Open5e monsters: $e'); - return false; - } - } - - List _parseMonstersFromBody(String body) { - try { - final decoded = jsonDecode(body); - if (decoded is Map && decoded.containsKey('results')) { - final results = decoded['results'] as List; - return results - .whereType>() - .map((m) => Monster.fromOpen5eJson(m)) - .toList(); - } else if (decoded is List) { - return decoded - .whereType>() - .map((m) => Monster.fromOpen5eJson(m)) - .toList(); - } - } catch (e) { - logger.e('Failed to decode monsters JSON: $e'); - } - return []; - } - - String? _computeLocalEtag(String body) { - try { - // simple checksum: use md5 hex - // avoid adding a crypto dependency; use a very small checksum fallback - return body.hashCode.toString(); - } catch (_) { - return null; - } - } - - String _listCacheKey(int page, int? pageSize) => - 'open5e:monsters:page:$page:${pageSize ?? 0}'; - - String _singleCacheKey(String slug) => 'open5e:monster:slug:$slug'; - - String _etagKeyForList(int page, int? pageSize) => - 'open5e:etag:monsters:page:$page:${pageSize ?? 0}'; - - String _etagKeyForSlug(String slug) => 'open5e:etag:monster:slug:$slug'; - - static const String _lastSyncKey = 'bestiary_lastSync'; - - /// Get the last sync timestamp - DateTime? getLastSyncTime() { - final lastSyncMillis = _persistence.read( - _lastSyncKey, - boxName: _boxName, - ); - if (lastSyncMillis == null) return null; - return DateTime.fromMillisecondsSinceEpoch(lastSyncMillis); - } - - /// Check if bestiary data is cached - bool isCached() { - return _persistence.hasData(_manifestKey, boxName: _boxName); - } - - /// Clear all cached bestiary data - Future clearCache() async { - // remove manifest and page keys heuristically - await _persistence.remove(_manifestKey, boxName: _boxName); - await _persistence.remove(_apiManifestKey, boxName: _boxName); - // remove some etag keys could be left behind; best to keep box namespace small - await _persistence.remove(_lastSyncKey, boxName: _boxName); - logger.i('Bestiary cache cleared'); - } -} diff --git a/moonforge/lib/core/services/open5e/README.md b/moonforge/lib/core/services/open5e/README.md new file mode 100644 index 00000000..8b32fa49 --- /dev/null +++ b/moonforge/lib/core/services/open5e/README.md @@ -0,0 +1,425 @@ +# Open5e API v2 Integration + +A comprehensive, type-safe client for the Open5e API v2 (https://api.open5e.com) that fully implements the official API specification. + +## Overview + +This integration provides complete access to all 33 Open5e v2 API endpoints: +- **Creatures** (formerly Monsters), Creature Types, Creature Sets +- **Spells**, Spell Schools +- **Character Options**: Backgrounds, Feats, Species (formerly Races), Classes, Abilities, Skills +- **Equipment**: Items, Magic Items, Weapons, Weapon Properties, Armor +- **Game Mechanics**: Conditions, Damage Types, Languages, Alignments, Sizes, Environments +- **Documentation**: Documents, Licenses, Publishers, Game Systems +- **Rules**: Rules, Rule Sets +- **Media**: Images, Services +- **Item Organization**: Item Sets, Item Categories, Item Rarities + +## Features + +- **Pure v2 API**: All endpoints use v2 API (no legacy v1 endpoints) +- **Type-Safe**: All API responses mapped to strongly-typed Dart models with null safety +- **GameSystem Filtering**: Automatic filtering by game system (5e-2024, 5e-2014, or a5e) +- **Official API Compliance**: Full support for filtering, searching, ordering per official docs +- **Caching**: Built-in caching with ETag support for efficient API usage +- **Pagination**: Automatic handling of paginated API responses +- **Type-Safe Constants**: Pre-defined constants for game systems and documents +- **Error Handling**: Comprehensive error handling with logging +- **Modular Models**: Split into 7 logical modules for better maintainability + +## Official v2 API Features Supported + +### GameSystem Filtering +All requests filter by game system. Defaults to 5e-2024: +```dart +// Default to 5e-2024 (latest rules) +await service.getCreatures( + options: Open5eQueryOptions( + filters: {'challenge_rating_decimal': '3'}, + ), +); + +// Use 5e-2014 rules +await service.getCreatures( + options: Open5eQueryOptions( + gameSystemKey: GameSystemKey.edition2014, + ), +); + +// Use Advanced 5e +await service.getCreatures( + options: Open5eQueryOptions( + gameSystemKey: GameSystemKey.advancedEdition, + ), +); +``` + +### Document Filtering +Limit results to specific source documents using type-safe constants: +```dart +// Only creatures from Tome of Beasts +await service.getCreatures( + options: Open5eQueryOptions( + documentKey: DocumentKey.tomeOfBeasts, + ), +); + +// SRD 2024 content only +await service.getCreatures( + options: Open5eQueryOptions( + documentKey: DocumentKey.srd2024, + ), +); +``` + +### Creature Type Filtering +Filter creatures by type (dragon, undead, humanoid, etc.): +```dart +// Get all dragons from 5e-2024 +await service.getCreatures( + options: Open5eQueryOptions( + creatureType: 'dragon', + ), +); + +// Get all undead from Tome of Beasts +await service.getCreatures( + options: Open5eQueryOptions( + creatureType: 'undead', + documentKey: DocumentKey.tomeOfBeasts, + ), +); +``` + +### Case-Insensitive Search +Partial-word matching on resource names: +```dart +// Find all creatures containing "fir" (matches "fire", "fireball", etc.) +await service.getCreatures( + options: Open5eQueryOptions(search: 'fir'), +); +``` + +### Ordering +Sort results by any field: +```dart +// Order creatures by challenge rating +await service.getCreatures( + options: Open5eQueryOptions(ordering: 'challenge_rating_decimal'), +); + +// Descending order (prefix with -) +await service.getCreatures( + options: Open5eQueryOptions(ordering: '-name'), +); +``` + +### Pagination +Control page size and navigate pages: +```dart +// Custom page size (100 per page) +await service.getCreatures( + options: Open5eQueryOptions(page: 2, limit: 100), +); +``` + +## Usage + +### Basic Setup + +```dart +import 'package:moonforge/core/services/open5e/index.dart'; +import 'package:moonforge/core/services/persistence_service.dart'; + +// Create the service +final persistenceService = PersistenceService(); +final open5eService = Open5eService(persistenceService); +``` + +### Fetching Creatures (formerly Monsters) + +```dart +// Get all creatures from 5e-2024 (default) +final creaturesResponse = await open5eService.getCreatures( + options: Open5eQueryOptions(page: 1), +); + +// Get CR 5 dragons from SRD 2024, ordered by name +final filtered = await open5eService.getCreatures( + options: Open5eQueryOptions( + filters: {'challenge_rating_decimal': '5'}, + creatureType: 'dragon', + documentKey: DocumentKey.srd2024, + ordering: 'name', + ), +); + +// Search for dragons in 5e-2014 rules +final dragons = await open5eService.getCreatures( + options: Open5eQueryOptions( + search: 'dragon', + gameSystemKey: GameSystemKey.edition2014, + ), +); + +// Get a specific creature by key +final aboleth = await open5eService.getCreatureByKey('srd-2024_aboleth'); + +// Get all creature types +final types = await open5eService.getCreatureTypes(); +``` + +### Fetching Spells + +```dart +// Get 3rd level spells from 5e-2024 +final level3Spells = await open5eService.getSpells( + options: Open5eQueryOptions(filters: {'level': '3'}), +); + +// Search for fire spells from 5e-2014 +final fireSpells = await open5eService.getSpells( + options: Open5eQueryOptions( + search: 'fire', + gameSystemKey: GameSystemKey.edition2014, + ), +); + +// Get specific spell by key +final fireball = await open5eService.getSpellByKey('fireball'); + +// Get spell schools +final schools = await open5eService.getSpellSchools(); +``` + +### Fetching Character Options + +```dart +// Get all species (formerly races) +final speciesResponse = await open5eService.getSpecies(); + +// Get classes ordered by name +final classes = await open5eService.getClasses( + options: Open5eQueryOptions(ordering: 'name'), +); + +// Get backgrounds from SRD 2024 +final backgrounds = await open5eService.getBackgrounds( + options: Open5eQueryOptions(documentKey: DocumentKey.srd2024), +); + +// Get feats +final feats = await open5eService.getFeats(); + +// Get abilities and skills +final abilities = await open5eService.getAbilities(); +final skills = await open5eService.getSkills(); +``` + +### Fetching Equipment + +```dart +// Get all items +final items = await open5eService.getItems(); + +// Get magic items from Tome of Beasts +final magicItems = await open5eService.getMagicItems( + options: Open5eQueryOptions( + documentKey: DocumentKey.tomeOfBeasts, + ), +); + +// Search for swords +final swords = await open5eService.getWeapons( + options: Open5eQueryOptions(search: 'sword'), +); + +// Get armor +final armor = await open5eService.getArmor(); + +// Get weapon properties +final weaponProps = await open5eService.getWeaponProperties(); + +// Get item organization +final itemSets = await open5eService.getItemSets(); +final itemCategories = await open5eService.getItemCategories(); +final itemRarities = await open5eService.getItemRarities(); +``` + +### Fetching Game Mechanics + +```dart +// Get conditions +final conditions = await open5eService.getConditions(); + +// Get damage types +final damageTypes = await open5eService.getDamageTypes(); + +// Get languages +final languages = await open5eService.getLanguages(); + +// Get alignments, sizes, environments +final alignments = await open5eService.getAlignments(); +final sizes = await open5eService.getSizes(); +final environments = await open5eService.getEnvironments(); +``` + +### Fetching Documentation + +```dart +// Get all documents +final documents = await open5eService.getDocuments(); + +// Get game systems +final gameSystems = await open5eService.getGameSystems(); + +// Get publishers +final publishers = await open5eService.getPublishers(); + +// Get licenses +final licenses = await open5eService.getLicenses(); +``` + +### Cache Management + +```dart +// Clear all cached data +await open5eService.clearCache(); + +// Fetch with fresh data (bypass cache) +final fresh = await open5eService.getCreatures(useCache: false); +``` + +## Query Options + +The `Open5eQueryOptions` class supports all official v2 API parameters: + +```dart +class Open5eQueryOptions { + final String? search; // Case-insensitive partial-word search + final String? gameSystemKey; // Game system filter (use GameSystemKey constants) + final String? documentKey; // Source document filter (use DocumentKey constants) + final String? creatureType; // Creature type filter (e.g., 'dragon', 'undead') + final String? ordering; // Sort field (prefix with - for descending) + final int page; // Page number (default: 1) + final int? limit; // Results per page + final Map? filters; // Additional filters (e.g., {'challenge_rating_decimal': '5'}) +} +``` + +### Type-Safe Constants + +Use pre-defined constants for common values: + +```dart +// Game Systems +GameSystemKey.edition2024 // '5e-2024' (default) +GameSystemKey.edition2014 // '5e-2014' +GameSystemKey.advancedEdition // 'a5e' + +// Documents +DocumentKey.srd2024 // 'srd-2024' +DocumentKey.srd2014 // 'srd' +DocumentKey.tomeOfBeasts // 'tob' +DocumentKey.tomeOfBeasts2 // 'tob2' +DocumentKey.tomeOfBeasts3 // 'tob3' +DocumentKey.creatureCodex // 'cc' +// ... and more +``` + +You can also fetch available values dynamically: +```dart +// Get all available game systems +final gameSystems = await service.getGameSystems(); + +// Get all available documents +final documents = await service.getDocuments(); + +// Get all creature types for filtering +final creatureTypes = await service.getCreatureTypes(); +``` + +## Model Structure + +Models are organized into 7 logical modules: + +- **common.dart**: `PaginatedResponse`, `Document`, `GameSystem`, `Publisher`, `License` +- **character.dart**: `Background`, `Feat`, `Species`, `CharacterClass`, `Ability`, `Skill` +- **spells.dart**: `Open5eSpell`, `SpellSchool` +- **equipment.dart**: `Item`, `MagicItem`, `Weapon`, `Armor`, `ItemSet`, `ItemCategory`, `ItemRarity`, `WeaponProperty` +- **mechanics.dart**: `Condition`, `DamageType`, `Language`, `Alignment`, `Size`, `Environment` +- **creatures.dart**: `Creature`, `CreatureType`, `CreatureSet` +- **rules.dart**: `Rule`, `RuleSet`, `Open5eImage`, `Open5eService` + +All v2 models have: +- `url`: API endpoint URL +- `key`: Unique identifier +- `name`: Display name +- `desc`: Description +- `document`: Source document with nested publisher and gamesystem (where applicable) + +## Error Handling + +All service methods: +- Return `null` on error (for single items) +- Return `null` on error (for paginated lists) +- Log errors using `LogContext.network` + +Example: +```dart +final spell = await open5eService.getSpellByKey('fireball'); +if (spell == null) { + // Handle error - check logs for details + print('Failed to fetch spell'); +} +``` + +## Testing + +Unit tests are available in `test/core/services/open5e_service_test.dart`. + +Run tests: +```bash +flutter test test/core/services/open5e_service_test.dart +``` + +## API Documentation + +For full API documentation, see: +- Official docs: https://open5e.com/api-docs +- GitHub v2 API: https://github.com/open5e/open5e-api/tree/staging/api_v2 + +## Version Support + +This integration uses **API v2 only** for all endpoints, providing: +- Consistent structure across all resources +- GameSystem filtering +- Rich document metadata with publisher information +- More comprehensive resource coverage (33 endpoints) + +## Migration from BestiaryService + +The old `BestiaryService` has been removed. Use `Open5eService` directly: + +```dart +// OLD (v1/mixed API) +final monsters = await bestiaryService.getAll(page: 1, pageSize: 20); +final dragon = await bestiaryService.getByName('Red Dragon'); + +// NEW (v2 API) +final creatures = await open5eService.getCreatures( + options: Open5eQueryOptions(page: 1, limit: 20), +); +final dragon = await open5eService.getCreatureByKey('srd-2024_ancient-red-dragon'); +``` + +## Breaking Changes from v1 + +- `monsters` → `creatures` +- `races` → `species` +- `getMonsterBySlug()` → `getCreatureByKey()` +- `documentSlug` → `documentKey` +- `slug` identifier → `key` identifier +- All endpoints now use v2 URLs +- GameSystem filtering is now automatic (defaults to 5e-2024) +- Query parameter names changed (e.g., `cr` → `challenge_rating_decimal`) diff --git a/moonforge/lib/core/services/open5e/index.dart b/moonforge/lib/core/services/open5e/index.dart new file mode 100644 index 00000000..ffe9088e --- /dev/null +++ b/moonforge/lib/core/services/open5e/index.dart @@ -0,0 +1,41 @@ +/// Open5e API v2 Integration +/// +/// A comprehensive, type-safe client for the Open5e API v2 that provides: +/// - Type-safe models for all 33 Open5e v2 resources +/// - Caching with ETag support +/// - Filtering, searching, and ordering per official API docs +/// - Pagination support +/// - GameSystem filtering (defaults to 5e-2024) +/// - Document filtering (e.g., filter by 'srd-2024', 'tob') +/// - Easy-to-use service methods +/// +/// Usage: +/// ```dart +/// final service = Open5eService(persistenceService); +/// +/// // Fetch creatures with CR 3 from 5e-2024 gamesystem +/// final creatures = await service.getCreatures( +/// options: Open5eQueryOptions( +/// filters: {'challenge_rating_decimal': '3'}, +/// ordering: 'name', +/// ), +/// ); +/// +/// // Search for fire-related spells in 5e-2014 +/// final fireSpells = await service.getSpells( +/// options: Open5eQueryOptions( +/// search: 'fire', +/// gameSystemKey: '5e-2014', +/// ), +/// ); +/// ``` + +export 'open5e_endpoints.dart'; +export 'open5e_service_v2.dart'; +export 'models/character.dart'; +export 'models/common.dart'; +export 'models/creatures.dart'; +export 'models/equipment.dart'; +export 'models/mechanics.dart'; +export 'models/rules.dart'; +export 'models/spells.dart'; diff --git a/moonforge/lib/core/services/open5e/models/character.dart b/moonforge/lib/core/services/open5e/models/character.dart new file mode 100644 index 00000000..6ffe5c14 --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/character.dart @@ -0,0 +1,237 @@ +/// Character-related models for Open5e API v2 + +import 'package:moonforge/core/services/open5e/models/common.dart'; + +/// Background from Open5e API v2 +class Background { + final String url; + final String key; + final String name; + final String desc; + final Document? document; + + Background({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.document, + }); + + factory Background.fromJson(Map json) { + return Background( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'document': document?.toJson(), + }; + } +} + +/// Feat from Open5e API v2 +class Feat { + final String url; + final String key; + final String name; + final String desc; + final String? prerequisite; + final Document? document; + + Feat({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.prerequisite, + this.document, + }); + + factory Feat.fromJson(Map json) { + return Feat( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + prerequisite: json['prerequisite'] as String?, + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'prerequisite': prerequisite, + 'document': document?.toJson(), + }; + } +} + +/// Species (formerly Race) from Open5e API v2 +class Species { + final String url; + final String key; + final String name; + final String desc; + final Document? document; + + Species({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.document, + }); + + factory Species.fromJson(Map json) { + return Species( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'document': document?.toJson(), + }; + } +} + +/// Character class from Open5e API v2 +class CharacterClass { + final String url; + final String key; + final String name; + final String desc; + final Document? document; + + CharacterClass({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.document, + }); + + factory CharacterClass.fromJson(Map json) { + return CharacterClass( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'document': document?.toJson(), + }; + } +} + +/// Ability from Open5e API v2 +class Ability { + final String url; + final String key; + final String name; + final String? fullName; + final String desc; + + Ability({ + required this.url, + required this.key, + required this.name, + this.fullName, + required this.desc, + }); + + factory Ability.fromJson(Map json) { + return Ability( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + fullName: json['full_name'] as String?, + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'full_name': fullName, + 'desc': desc, + }; + } +} + +/// Skill from Open5e API v2 +class Skill { + final String url; + final String key; + final String name; + final String desc; + final String? ability; + + Skill({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.ability, + }); + + factory Skill.fromJson(Map json) { + return Skill( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ability: json['ability'] as String?, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'ability': ability, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/models/common.dart b/moonforge/lib/core/services/open5e/models/common.dart new file mode 100644 index 00000000..775d57db --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/common.dart @@ -0,0 +1,188 @@ +/// Core data structures for Open5e API v2 responses + +/// Generic paginated response wrapper used by Open5e v2 list endpoints +class PaginatedResponse { + final int count; + final String? next; + final String? previous; + final List results; + + PaginatedResponse({ + required this.count, + this.next, + this.previous, + required this.results, + }); + + factory PaginatedResponse.fromJson( + Map json, + T Function(Map) fromJsonT, + ) { + return PaginatedResponse( + count: json['count'] as int? ?? 0, + next: json['next'] as String?, + previous: json['previous'] as String?, + results: (json['results'] as List?) + ?.map((e) => fromJsonT(e as Map)) + .toList() ?? + [], + ); + } + + Map toJson(Map Function(T) toJsonT) { + return { + 'count': count, + 'next': next, + 'previous': previous, + 'results': results.map(toJsonT).toList(), + }; + } +} + +/// GameSystem represents a D&D rule system +class GameSystem { + final String url; + final String key; + final String name; + final String desc; + final String contentPrefix; + + GameSystem({ + required this.url, + required this.key, + required this.name, + required this.desc, + required this.contentPrefix, + }); + + factory GameSystem.fromJson(Map json) { + return GameSystem( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + contentPrefix: json['content_prefix'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'content_prefix': contentPrefix, + }; + } +} + +/// Publisher represents a content publisher +class Publisher { + final String url; + final String key; + final String name; + + Publisher({ + required this.url, + required this.key, + required this.name, + }); + + factory Publisher.fromJson(Map json) { + return Publisher( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + }; + } +} + +/// Document - represents a rulebook or source with nested gamesystem and publisher +class Document { + final String name; + final String key; + final String type; + final String displayName; + final Publisher? publisher; + final GameSystem? gamesystem; + final String? permalink; + + Document({ + required this.name, + required this.key, + required this.type, + required this.displayName, + this.publisher, + this.gamesystem, + this.permalink, + }); + + factory Document.fromJson(Map json) { + return Document( + name: json['name'] as String? ?? '', + key: json['key'] as String? ?? '', + type: json['type'] as String? ?? '', + displayName: json['display_name'] as String? ?? '', + publisher: json['publisher'] != null + ? Publisher.fromJson(json['publisher'] as Map) + : null, + gamesystem: json['gamesystem'] != null + ? GameSystem.fromJson(json['gamesystem'] as Map) + : null, + permalink: json['permalink'] as String?, + ); + } + + Map toJson() { + return { + 'name': name, + 'key': key, + 'type': type, + 'display_name': displayName, + 'publisher': publisher?.toJson(), + 'gamesystem': gamesystem?.toJson(), + 'permalink': permalink, + }; + } +} + +/// License represents a content license +class License { + final String url; + final String key; + final String name; + final String? desc; + + License({ + required this.url, + required this.key, + required this.name, + this.desc, + }); + + factory License.fromJson(Map json) { + return License( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String?, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/models/creatures.dart b/moonforge/lib/core/services/open5e/models/creatures.dart new file mode 100644 index 00000000..ab9f0b01 --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/creatures.dart @@ -0,0 +1,176 @@ +/// Creature-related models for Open5e API v2 + +import 'package:moonforge/core/services/open5e/models/common.dart'; + +/// Creature from Open5e API v2 (formerly Monster in v1) +class Creature { + final String url; + final String key; + final String name; + final Document? document; + final String? desc; + final String? size; + final String? type; + final String? category; + final String? subcategory; + final int? armorClass; + final int? hitPoints; + final String? hitDice; + final int? speed; + final int? abilityScoreStrength; + final int? abilityScoreDexterity; + final int? abilityScoreConstitution; + final int? abilityScoreIntelligence; + final int? abilityScoreWisdom; + final int? abilityScoreCharisma; + final double? challengeRatingDecimal; + final String? challengeRatingText; + final int? passivePerception; + + Creature({ + required this.url, + required this.key, + required this.name, + this.document, + this.desc, + this.size, + this.type, + this.category, + this.subcategory, + this.armorClass, + this.hitPoints, + this.hitDice, + this.speed, + this.abilityScoreStrength, + this.abilityScoreDexterity, + this.abilityScoreConstitution, + this.abilityScoreIntelligence, + this.abilityScoreWisdom, + this.abilityScoreCharisma, + this.challengeRatingDecimal, + this.challengeRatingText, + this.passivePerception, + }); + + factory Creature.fromJson(Map json) { + return Creature( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + desc: json['desc'] as String?, + size: json['size'] as String?, + type: json['type'] as String?, + category: json['category'] as String?, + subcategory: json['subcategory'] as String?, + armorClass: json['armor_class'] as int?, + hitPoints: json['hit_points'] as int?, + hitDice: json['hit_dice'] as String?, + speed: json['speed'] as int?, + abilityScoreStrength: json['ability_score_strength'] as int?, + abilityScoreDexterity: json['ability_score_dexterity'] as int?, + abilityScoreConstitution: json['ability_score_constitution'] as int?, + abilityScoreIntelligence: json['ability_score_intelligence'] as int?, + abilityScoreWisdom: json['ability_score_wisdom'] as int?, + abilityScoreCharisma: json['ability_score_charisma'] as int?, + challengeRatingDecimal: (json['challenge_rating_decimal'] as num?)?.toDouble(), + challengeRatingText: json['challenge_rating_text'] as String?, + passivePerception: json['passive_perception'] as int?, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'document': document?.toJson(), + 'desc': desc, + 'size': size, + 'type': type, + 'category': category, + 'subcategory': subcategory, + 'armor_class': armorClass, + 'hit_points': hitPoints, + 'hit_dice': hitDice, + 'speed': speed, + 'ability_score_strength': abilityScoreStrength, + 'ability_score_dexterity': abilityScoreDexterity, + 'ability_score_constitution': abilityScoreConstitution, + 'ability_score_intelligence': abilityScoreIntelligence, + 'ability_score_wisdom': abilityScoreWisdom, + 'ability_score_charisma': abilityScoreCharisma, + 'challenge_rating_decimal': challengeRatingDecimal, + 'challenge_rating_text': challengeRatingText, + 'passive_perception': passivePerception, + }; + } +} + +/// Creature Type from Open5e API v2 +class CreatureType { + final String url; + final String key; + final String name; + final String desc; + + CreatureType({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory CreatureType.fromJson(Map json) { + return CreatureType( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Creature Set from Open5e API v2 +class CreatureSet { + final String url; + final String key; + final String name; + final String desc; + + CreatureSet({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory CreatureSet.fromJson(Map json) { + return CreatureSet( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/models/equipment.dart b/moonforge/lib/core/services/open5e/models/equipment.dart new file mode 100644 index 00000000..b25058a7 --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/equipment.dart @@ -0,0 +1,343 @@ +/// Equipment-related models for Open5e API v2 + +import 'package:moonforge/core/services/open5e/models/common.dart'; + +/// Generic Item from Open5e API v2 +class Item { + final String url; + final String key; + final String name; + final String desc; + final Document? document; + + Item({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.document, + }); + + factory Item.fromJson(Map json) { + return Item( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'document': document?.toJson(), + }; + } +} + +/// Magic Item from Open5e API v2 +class MagicItem { + final String url; + final String key; + final String name; + final String desc; + final String? type; + final String? rarity; + final bool? requiresAttunement; + final Document? document; + + MagicItem({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.type, + this.rarity, + this.requiresAttunement, + this.document, + }); + + factory MagicItem.fromJson(Map json) { + return MagicItem( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + type: json['type'] as String?, + rarity: json['rarity'] as String?, + requiresAttunement: json['requires_attunement'] as bool?, + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'type': type, + 'rarity': rarity, + 'requires_attunement': requiresAttunement, + 'document': document?.toJson(), + }; + } +} + +/// Weapon from Open5e API v2 +class Weapon { + final String url; + final String key; + final String name; + final String desc; + final String? category; + final String? damage; + final String? damageType; + final String? weight; + final String? properties; + final Document? document; + + Weapon({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.category, + this.damage, + this.damageType, + this.weight, + this.properties, + this.document, + }); + + factory Weapon.fromJson(Map json) { + return Weapon( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + category: json['category'] as String?, + damage: json['damage'] as String?, + damageType: json['damage_type'] as String?, + weight: json['weight'] as String?, + properties: json['properties'] as String?, + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'category': category, + 'damage': damage, + 'damage_type': damageType, + 'weight': weight, + 'properties': properties, + 'document': document?.toJson(), + }; + } +} + +/// Armor from Open5e API v2 +class Armor { + final String url; + final String key; + final String name; + final String desc; + final String? category; + final String? armorClass; + final String? strength; + final bool? stealthDisadvantage; + final String? weight; + final Document? document; + + Armor({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.category, + this.armorClass, + this.strength, + this.stealthDisadvantage, + this.weight, + this.document, + }); + + factory Armor.fromJson(Map json) { + return Armor( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + category: json['category'] as String?, + armorClass: json['armor_class'] as String?, + strength: json['strength'] as String?, + stealthDisadvantage: json['stealth_disadvantage'] as bool?, + weight: json['weight'] as String?, + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'category': category, + 'armor_class': armorClass, + 'strength': strength, + 'stealth_disadvantage': stealthDisadvantage, + 'weight': weight, + 'document': document?.toJson(), + }; + } +} + +/// Item Set from Open5e API v2 +class ItemSet { + final String url; + final String key; + final String name; + final String desc; + + ItemSet({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory ItemSet.fromJson(Map json) { + return ItemSet( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Item Category from Open5e API v2 +class ItemCategory { + final String url; + final String key; + final String name; + final String desc; + + ItemCategory({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory ItemCategory.fromJson(Map json) { + return ItemCategory( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Item Rarity from Open5e API v2 +class ItemRarity { + final String url; + final String key; + final String name; + final String desc; + + ItemRarity({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory ItemRarity.fromJson(Map json) { + return ItemRarity( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Weapon Property from Open5e API v2 +class WeaponProperty { + final String url; + final String key; + final String name; + final String desc; + + WeaponProperty({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory WeaponProperty.fromJson(Map json) { + return WeaponProperty( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/models/mechanics.dart b/moonforge/lib/core/services/open5e/models/mechanics.dart new file mode 100644 index 00000000..fdad812b --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/mechanics.dart @@ -0,0 +1,207 @@ +/// Game mechanics models for Open5e API v2 + +import 'package:moonforge/core/services/open5e/models/common.dart'; + +/// Condition from Open5e API v2 +class Condition { + final String url; + final String key; + final String name; + final String desc; + final Document? document; + + Condition({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.document, + }); + + factory Condition.fromJson(Map json) { + return Condition( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'document': document?.toJson(), + }; + } +} + +/// Damage Type from Open5e API v2 +class DamageType { + final String url; + final String key; + final String name; + final String desc; + + DamageType({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory DamageType.fromJson(Map json) { + return DamageType( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Language from Open5e API v2 +class Language { + final String url; + final String key; + final String name; + final String desc; + + Language({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory Language.fromJson(Map json) { + return Language( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Alignment from Open5e API v2 +class Alignment { + final String url; + final String key; + final String name; + final String desc; + + Alignment({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory Alignment.fromJson(Map json) { + return Alignment( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Size from Open5e API v2 +class Size { + final String url; + final String key; + final String name; + final String desc; + + Size({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory Size.fromJson(Map json) { + return Size( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Environment from Open5e API v2 +class Environment { + final String url; + final String key; + final String name; + final String desc; + + Environment({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory Environment.fromJson(Map json) { + return Environment( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/models/rules.dart b/moonforge/lib/core/services/open5e/models/rules.dart new file mode 100644 index 00000000..e429ea43 --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/rules.dart @@ -0,0 +1,154 @@ +/// Rules and miscellaneous models for Open5e API v2 + +import 'package:moonforge/core/services/open5e/models/common.dart'; + +/// Rule from Open5e API v2 +class Rule { + final String url; + final String key; + final String name; + final String desc; + final Document? document; + + Rule({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.document, + }); + + factory Rule.fromJson(Map json) { + return Rule( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'document': document?.toJson(), + }; + } +} + +/// Rule Set from Open5e API v2 +class RuleSet { + final String url; + final String key; + final String name; + final String desc; + + RuleSet({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory RuleSet.fromJson(Map json) { + return RuleSet( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} + +/// Image from Open5e API v2 +class Open5eImage { + final String url; + final String key; + final String name; + final String? desc; + final String? imageUrl; + final Document? document; + + Open5eImage({ + required this.url, + required this.key, + required this.name, + this.desc, + this.imageUrl, + this.document, + }); + + factory Open5eImage.fromJson(Map json) { + return Open5eImage( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String?, + imageUrl: json['image_url'] as String?, + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'image_url': imageUrl, + 'document': document?.toJson(), + }; + } +} + +/// Service resource from Open5e API v2 +/// +/// Renamed from Open5eService to Open5eServiceResource to avoid +/// conflict with the main Open5eService class +class Open5eServiceResource { + final String url; + final String key; + final String name; + final String desc; + + Open5eServiceResource({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory Open5eServiceResource.fromJson(Map json) { + return Open5eServiceResource( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/models/spells.dart b/moonforge/lib/core/services/open5e/models/spells.dart new file mode 100644 index 00000000..027d78cf --- /dev/null +++ b/moonforge/lib/core/services/open5e/models/spells.dart @@ -0,0 +1,115 @@ +/// Spell-related models for Open5e API v2 + +import 'package:moonforge/core/services/open5e/models/common.dart'; + +/// Spell from Open5e API v2 +class Open5eSpell { + final String url; + final String key; + final String name; + final String desc; + final String? higherLevel; + final String? range; + final String? components; + final String? material; + final bool? ritual; + final String? duration; + final bool? concentration; + final String? castingTime; + final int? level; + final String? school; + final Document? document; + + Open5eSpell({ + required this.url, + required this.key, + required this.name, + required this.desc, + this.higherLevel, + this.range, + this.components, + this.material, + this.ritual, + this.duration, + this.concentration, + this.castingTime, + this.level, + this.school, + this.document, + }); + + factory Open5eSpell.fromJson(Map json) { + return Open5eSpell( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + higherLevel: json['higher_level'] as String?, + range: json['range'] as String?, + components: json['components'] as String?, + material: json['material'] as String?, + ritual: json['ritual'] as bool?, + duration: json['duration'] as String?, + concentration: json['concentration'] as bool?, + castingTime: json['casting_time'] as String?, + level: json['level'] as int?, + school: json['school'] as String?, + document: json['document'] != null + ? Document.fromJson(json['document'] as Map) + : null, + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + 'higher_level': higherLevel, + 'range': range, + 'components': components, + 'material': material, + 'ritual': ritual, + 'duration': duration, + 'concentration': concentration, + 'casting_time': castingTime, + 'level': level, + 'school': school, + 'document': document?.toJson(), + }; + } +} + +/// Spell School from Open5e API v2 +class SpellSchool { + final String url; + final String key; + final String name; + final String desc; + + SpellSchool({ + required this.url, + required this.key, + required this.name, + required this.desc, + }); + + factory SpellSchool.fromJson(Map json) { + return SpellSchool( + url: json['url'] as String? ?? '', + key: json['key'] as String? ?? '', + name: json['name'] as String? ?? '', + desc: json['desc'] as String? ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'key': key, + 'name': name, + 'desc': desc, + }; + } +} diff --git a/moonforge/lib/core/services/open5e/open5e_endpoints.dart b/moonforge/lib/core/services/open5e/open5e_endpoints.dart new file mode 100644 index 00000000..7a0935c6 --- /dev/null +++ b/moonforge/lib/core/services/open5e/open5e_endpoints.dart @@ -0,0 +1,131 @@ +/// Open5e API v2 endpoint configuration +/// +/// Defines all available Open5e API v2 endpoints with their base URLs. +/// All endpoints use the v2 API with gamesystem filtering support. +class Open5eEndpoints { + static const String baseUrl = 'https://api.open5e.com/v2'; + + /// Default gamesystem to use for filtering + static const String defaultGameSystem = '5e-2024'; + + // Core content endpoints + static const String items = '$baseUrl/items/?format=api'; + static const String magicItems = '$baseUrl/magicitems/?format=api'; + static const String itemSets = '$baseUrl/itemsets/?format=api'; + static const String itemCategories = '$baseUrl/itemcategories/?format=api'; + static const String itemRarities = '$baseUrl/itemrarities/?format=api'; + static const String weapons = '$baseUrl/weapons/?format=api'; + static const String weaponProperties = '$baseUrl/weaponproperties/?format=api'; + static const String armor = '$baseUrl/armor/?format=api'; + + // Character options + static const String backgrounds = '$baseUrl/backgrounds/?format=api'; + static const String feats = '$baseUrl/feats/?format=api'; + static const String species = '$baseUrl/species/?format=api'; + static const String classes = '$baseUrl/classes/?format=api'; + static const String abilities = '$baseUrl/abilities/?format=api'; + static const String skills = '$baseUrl/skills/?format=api'; + + // Creatures + static const String creatures = '$baseUrl/creatures/?format=api'; + static const String creatureTypes = '$baseUrl/creaturetypes/?format=api'; + static const String creatureSets = '$baseUrl/creaturesets/?format=api'; + + // Spells + static const String spells = '$baseUrl/spells/?format=api'; + static const String spellSchools = '$baseUrl/spellschools/?format=api'; + + // Game mechanics + static const String conditions = '$baseUrl/conditions/?format=api'; + static const String damageTypes = '$baseUrl/damagetypes/?format=api'; + static const String languages = '$baseUrl/languages/?format=api'; + static const String alignments = '$baseUrl/alignments/?format=api'; + static const String sizes = '$baseUrl/sizes/?format=api'; + static const String environments = '$baseUrl/environments/?format=api'; + + // Rules and documentation + static const String documents = '$baseUrl/documents/?format=api'; + static const String licenses = '$baseUrl/licenses/?format=api'; + static const String publishers = '$baseUrl/publishers/?format=api'; + static const String gameSystems = '$baseUrl/gamesystems/?format=api'; + static const String rules = '$baseUrl/rules/?format=api'; + static const String ruleSets = '$baseUrl/rulesets/?format=api'; + + // Media + static const String images = '$baseUrl/images/?format=api'; + static const String services = '$baseUrl/services/?format=api'; + + /// Get endpoint URL by resource name + static String? getEndpoint(String resourceName) { + switch (resourceName) { + case 'items': + return items; + case 'magicitems': + return magicItems; + case 'itemsets': + return itemSets; + case 'itemcategories': + return itemCategories; + case 'itemrarities': + return itemRarities; + case 'weapons': + return weapons; + case 'weaponproperties': + return weaponProperties; + case 'armor': + return armor; + case 'backgrounds': + return backgrounds; + case 'feats': + return feats; + case 'species': + return species; + case 'classes': + return classes; + case 'abilities': + return abilities; + case 'skills': + return skills; + case 'creatures': + return creatures; + case 'creaturetypes': + return creatureTypes; + case 'creaturesets': + return creatureSets; + case 'spells': + return spells; + case 'spellschools': + return spellSchools; + case 'conditions': + return conditions; + case 'damagetypes': + return damageTypes; + case 'languages': + return languages; + case 'alignments': + return alignments; + case 'sizes': + return sizes; + case 'environments': + return environments; + case 'documents': + return documents; + case 'licenses': + return licenses; + case 'publishers': + return publishers; + case 'gamesystems': + return gameSystems; + case 'rules': + return rules; + case 'rulesets': + return ruleSets; + case 'images': + return images; + case 'services': + return services; + default: + return null; + } + } +} diff --git a/moonforge/lib/core/services/open5e/open5e_service_v2.dart b/moonforge/lib/core/services/open5e/open5e_service_v2.dart new file mode 100644 index 00000000..20b4b2d2 --- /dev/null +++ b/moonforge/lib/core/services/open5e/open5e_service_v2.dart @@ -0,0 +1,842 @@ +import 'dart:convert'; + +import 'package:http/http.dart' show Client, Response; +import 'package:moonforge/core/services/open5e/open5e_endpoints.dart'; +import 'package:moonforge/core/services/open5e/models/character.dart'; +import 'package:moonforge/core/services/open5e/models/common.dart'; +import 'package:moonforge/core/services/open5e/models/creatures.dart'; +import 'package:moonforge/core/services/open5e/models/equipment.dart'; +import 'package:moonforge/core/services/open5e/models/mechanics.dart'; +import 'package:moonforge/core/services/open5e/models/rules.dart'; +import 'package:moonforge/core/services/open5e/models/spells.dart'; +import 'package:moonforge/core/services/persistence_service.dart'; +import 'package:moonforge/core/utils/logger.dart'; + +/// Type-safe game system keys for Open5e API v2 +/// +/// These values are used for filtering content by game system. +/// Can be fetched dynamically from /v2/gamesystems/ endpoint. +class GameSystemKey { + static const String edition2024 = '5e-2024'; + static const String edition2014 = '5e-2014'; + static const String advancedEdition = 'a5e'; + + /// All available game system keys + static const List all = [edition2024, edition2014, advancedEdition]; +} + +/// Type-safe document keys for Open5e API v2 +/// +/// These represent source documents/books. The full list can be fetched +/// dynamically from /v2/documents/ endpoint for the most up-to-date values. +class DocumentKey { + // 5e 2024 documents + static const String srd2024 = 'srd-2024'; + + // 5e 2014 documents + static const String srd2014 = 'srd'; + static const String wotcSrd = 'wotc-srd'; + + // Third-party documents + static const String tomeOfBeasts = 'tob'; + static const String tomeOfBeasts2 = 'tob2'; + static const String tomeOfBeasts3 = 'tob3'; + static const String creaturesCodex = 'cc'; + static const String creatureCodex = 'cc'; // Alias for creaturesCodex + static const String menagerie = 'menagerie'; + static const String midgardHeroes = 'dmag'; + + /// Common document keys + static const List common = [srd2024, srd2014, tomeOfBeasts]; +} + +/// Query options for Open5e API v2 requests +/// +/// Supports filtering, searching, ordering, and pagination according to +/// the official Open5e API v2 documentation +class Open5eQueryOptions { + /// Case-insensitive name search (name__icontains parameter) + final String? search; + + /// Filter by gamesystem key (use GameSystemKey constants) + /// Defaults to '5e-2024' if not specified + final String? gameSystemKey; + + /// Filter by source document key (use DocumentKey constants) + final String? documentKey; + + /// Filter by creature type (e.g., 'dragon', 'undead', 'humanoid') + /// Only applicable for creatures endpoint. Get values from /v2/creaturetypes/ + final String? creatureType; + + /// Ordering field (e.g., 'name', 'challenge_rating_decimal', '-name' for descending) + final String? ordering; + + /// Page number (1-based) + final int page; + + /// Results per page (limit parameter) + final int? limit; + + /// Additional filter parameters (e.g., {'challenge_rating_decimal': '3'} for creatures) + final Map? filters; + + Open5eQueryOptions({ + this.search, + this.gameSystemKey, + this.documentKey, + this.creatureType, + this.ordering, + this.page = 1, + this.limit, + this.filters, + }); + + /// Convert to query parameters with default gamesystem + Map toQueryParams() { + final params = { + 'format': 'api', + 'page': page.toString(), + // Default to 5e-2024 gamesystem if not specified + 'document__gamesystem__key__iexact': + gameSystemKey ?? Open5eEndpoints.defaultGameSystem, + }; + + if (search != null) params['name__icontains'] = search!; + if (documentKey != null) params['document__key__iexact'] = documentKey!; + if (creatureType != null) params['type'] = creatureType!; + if (ordering != null) params['ordering'] = ordering!; + if (limit != null) params['limit'] = limit.toString(); + if (filters != null) params.addAll(filters!); + + return params; + } +} + +/// Base client for Open5e API interactions +/// +/// Provides generic methods for fetching data from Open5e API endpoints with +/// caching, ETags support, filtering, searching, and ordering. +class Open5eClient { + static const String _boxName = 'open5e_cache'; + static const Duration _defaultStaleThreshold = Duration(hours: 24); + + final PersistenceService _persistence; + final Client _httpClient; + final Duration staleThreshold; + + Open5eClient( + this._persistence, { + Client? httpClient, + this.staleThreshold = _defaultStaleThreshold, + }) : _httpClient = httpClient ?? Client(); + + /// Generic method to fetch a paginated list from an endpoint + Future?> fetchList({ + required String endpoint, + required T Function(Map) fromJson, + Open5eQueryOptions? options, + bool useCache = true, + bool force = false, + }) async { + final queryOptions = options ?? Open5eQueryOptions(); + final cacheKey = _buildCacheKey(endpoint, queryOptions); + final etagKey = '${cacheKey}_etag'; + + // Try cache first + if (useCache && !force) { + final cached = _persistence.read(cacheKey, boxName: _boxName); + if (cached != null) { + try { + final decoded = jsonDecode(cached) as Map; + return PaginatedResponse.fromJson(decoded, fromJson); + } catch (e) { + logger.w('Failed to parse cached data for $endpoint: $e', + context: LogContext.network); + // Clear corrupted cache + _persistence.delete(cacheKey, boxName: _boxName); + _persistence.delete(etagKey, boxName: _boxName); + logger.d('Cleared corrupted cache for $endpoint', + context: LogContext.network); + } + } + } + + // Build URL with query parameters + // Parse the endpoint URL and merge existing query params with new ones + final baseUri = Uri.parse(endpoint); + final mergedParams = { + ...baseUri.queryParameters, // Keep existing params like format=api + ...queryOptions.toQueryParams(), // Add new params + }; + final uri = baseUri.replace(queryParameters: mergedParams); + + // Add ETag if available + final headers = {}; + if (useCache && !force) { + final etag = _persistence.read(etagKey, boxName: _boxName); + if (etag != null) headers['If-None-Match'] = etag; + } + + try { + logger.d('Fetching from Open5e: $uri', context: LogContext.network); + final response = await _httpClient.get(uri, headers: headers); + + if (response.statusCode == 200) { + // Store in cache + await _persistence.write(cacheKey, response.body, boxName: _boxName); + + // Store ETag + final newEtag = response.headers['etag']; + if (newEtag != null) { + await _persistence.write(etagKey, newEtag, boxName: _boxName); + } + + final decoded = jsonDecode(response.body) as Map; + return PaginatedResponse.fromJson(decoded, fromJson); + } else if (response.statusCode == 304) { + // Not modified, return cached + final cached = _persistence.read(cacheKey, boxName: _boxName); + if (cached != null) { + final decoded = jsonDecode(cached) as Map; + return PaginatedResponse.fromJson(decoded, fromJson); + } + } else { + logger.e('Open5e API error: ${response.statusCode} - ${response.body}', + context: LogContext.network); + } + } catch (e) { + logger.e('Failed to fetch from Open5e: $e', context: LogContext.network); + } + + return null; + } + + /// Generic method to fetch a single resource by slug + Future fetchBySlug({ + required String endpoint, + required String slug, + required T Function(Map) fromJson, + bool useCache = true, + bool force = false, + }) async { + final cacheKey = '${endpoint}_slug_$slug'; + final etagKey = '${cacheKey}_etag'; + + // Try cache first + if (useCache && !force) { + final cached = _persistence.read(cacheKey, boxName: _boxName); + if (cached != null) { + try { + final decoded = jsonDecode(cached) as Map; + return fromJson(decoded); + } catch (e) { + logger.w('Failed to parse cached resource $slug: $e', + context: LogContext.network); + } + } + } + + // Build URL + final url = endpoint.endsWith('/') ? '$endpoint$slug/' : '$endpoint/$slug/'; + final uri = Uri.parse('$url?format=json'); + + // Add ETag if available + final headers = {}; + if (useCache && !force) { + final etag = _persistence.read(etagKey, boxName: _boxName); + if (etag != null) headers['If-None-Match'] = etag; + } + + try { + logger.d('Fetching from Open5e: $uri', context: LogContext.network); + final response = await _httpClient.get(uri, headers: headers); + + if (response.statusCode == 200) { + // Store in cache + await _persistence.write(cacheKey, response.body, boxName: _boxName); + + // Store ETag + final newEtag = response.headers['etag']; + if (newEtag != null) { + await _persistence.write(etagKey, newEtag, boxName: _boxName); + } + + final decoded = jsonDecode(response.body) as Map; + return fromJson(decoded); + } else if (response.statusCode == 304) { + // Not modified, return cached + final cached = _persistence.read(cacheKey, boxName: _boxName); + if (cached != null) { + final decoded = jsonDecode(cached) as Map; + return fromJson(decoded); + } + } else { + logger.e('Open5e API error: ${response.statusCode} - ${response.body}', + context: LogContext.network); + } + } catch (e) { + logger.e('Failed to fetch from Open5e: $e', context: LogContext.network); + } + + return null; + } + + /// Clear all cached data + /// + /// Note: Due to PersistenceService limitations, this marks the cache + /// for clearing. Individual cache entries will be cleared when accessed + /// with force=true or on next request. + Future clearCache() async { + logger.i('Open5e cache clear requested - cache will be refreshed on next access', + context: LogContext.network); + // Note: PersistenceService doesn't provide a way to enumerate and clear + // all keys in a box. Cache entries will be invalidated on next access. + } + + /// Build cache key for list requests + String _buildCacheKey(String endpoint, Open5eQueryOptions options) { + final buffer = StringBuffer('${endpoint}_page_${options.page}'); + if (options.limit != null) buffer.write('_limit_${options.limit}'); + if (options.search != null) buffer.write('_search_${options.search}'); + if (options.gameSystemKey != null) { + buffer.write('_gs_${options.gameSystemKey}'); + } + if (options.documentKey != null) { + buffer.write('_doc_${options.documentKey}'); + } + if (options.ordering != null) buffer.write('_order_${options.ordering}'); + if (options.filters != null && options.filters!.isNotEmpty) { + final sortedKeys = options.filters!.keys.toList()..sort(); + for (final key in sortedKeys) { + buffer.write('_${key}_${options.filters![key]}'); + } + } + return buffer.toString(); + } +} + +/// High-level service for accessing Open5e v2 data +/// +/// Provides type-safe methods for all Open5e v2 endpoints with caching, +/// filtering, searching, and ordering support. All requests default to +/// 5e-2024 gamesystem unless specified otherwise. +class Open5eService { + final Open5eClient _client; + + Open5eService(PersistenceService persistence, {Client? httpClient}) + : _client = Open5eClient(persistence, httpClient: httpClient); + + // Creatures (formerly Monsters in v1) + Future?> getCreatures({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.creatures, + fromJson: Creature.fromJson, + options: options, + useCache: useCache, + ); + + Future getCreatureByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.creatures, + slug: key, + fromJson: Creature.fromJson, + useCache: useCache, + ); + + // Creature Types + Future?> getCreatureTypes({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.creatureTypes, + fromJson: CreatureType.fromJson, + options: options, + useCache: useCache, + ); + + // Creature Sets + Future?> getCreatureSets({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.creatureSets, + fromJson: CreatureSet.fromJson, + options: options, + useCache: useCache, + ); + + // Spells + Future?> getSpells({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.spells, + fromJson: Open5eSpell.fromJson, + options: options, + useCache: useCache, + ); + + Future getSpellByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.spells, + slug: key, + fromJson: Open5eSpell.fromJson, + useCache: useCache, + ); + + // Spell Schools + Future?> getSpellSchools({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.spellSchools, + fromJson: SpellSchool.fromJson, + options: options, + useCache: useCache, + ); + + // Backgrounds + Future?> getBackgrounds({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.backgrounds, + fromJson: Background.fromJson, + options: options, + useCache: useCache, + ); + + Future getBackgroundByKey(String key, + {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.backgrounds, + slug: key, + fromJson: Background.fromJson, + useCache: useCache, + ); + + // Feats + Future?> getFeats({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.feats, + fromJson: Feat.fromJson, + options: options, + useCache: useCache, + ); + + Future getFeatByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.feats, + slug: key, + fromJson: Feat.fromJson, + useCache: useCache, + ); + + // Species (formerly Races in v1) + Future?> getSpecies({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.species, + fromJson: Species.fromJson, + options: options, + useCache: useCache, + ); + + Future getSpeciesByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.species, + slug: key, + fromJson: Species.fromJson, + useCache: useCache, + ); + + // Classes + Future?> getClasses({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.classes, + fromJson: CharacterClass.fromJson, + options: options, + useCache: useCache, + ); + + Future getClassByKey(String key, + {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.classes, + slug: key, + fromJson: CharacterClass.fromJson, + useCache: useCache, + ); + + // Abilities + Future?> getAbilities({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.abilities, + fromJson: Ability.fromJson, + options: options, + useCache: useCache, + ); + + // Skills + Future?> getSkills({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.skills, + fromJson: Skill.fromJson, + options: options, + useCache: useCache, + ); + + // Items + Future?> getItems({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.items, + fromJson: Item.fromJson, + options: options, + useCache: useCache, + ); + + Future getItemByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.items, + slug: key, + fromJson: Item.fromJson, + useCache: useCache, + ); + + // Magic Items + Future?> getMagicItems({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.magicItems, + fromJson: MagicItem.fromJson, + options: options, + useCache: useCache, + ); + + Future getMagicItemByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.magicItems, + slug: key, + fromJson: MagicItem.fromJson, + useCache: useCache, + ); + + // Item Sets + Future?> getItemSets({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.itemSets, + fromJson: ItemSet.fromJson, + options: options, + useCache: useCache, + ); + + // Item Categories + Future?> getItemCategories({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.itemCategories, + fromJson: ItemCategory.fromJson, + options: options, + useCache: useCache, + ); + + // Item Rarities + Future?> getItemRarities({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.itemRarities, + fromJson: ItemRarity.fromJson, + options: options, + useCache: useCache, + ); + + // Weapons + Future?> getWeapons({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.weapons, + fromJson: Weapon.fromJson, + options: options, + useCache: useCache, + ); + + Future getWeaponByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.weapons, + slug: key, + fromJson: Weapon.fromJson, + useCache: useCache, + ); + + // Weapon Properties + Future?> getWeaponProperties({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.weaponProperties, + fromJson: WeaponProperty.fromJson, + options: options, + useCache: useCache, + ); + + // Armor + Future?> getArmor({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.armor, + fromJson: Armor.fromJson, + options: options, + useCache: useCache, + ); + + Future getArmorByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.armor, + slug: key, + fromJson: Armor.fromJson, + useCache: useCache, + ); + + // Conditions + Future?> getConditions({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.conditions, + fromJson: Condition.fromJson, + options: options, + useCache: useCache, + ); + + Future getConditionByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.conditions, + slug: key, + fromJson: Condition.fromJson, + useCache: useCache, + ); + + // Damage Types + Future?> getDamageTypes({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.damageTypes, + fromJson: DamageType.fromJson, + options: options, + useCache: useCache, + ); + + // Languages + Future?> getLanguages({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.languages, + fromJson: Language.fromJson, + options: options, + useCache: useCache, + ); + + // Alignments + Future?> getAlignments({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.alignments, + fromJson: Alignment.fromJson, + options: options, + useCache: useCache, + ); + + // Sizes + Future?> getSizes({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.sizes, + fromJson: Size.fromJson, + options: options, + useCache: useCache, + ); + + // Environments + Future?> getEnvironments({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.environments, + fromJson: Environment.fromJson, + options: options, + useCache: useCache, + ); + + // Documents + Future?> getDocuments({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.documents, + fromJson: Document.fromJson, + options: options, + useCache: useCache, + ); + + Future getDocumentByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.documents, + slug: key, + fromJson: Document.fromJson, + useCache: useCache, + ); + + // Licenses + Future?> getLicenses({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.licenses, + fromJson: License.fromJson, + options: options, + useCache: useCache, + ); + + // Publishers + Future?> getPublishers({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.publishers, + fromJson: Publisher.fromJson, + options: options, + useCache: useCache, + ); + + // Game Systems + Future?> getGameSystems({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.gameSystems, + fromJson: GameSystem.fromJson, + options: options, + useCache: useCache, + ); + + // Rules + Future?> getRules({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.rules, + fromJson: Rule.fromJson, + options: options, + useCache: useCache, + ); + + Future getRuleByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.rules, + slug: key, + fromJson: Rule.fromJson, + useCache: useCache, + ); + + // Rule Sets + Future?> getRuleSets({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.ruleSets, + fromJson: RuleSet.fromJson, + options: options, + useCache: useCache, + ); + + // Images + Future?> getImages({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.images, + fromJson: Open5eImage.fromJson, + options: options, + useCache: useCache, + ); + + Future getImageByKey(String key, {bool useCache = true}) => + _client.fetchBySlug( + endpoint: Open5eEndpoints.images, + slug: key, + fromJson: Open5eImage.fromJson, + useCache: useCache, + ); + + // Services + Future?> getServices({ + Open5eQueryOptions? options, + bool useCache = true, + }) => + _client.fetchList( + endpoint: Open5eEndpoints.services, + fromJson: Open5eServiceResource.fromJson, + options: options, + useCache: useCache, + ); + + /// Clear all cached Open5e data + Future clearCache() => _client.clearCache(); +} diff --git a/moonforge/lib/core/services/router_config.dart b/moonforge/lib/core/services/router_config.dart index 85fb7085..7eddfe9c 100644 --- a/moonforge/lib/core/services/router_config.dart +++ b/moonforge/lib/core/services/router_config.dart @@ -24,6 +24,7 @@ import 'package:moonforge/features/entities/views/entity_edit_view.dart'; import 'package:moonforge/features/entities/views/entity_list_view.dart'; import 'package:moonforge/features/entities/views/entity_view.dart'; import 'package:moonforge/features/home/views/home_view.dart'; +import 'package:moonforge/features/open5e_browser/views/open5e_browser_view.dart'; import 'package:moonforge/features/parties/views/member_edit_view.dart'; import 'package:moonforge/features/parties/views/member_view.dart'; import 'package:moonforge/features/parties/views/party_edit_view.dart'; @@ -42,7 +43,7 @@ import 'package:moonforge/layout/layout_shell.dart'; part 'router_config.g.dart'; -/// Main shell route with 4 branches: Home, Campaign, Party, Settings +/// Main shell route with 5 branches: Home, Campaign, Party, Open5e, Settings @TypedStatefulShellRoute( branches: >[ // Branch 0: Home/Auth @@ -143,7 +144,13 @@ part 'router_config.g.dart'; ), ], ), - // Branch 3: Settings / Profile + // Branch 3: Open5e Browser + TypedStatefulShellBranch( + routes: >[ + TypedGoRoute(path: '/open5e-browser'), + ], + ), + // Branch 4: Settings / Profile TypedStatefulShellBranch( routes: >[ TypedGoRoute(path: '/settings'), @@ -182,6 +189,11 @@ class PartyBranchData extends StatefulShellBranchData { const PartyBranchData(); } +@immutable +class Open5eBranchData extends StatefulShellBranchData { + const Open5eBranchData(); +} + @immutable class SettingsBranchData extends StatefulShellBranchData { const SettingsBranchData(); @@ -599,6 +611,16 @@ class ProfileRouteData extends GoRouteData with $ProfileRouteData { const ProfileView(); } +@immutable +class Open5eBrowserRouteData extends GoRouteData + with $Open5eBrowserRouteData { + const Open5eBrowserRouteData(); + + @override + Widget build(BuildContext context, GoRouterState state) => + const Open5eBrowserView(); +} + // Public routes (outside shell) @TypedGoRoute(path: '/share/session/:token') @immutable diff --git a/moonforge/lib/core/services/router_config.g.dart b/moonforge/lib/core/services/router_config.g.dart index ada25476..96dce490 100644 --- a/moonforge/lib/core/services/router_config.g.dart +++ b/moonforge/lib/core/services/router_config.g.dart @@ -190,6 +190,14 @@ RouteBase get $appShellRouteData => StatefulShellRouteData.$route( ), ], ), + StatefulShellBranchData.$branch( + routes: [ + GoRouteData.$route( + path: '/open5e-browser', + factory: $Open5eBrowserRouteData._fromState, + ), + ], + ), StatefulShellBranchData.$branch( routes: [ GoRouteData.$route( @@ -1040,6 +1048,27 @@ mixin $SessionEditRouteData on GoRouteData { void replace(BuildContext context) => context.replace(location); } +mixin $Open5eBrowserRouteData on GoRouteData { + static Open5eBrowserRouteData _fromState(GoRouterState state) => + const Open5eBrowserRouteData(); + + @override + String get location => GoRouteData.$location('/open5e-browser'); + + @override + void go(BuildContext context) => context.go(location); + + @override + Future push(BuildContext context) => context.push(location); + + @override + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + @override + void replace(BuildContext context) => context.replace(location); +} + mixin $SettingsRouteData on GoRouteData { static SettingsRouteData _fromState(GoRouterState state) => const SettingsRouteData(); diff --git a/moonforge/lib/core/widgets/open5e/character_widgets.dart b/moonforge/lib/core/widgets/open5e/character_widgets.dart new file mode 100644 index 00000000..77b9a3a7 --- /dev/null +++ b/moonforge/lib/core/widgets/open5e/character_widgets.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import 'package:moonforge/core/services/open5e/models/character.dart'; +import 'package:moonforge/core/widgets/surface_container.dart'; + +/// Widget to display a Background from Open5e v2 +class BackgroundWidget extends StatelessWidget { + final Background background; + + const BackgroundWidget({super.key, required this.background}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + background.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 8), + Text( + background.desc, + style: theme.textTheme.bodyMedium, + ), + if (background.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${background.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (background.document!.gamesystem != null) + Text( + 'System: ${background.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} + +/// Widget to display a Feat from Open5e v2 +class FeatWidget extends StatelessWidget { + final Feat feat; + + const FeatWidget({super.key, required this.feat}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + feat.name, + style: theme.textTheme.headlineMedium, + ), + if (feat.prerequisite != null) ...[ + const SizedBox(height: 4), + Text( + 'Prerequisite: ${feat.prerequisite}', + style: theme.textTheme.labelMedium, + ), + ], + const SizedBox(height: 8), + Text( + feat.desc, + style: theme.textTheme.bodyMedium, + ), + if (feat.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${feat.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (feat.document!.gamesystem != null) + Text( + 'System: ${feat.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} + +/// Widget to display a Species (formerly Race) from Open5e v2 +class SpeciesWidget extends StatelessWidget { + final Species species; + + const SpeciesWidget({super.key, required this.species}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + species.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 8), + Text( + species.desc, + style: theme.textTheme.bodyMedium, + ), + if (species.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${species.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (species.document!.gamesystem != null) + Text( + 'System: ${species.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} + +/// Widget to display a CharacterClass from Open5e v2 +class CharacterClassWidget extends StatelessWidget { + final CharacterClass characterClass; + + const CharacterClassWidget({super.key, required this.characterClass}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + characterClass.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 8), + Text( + characterClass.desc, + style: theme.textTheme.bodyMedium, + ), + if (characterClass.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${characterClass.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (characterClass.document!.gamesystem != null) + Text( + 'System: ${characterClass.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} + +/// Widget to display an Ability from Open5e v2 +class AbilityWidget extends StatelessWidget { + final Ability ability; + + const AbilityWidget({super.key, required this.ability}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + ability.name, + style: theme.textTheme.headlineMedium, + ), + if (ability.fullName != null) ...[ + const SizedBox(height: 4), + Text( + ability.fullName!, + style: theme.textTheme.titleMedium, + ), + ], + const SizedBox(height: 8), + Text( + ability.desc, + style: theme.textTheme.bodyMedium, + ), + ], + ), + ); + } +} + +/// Widget to display a Skill from Open5e v2 +class SkillWidget extends StatelessWidget { + final Skill skill; + + const SkillWidget({super.key, required this.skill}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + skill.name, + style: theme.textTheme.headlineMedium, + ), + if (skill.ability != null) ...[ + const SizedBox(height: 4), + Text( + 'Ability: ${skill.ability}', + style: theme.textTheme.labelMedium, + ), + ], + const SizedBox(height: 8), + Text( + skill.desc, + style: theme.textTheme.bodyMedium, + ), + ], + ), + ); + } +} diff --git a/moonforge/lib/core/widgets/open5e/creature_widgets.dart b/moonforge/lib/core/widgets/open5e/creature_widgets.dart new file mode 100644 index 00000000..e8a2047f --- /dev/null +++ b/moonforge/lib/core/widgets/open5e/creature_widgets.dart @@ -0,0 +1,185 @@ +import 'package:flutter/material.dart'; +import 'package:moonforge/core/services/open5e/models/creatures.dart'; +import 'package:moonforge/core/services/open5e/models/mechanics.dart'; +import 'package:moonforge/core/widgets/surface_container.dart'; + +/// Widget to display a Creature from Open5e v2 (formerly Monster) +class CreatureWidget extends StatelessWidget { + final Creature creature; + + const CreatureWidget({super.key, required this.creature}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + creature.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 4), + Row( + children: [ + if (creature.size != null) Text(creature.size!), + if (creature.type != null) ...[ + if (creature.size != null) const Text(' '), + Text(creature.type!), + ], + if (creature.challengeRatingText != null) ...[ + const Text(' • CR '), + Text( + creature.challengeRatingText!, + style: theme.textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ], + ], + ), + const SizedBox(height: 16), + if (creature.armorClass != null) + _buildCreatureStat('AC', '${creature.armorClass}', theme), + if (creature.hitPoints != null) + _buildCreatureStat('HP', '${creature.hitPoints}', theme), + if (creature.hitDice != null) + _buildCreatureStat('Hit Dice', creature.hitDice!, theme), + if (creature.speed != null) + _buildCreatureStat('Speed', '${creature.speed} ft.', theme), + const SizedBox(height: 16), + // Ability Scores + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + if (creature.abilityScoreStrength != null) + _buildAbilityScore('STR', creature.abilityScoreStrength!, theme), + if (creature.abilityScoreDexterity != null) + _buildAbilityScore('DEX', creature.abilityScoreDexterity!, theme), + if (creature.abilityScoreConstitution != null) + _buildAbilityScore('CON', creature.abilityScoreConstitution!, theme), + if (creature.abilityScoreIntelligence != null) + _buildAbilityScore('INT', creature.abilityScoreIntelligence!, theme), + if (creature.abilityScoreWisdom != null) + _buildAbilityScore('WIS', creature.abilityScoreWisdom!, theme), + if (creature.abilityScoreCharisma != null) + _buildAbilityScore('CHA', creature.abilityScoreCharisma!, theme), + ], + ), + if (creature.passivePerception != null) ...[ + const SizedBox(height: 16), + _buildCreatureStat('Passive Perception', + '${creature.passivePerception}', theme), + ], + if (creature.desc != null) ...[ + const SizedBox(height: 16), + Text( + creature.desc!, + style: theme.textTheme.bodyMedium, + ), + ], + if (creature.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${creature.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (creature.document!.gamesystem != null) + Text( + 'System: ${creature.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } + + Widget _buildCreatureStat(String label, String value, ThemeData theme) { + return Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 140, + child: Text( + '$label:', + style: theme.textTheme.titleSmall, + ), + ), + Expanded( + child: Text(value, style: theme.textTheme.bodyMedium), + ), + ], + ), + ); + } + + Widget _buildAbilityScore(String ability, int score, ThemeData theme) { + final modifier = ((score - 10) / 2).floor(); + final modifierStr = modifier >= 0 ? '+$modifier' : '$modifier'; + + return Column( + children: [ + Text( + ability, + style: theme.textTheme.labelSmall, + ), + Text( + '$score', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + Text( + modifierStr, + style: theme.textTheme.labelSmall, + ), + ], + ); + } +} + +/// Widget to display a Condition from Open5e v2 +class ConditionWidget extends StatelessWidget { + final Condition condition; + + const ConditionWidget({super.key, required this.condition}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + condition.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 8), + Text( + condition.desc, + style: theme.textTheme.bodyMedium, + ), + if (condition.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${condition.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (condition.document!.gamesystem != null) + Text( + 'System: ${condition.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} diff --git a/moonforge/lib/core/widgets/open5e/equipment_widgets.dart b/moonforge/lib/core/widgets/open5e/equipment_widgets.dart new file mode 100644 index 00000000..9e0883d7 --- /dev/null +++ b/moonforge/lib/core/widgets/open5e/equipment_widgets.dart @@ -0,0 +1,272 @@ +import 'package:flutter/material.dart'; +import 'package:moonforge/core/services/open5e/models/equipment.dart'; +import 'package:moonforge/core/widgets/surface_container.dart'; + +/// Widget to display a generic Item from Open5e v2 +class ItemWidget extends StatelessWidget { + final Item item; + + const ItemWidget({super.key, required this.item}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 8), + Text( + item.desc, + style: theme.textTheme.bodyMedium, + ), + if (item.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${item.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (item.document!.gamesystem != null) + Text( + 'System: ${item.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} + +/// Widget to display a MagicItem from Open5e v2 +class MagicItemWidget extends StatelessWidget { + final MagicItem magicItem; + + const MagicItemWidget({super.key, required this.magicItem}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + magicItem.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 4), + Row( + children: [ + if (magicItem.type != null) + Text( + magicItem.type!, + style: theme.textTheme.labelLarge, + ), + if (magicItem.rarity != null) ...[ + if (magicItem.type != null) const Text(' • '), + Text( + magicItem.rarity!, + style: theme.textTheme.labelLarge, + ), + ], + ], + ), + if (magicItem.requiresAttunement == true) ...[ + const SizedBox(height: 4), + Text( + 'Requires Attunement', + style: theme.textTheme.labelMedium?.copyWith( + fontStyle: FontStyle.italic, + ), + ), + ], + const SizedBox(height: 8), + Text( + magicItem.desc, + style: theme.textTheme.bodyMedium, + ), + if (magicItem.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${magicItem.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (magicItem.document!.gamesystem != null) + Text( + 'System: ${magicItem.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } +} + +/// Widget to display a Weapon from Open5e v2 +class WeaponWidget extends StatelessWidget { + final Weapon weapon; + + const WeaponWidget({super.key, required this.weapon}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + weapon.name, + style: theme.textTheme.headlineMedium, + ), + if (weapon.category != null) ...[ + const SizedBox(height: 4), + Text( + weapon.category!, + style: theme.textTheme.labelLarge, + ), + ], + const SizedBox(height: 16), + if (weapon.damage != null) + _buildWeaponStat('Damage', weapon.damage!, theme), + if (weapon.damageType != null) + _buildWeaponStat('Damage Type', weapon.damageType!, theme), + if (weapon.weight != null) + _buildWeaponStat('Weight', weapon.weight!, theme), + if (weapon.properties != null) + _buildWeaponStat('Properties', weapon.properties!, theme), + const SizedBox(height: 8), + Text( + weapon.desc, + style: theme.textTheme.bodyMedium, + ), + if (weapon.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${weapon.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (weapon.document!.gamesystem != null) + Text( + 'System: ${weapon.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } + + Widget _buildWeaponStat(String label, String value, ThemeData theme) { + return Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text( + '$label:', + style: theme.textTheme.titleSmall, + ), + ), + Expanded( + child: Text(value, style: theme.textTheme.bodyMedium), + ), + ], + ), + ); + } +} + +/// Widget to display Armor from Open5e v2 +class ArmorWidget extends StatelessWidget { + final Armor armor; + + const ArmorWidget({super.key, required this.armor}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + armor.name, + style: theme.textTheme.headlineMedium, + ), + if (armor.category != null) ...[ + const SizedBox(height: 4), + Text( + armor.category!, + style: theme.textTheme.labelLarge, + ), + ], + const SizedBox(height: 16), + if (armor.armorClass != null) + _buildArmorStat('AC', armor.armorClass!, theme), + if (armor.strength != null) + _buildArmorStat('Strength Required', armor.strength!, theme), + if (armor.stealthDisadvantage == true) + Text( + 'Stealth Disadvantage', + style: theme.textTheme.labelMedium?.copyWith( + color: theme.colorScheme.error, + ), + ), + if (armor.weight != null) + _buildArmorStat('Weight', armor.weight!, theme), + const SizedBox(height: 8), + Text( + armor.desc, + style: theme.textTheme.bodyMedium, + ), + if (armor.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${armor.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (armor.document!.gamesystem != null) + Text( + 'System: ${armor.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } + + Widget _buildArmorStat(String label, String value, ThemeData theme) { + return Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 140, + child: Text( + '$label:', + style: theme.textTheme.titleSmall, + ), + ), + Expanded( + child: Text(value, style: theme.textTheme.bodyMedium), + ), + ], + ), + ); + } +} diff --git a/moonforge/lib/core/widgets/open5e/spell_widgets.dart b/moonforge/lib/core/widgets/open5e/spell_widgets.dart new file mode 100644 index 00000000..52b011a8 --- /dev/null +++ b/moonforge/lib/core/widgets/open5e/spell_widgets.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:moonforge/core/services/open5e/models/spells.dart'; +import 'package:moonforge/core/widgets/surface_container.dart'; + +/// Widget to display a Spell from Open5e v2 +class SpellWidget extends StatelessWidget { + final Open5eSpell spell; + + const SpellWidget({super.key, required this.spell}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return SurfaceContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + spell.name, + style: theme.textTheme.headlineMedium, + ), + const SizedBox(height: 4), + Text( + 'Level ${spell.level ?? 0} ${spell.school ?? ''}${spell.ritual == true ? ' (ritual)' : ''}', + style: theme.textTheme.labelLarge, + ), + const SizedBox(height: 16), + _buildSpellStat('Casting Time', spell.castingTime, theme), + _buildSpellStat('Range', spell.range, theme), + _buildSpellStat('Components', spell.components, theme), + if (spell.material != null) + Padding( + padding: const EdgeInsets.only(left: 16, top: 4), + child: Text(spell.material!, style: theme.textTheme.bodySmall), + ), + _buildSpellStat('Duration', + '${spell.duration ?? ''}${spell.concentration == true ? ' (concentration)' : ''}', + theme), + const SizedBox(height: 16), + Text( + spell.desc, + style: theme.textTheme.bodyMedium, + ), + if (spell.higherLevel != null) ...[ + const SizedBox(height: 8), + Text( + 'At Higher Levels: ${spell.higherLevel}', + style: theme.textTheme.bodyMedium, + ), + ], + if (spell.document != null) ...[ + const SizedBox(height: 16), + Text( + 'Source: ${spell.document!.displayName}', + style: theme.textTheme.labelSmall, + ), + if (spell.document!.gamesystem != null) + Text( + 'System: ${spell.document!.gamesystem!.name}', + style: theme.textTheme.labelSmall, + ), + ], + ], + ), + ); + } + + Widget _buildSpellStat(String label, String? value, ThemeData theme) { + if (value == null || value.isEmpty) return const SizedBox.shrink(); + return Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + '$label:', + style: theme.textTheme.titleSmall, + ), + ), + Expanded( + child: Text(value, style: theme.textTheme.bodyMedium), + ), + ], + ), + ); + } +} diff --git a/moonforge/lib/features/encounters/widgets/add_combatant_dialog.dart b/moonforge/lib/features/encounters/widgets/add_combatant_dialog.dart index 0aeb962d..98f7a54a 100644 --- a/moonforge/lib/features/encounters/widgets/add_combatant_dialog.dart +++ b/moonforge/lib/features/encounters/widgets/add_combatant_dialog.dart @@ -97,7 +97,7 @@ class BestiaryMonsterList extends StatelessWidget { Text(l10n.errorSomethingWentWrong), const SizedBox(height: 8), ElevatedButton( - onPressed: () => bestiaryProvider.loadMonsters(forceSync: true), + onPressed: () => bestiaryProvider.loadCreatures(forceSync: true), child: Text(l10n.retry), ), ], @@ -105,21 +105,21 @@ class BestiaryMonsterList extends StatelessWidget { ); } - final monsters = bestiaryProvider.monsters; + final creatures = bestiaryProvider.creatures; - if (monsters.isEmpty) { + if (creatures.isEmpty) { return Center(child: Text(l10n.emptyStateNoItems)); } return ListView.builder( - itemCount: monsters.length, + itemCount: creatures.length, itemBuilder: (context, index) { - final monster = monsters[index] as Map; - final name = monster['name'] as String? ?? 'Unknown'; - final cr = monster['cr'] as String? ?? '0'; + final creature = creatures[index] as Map; + final name = creature['name'] as String? ?? 'Unknown'; + final cr = creature['cr'] as String? ?? '0'; final xp = EncounterDifficultyService.getXpForCr(cr); - final hp = _parseHp(monster['hp']); - final ac = _parseAc(monster['ac']); + final hp = _parseHp(creature['hp']); + final ac = _parseAc(creature['ac']); return ListTile( title: Text(name), diff --git a/moonforge/lib/features/open5e_browser/views/open5e_browser_view.dart b/moonforge/lib/features/open5e_browser/views/open5e_browser_view.dart new file mode 100644 index 00000000..f7a10c72 --- /dev/null +++ b/moonforge/lib/features/open5e_browser/views/open5e_browser_view.dart @@ -0,0 +1,533 @@ +import 'package:flutter/material.dart' hide Alignment; +import 'package:moonforge/core/services/open5e/index.dart'; +import 'package:moonforge/core/services/persistence_service.dart'; +import 'package:moonforge/core/widgets/open5e/character_widgets.dart'; +import 'package:moonforge/core/widgets/open5e/creature_widgets.dart'; +import 'package:moonforge/core/widgets/open5e/equipment_widgets.dart'; +import 'package:moonforge/core/widgets/open5e/spell_widgets.dart'; + +enum Open5eEndpointType { + creatures, + spells, + backgrounds, + species, + classes, + feats, + conditions, + items, + magicItems, + weapons, + armor, + abilities, + skills, + creatureTypes, + creatureSets, + spellSchools, + damageTypes, + languages, + alignments, + sizes, + environments, + itemSets, + itemCategories, + itemRarities, + weaponProperties, +} + +extension Open5eEndpointTypeExtension on Open5eEndpointType { + String get displayName { + switch (this) { + case Open5eEndpointType.creatures: + return 'Creatures'; + case Open5eEndpointType.spells: + return 'Spells'; + case Open5eEndpointType.backgrounds: + return 'Backgrounds'; + case Open5eEndpointType.species: + return 'Species'; + case Open5eEndpointType.classes: + return 'Classes'; + case Open5eEndpointType.feats: + return 'Feats'; + case Open5eEndpointType.conditions: + return 'Conditions'; + case Open5eEndpointType.items: + return 'Items'; + case Open5eEndpointType.magicItems: + return 'Magic Items'; + case Open5eEndpointType.weapons: + return 'Weapons'; + case Open5eEndpointType.armor: + return 'Armor'; + case Open5eEndpointType.abilities: + return 'Abilities'; + case Open5eEndpointType.skills: + return 'Skills'; + case Open5eEndpointType.creatureTypes: + return 'Creature Types'; + case Open5eEndpointType.creatureSets: + return 'Creature Sets'; + case Open5eEndpointType.spellSchools: + return 'Spell Schools'; + case Open5eEndpointType.damageTypes: + return 'Damage Types'; + case Open5eEndpointType.languages: + return 'Languages'; + case Open5eEndpointType.alignments: + return 'Alignments'; + case Open5eEndpointType.sizes: + return 'Sizes'; + case Open5eEndpointType.environments: + return 'Environments'; + case Open5eEndpointType.itemSets: + return 'Item Sets'; + case Open5eEndpointType.itemCategories: + return 'Item Categories'; + case Open5eEndpointType.itemRarities: + return 'Item Rarities'; + case Open5eEndpointType.weaponProperties: + return 'Weapon Properties'; + } + } +} + +class Open5eBrowserView extends StatefulWidget { + const Open5eBrowserView({super.key}); + + @override + State createState() => _Open5eBrowserViewState(); +} + +class _Open5eBrowserViewState extends State { + late final Open5eService _service; + Open5eEndpointType _selectedEndpoint = Open5eEndpointType.creatures; + String _selectedGameSystem = GameSystemKey.edition2024; + List _results = []; + bool _isLoading = false; + String? _errorMessage; + String _searchQuery = ''; + final TextEditingController _searchController = TextEditingController(); + + @override + void initState() { + super.initState(); + _service = Open5eService(PersistenceService()); + // Use addPostFrameCallback to ensure widget is fully built before loading + WidgetsBinding.instance.addPostFrameCallback((_) { + _loadData(); + }); + } + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + + Future _loadData() async { + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + final options = Open5eQueryOptions( + gameSystemKey: _selectedGameSystem, + search: _searchQuery.isEmpty ? null : _searchQuery, + limit: 50, + ); + + dynamic response; + + switch (_selectedEndpoint) { + case Open5eEndpointType.creatures: + response = await _service.getCreatures(options: options); + break; + case Open5eEndpointType.spells: + response = await _service.getSpells(options: options); + break; + case Open5eEndpointType.backgrounds: + response = await _service.getBackgrounds(options: options); + break; + case Open5eEndpointType.species: + response = await _service.getSpecies(options: options); + break; + case Open5eEndpointType.classes: + response = await _service.getClasses(options: options); + break; + case Open5eEndpointType.feats: + response = await _service.getFeats(options: options); + break; + case Open5eEndpointType.conditions: + response = await _service.getConditions(options: options); + break; + case Open5eEndpointType.items: + response = await _service.getItems(options: options); + break; + case Open5eEndpointType.magicItems: + response = await _service.getMagicItems(options: options); + break; + case Open5eEndpointType.weapons: + response = await _service.getWeapons(options: options); + break; + case Open5eEndpointType.armor: + response = await _service.getArmor(options: options); + break; + case Open5eEndpointType.abilities: + response = await _service.getAbilities(options: options); + break; + case Open5eEndpointType.skills: + response = await _service.getSkills(options: options); + break; + case Open5eEndpointType.creatureTypes: + response = await _service.getCreatureTypes(options: options); + break; + case Open5eEndpointType.creatureSets: + response = await _service.getCreatureSets(options: options); + break; + case Open5eEndpointType.spellSchools: + response = await _service.getSpellSchools(options: options); + break; + case Open5eEndpointType.damageTypes: + response = await _service.getDamageTypes(options: options); + break; + case Open5eEndpointType.languages: + response = await _service.getLanguages(options: options); + break; + case Open5eEndpointType.alignments: + response = await _service.getAlignments(options: options); + break; + case Open5eEndpointType.sizes: + response = await _service.getSizes(options: options); + break; + case Open5eEndpointType.environments: + response = await _service.getEnvironments(options: options); + break; + case Open5eEndpointType.itemSets: + response = await _service.getItemSets(options: options); + break; + case Open5eEndpointType.itemCategories: + response = await _service.getItemCategories(options: options); + break; + case Open5eEndpointType.itemRarities: + response = await _service.getItemRarities(options: options); + break; + case Open5eEndpointType.weaponProperties: + response = await _service.getWeaponProperties(options: options); + break; + } + + if (response != null) { + setState(() { + _results = response.results; + _isLoading = false; + _errorMessage = null; + }); + } else { + setState(() { + _results = []; + _isLoading = false; + _errorMessage = 'Failed to load data from Open5e API. Please check your network connection.'; + }); + } + } catch (e, stackTrace) { + print('Error loading Open5e data: $e'); + print('Stack trace: $stackTrace'); + setState(() { + _results = []; + _isLoading = false; + _errorMessage = 'Error loading data: $e'; + }); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error loading data: $e'), + duration: const Duration(seconds: 5), + action: SnackBarAction( + label: 'Retry', + onPressed: _loadData, + ), + ), + ); + } + } + } + + void _showDetailModal(dynamic item) { + showDialog( + context: context, + builder: (context) => Dialog( + child: Container( + constraints: const BoxConstraints(maxWidth: 600), + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: _buildDetailWidget(item), + ), + ), + ), + ); + } + + Widget _buildDetailWidget(dynamic item) { + switch (_selectedEndpoint) { + case Open5eEndpointType.creatures: + return CreatureWidget(creature: item as Creature); + case Open5eEndpointType.spells: + return SpellWidget(spell: item as Open5eSpell); + case Open5eEndpointType.backgrounds: + return BackgroundWidget(background: item as Background); + case Open5eEndpointType.species: + return SpeciesWidget(species: item as Species); + case Open5eEndpointType.classes: + return CharacterClassWidget(characterClass: item as CharacterClass); + case Open5eEndpointType.feats: + return FeatWidget(feat: item as Feat); + case Open5eEndpointType.conditions: + return ConditionWidget(condition: item as Condition); + case Open5eEndpointType.items: + return ItemWidget(item: item as Item); + case Open5eEndpointType.magicItems: + return MagicItemWidget(magicItem: item as MagicItem); + case Open5eEndpointType.weapons: + return WeaponWidget(weapon: item as Weapon); + case Open5eEndpointType.armor: + return ArmorWidget(armor: item as Armor); + case Open5eEndpointType.abilities: + return AbilityWidget(ability: item as Ability); + case Open5eEndpointType.skills: + return SkillWidget(skill: item as Skill); + default: + // For simple types (CreatureType, SpellSchool, etc.), show basic info + return _buildSimpleWidget(item); + } + } + + Widget _buildSimpleWidget(dynamic item) { + String name = ''; + String? desc; + + if (item is CreatureType || + item is CreatureSet || + item is SpellSchool || + item is DamageType || + item is Language || + item is Alignment || + item is Size || + item is Environment || + item is ItemSet || + item is ItemCategory || + item is ItemRarity || + item is WeaponProperty) { + name = item.name; + desc = item.desc; + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + name, + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + ), + if (desc != null && desc.isNotEmpty) ...[ + const SizedBox(height: 16), + Text(desc), + ], + ], + ); + } + + String _getItemName(dynamic item) { + return item.name ?? 'Unknown'; + } + + String? _getItemDescription(dynamic item) { + if (item is Creature) { + return '${item.type ?? 'Unknown'} - CR ${item.challengeRatingText ?? item.challengeRatingDecimal?.toString() ?? '?'}'; + } + if (item is Open5eSpell) { + return 'Level ${item.level ?? '?'} ${item.school ?? 'Unknown'}'; + } + if (item is Species) { + return item.desc != null && item.desc!.length > 100 + ? '${item.desc!.substring(0, 100)}...' + : item.desc; + } + if (item is Background || item is Feat || item is Condition) { + final desc = item.desc; + return desc != null && desc.length > 100 + ? '${desc.substring(0, 100)}...' + : desc; + } + if (item is CharacterClass) return item.desc.length > 100 ? '${item.desc.substring(0, 100)}...' : item.desc; + if (item is MagicItem || item is Item) return item.type; + if (item is Weapon) return item.category; + if (item is Armor) return item.category; + if (item is Ability) return item.fullName; + if (item is Skill) return item.ability; + // For simple types, just return the first part of description + final desc = item.desc; + if (desc != null && desc.isNotEmpty) { + return desc.length > 100 ? '${desc.substring(0, 100)}...' : desc; + } + return null; + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + appBar: AppBar( + title: const Text('Open5e Browser'), + ), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: DropdownButtonFormField( + value: _selectedEndpoint, + decoration: const InputDecoration( + labelText: 'Endpoint', + border: OutlineInputBorder(), + ), + items: Open5eEndpointType.values.map((type) { + return DropdownMenuItem( + value: type, + child: Text(type.displayName), + ); + }).toList(), + onChanged: (value) { + if (value != null) { + setState(() { + _selectedEndpoint = value; + _results = []; + }); + _loadData(); + } + }, + ), + ), + const SizedBox(width: 16), + Expanded( + child: DropdownButtonFormField( + value: _selectedGameSystem, + decoration: const InputDecoration( + labelText: 'Game System', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem( + value: GameSystemKey.edition2024, + child: Text('5e 2024'), + ), + DropdownMenuItem( + value: GameSystemKey.edition2014, + child: Text('5e 2014'), + ), + DropdownMenuItem( + value: GameSystemKey.advancedEdition, + child: Text('A5e'), + ), + ], + onChanged: (value) { + if (value != null) { + setState(() { + _selectedGameSystem = value; + _results = []; + }); + _loadData(); + } + }, + ), + ), + ], + ), + const SizedBox(height: 16), + TextField( + controller: _searchController, + decoration: InputDecoration( + labelText: 'Search', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: const Icon(Icons.search), + onPressed: () { + setState(() => _searchQuery = _searchController.text); + _loadData(); + }, + ), + ), + onSubmitted: (value) { + setState(() => _searchQuery = value); + _loadData(); + }, + ), + ], + ), + ), + Expanded( + child: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _errorMessage != null + ? Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + size: 48, + color: Colors.red, + ), + const SizedBox(height: 16), + Text( + _errorMessage!, + style: theme.textTheme.bodyLarge, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton.icon( + onPressed: _loadData, + icon: const Icon(Icons.refresh), + label: const Text('Retry'), + ), + ], + ), + ), + ) + : _results.isEmpty + ? Center( + child: Text( + 'No results found', + style: theme.textTheme.bodyLarge, + ), + ) + : ListView.builder( + itemCount: _results.length, + itemBuilder: (context, index) { + final item = _results[index]; + final name = _getItemName(item); + final description = _getItemDescription(item); + + return ListTile( + title: Text(name), + subtitle: + description != null ? Text(description) : null, + onTap: () => _showDetailModal(item), + trailing: const Icon(Icons.chevron_right), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/moonforge/lib/gen/colors.gen.dart b/moonforge/lib/gen/colors.gen.dart index 4f60913b..d5ca0954 100644 --- a/moonforge/lib/gen/colors.gen.dart +++ b/moonforge/lib/gen/colors.gen.dart @@ -4,12 +4,12 @@ /// FlutterGen /// ***************************************************** +import 'package:flutter/material.dart'; // coverage:ignore-file // ignore_for_file: type=lint // ignore_for_file: deprecated_member_use,directives_ordering,implicit_dynamic_list_literal,unnecessary_import import 'package:flutter/painting.dart'; -import 'package:flutter/material.dart'; class ColorName { ColorName._(); @@ -17,8 +17,8 @@ class ColorName { /// Color: #E8A6D4 static const Color accent = Color(0xFFE8A6D4); - /// Color: #FF6EC1 - static const Color brandPrimary = Color(0xFFFF6EC1); + /// Color: #A855F7 + static const Color brandPrimary = Color(0xFFA855F7); /// Color: #4E3847 static const Color brandSecondary = Color(0xFF4E3847); diff --git a/moonforge/lib/layout/destinations.dart b/moonforge/lib/layout/destinations.dart index 333f3722..1c2bcdb7 100644 --- a/moonforge/lib/layout/destinations.dart +++ b/moonforge/lib/layout/destinations.dart @@ -23,6 +23,11 @@ final List kPrimaryTabs = [ location: '/campaign', ), TabSpec(label: 'Party', icon: DomainType.party.icon, location: '/party'), + TabSpec( + label: 'Open5e Browser', + icon: Icons.library_books_outlined, + location: '/open5e-browser', + ), TabSpec( label: 'Settings', icon: Icons.settings_outlined, diff --git a/moonforge/lib/layout/widgets/common/app_navigation_rail.dart b/moonforge/lib/layout/widgets/common/app_navigation_rail.dart index 150c9875..ca5ab772 100644 --- a/moonforge/lib/layout/widgets/common/app_navigation_rail.dart +++ b/moonforge/lib/layout/widgets/common/app_navigation_rail.dart @@ -45,10 +45,6 @@ class AppNavigationRail extends StatelessWidget { final tocEntries = TocDeclaration.of(context); final tocController = TocProvider.of(context); - logger.d( - 'AppNavigationRail: Building - TOC entries: ${tocEntries != null ? "${tocEntries.length} from TocDeclaration" : "null"}, controller: ${tocController != null ? "found" : "null"}', - ); - // For mobile compact, always use collapsed. Otherwise, respect user settings. final shouldExpand = !forceCollapsed && settings.isRailNavExtended; @@ -85,8 +81,6 @@ class AppNavigationRail extends StatelessWidget { ),*/ ]; - logger.d('AppNavigationRail: Created ${sections.length} sections'); - return NavigationRailM3E( type: shouldExpand ? NavigationRailM3EType.expanded @@ -99,9 +93,6 @@ class AppNavigationRail extends StatelessWidget { if (tocController != null && tocEntries != null && i >= tabs.length) { final tocIndex = i - tabs.length; if (tocIndex < tocEntries.length) { - logger.d( - 'AppNavigationRail: Scrolling to TOC entry at index $tocIndex', - ); tocController.scrollToEntry(tocEntries[tocIndex]); return; // Don't trigger navigation for TOC items } diff --git a/moonforge/lib/main.dart b/moonforge/lib/main.dart index c640d51e..359aa403 100644 --- a/moonforge/lib/main.dart +++ b/moonforge/lib/main.dart @@ -116,17 +116,17 @@ void _initializeLogger() { // In debug mode, enable additional logging contexts for development if (kDebugMode) { logger.enableContexts([ - LogContext.sync, // Enable sync logging to debug sync operations - LogContext.database, // Enable database logging for query debugging + LogContext.sync, // Enable sync logging to debug sync operations + LogContext.database, // Enable database logging for query debugging // LogContext.auth, // Uncomment to debug authentication issues - // LogContext.navigation, // Uncomment to debug navigation issues + LogContext.navigation, // Uncomment to debug navigation issues // LogContext.ui, // Uncomment to debug UI state issues - // LogContext.network, // Uncomment to debug network requests + LogContext.network, // Uncomment to debug network requests // LogContext.data, // Uncomment to debug data parsing issues ]); logger.i('Logger initialized with contexts: ${logger.enabledContexts}'); } - + // In release mode, only general context is enabled (default) // This reduces log noise in production while keeping errors visible } diff --git a/moonforge/test/core/services/open5e_service_test.dart b/moonforge/test/core/services/open5e_service_test.dart new file mode 100644 index 00000000..668d5645 --- /dev/null +++ b/moonforge/test/core/services/open5e_service_test.dart @@ -0,0 +1,337 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; +import 'package:mocktail/mocktail.dart'; +import 'package:moonforge/core/services/open5e/index.dart'; +import 'package:moonforge/core/services/persistence_service.dart'; + +class MockClient extends Mock implements http.Client {} + +class MockPersistenceService extends Mock implements PersistenceService {} + +void main() { + group('Open5eEndpoints', () { + test('getEndpoint returns correct URL for known resources', () { + expect( + Open5eEndpoints.getEndpoint('creatures'), + 'https://api.open5e.com/v2/creatures/?format=api', + ); + expect( + Open5eEndpoints.getEndpoint('spells'), + 'https://api.open5e.com/v2/spells/?format=api', + ); + expect( + Open5eEndpoints.getEndpoint('weapons'), + 'https://api.open5e.com/v2/weapons/?format=api', + ); + expect( + Open5eEndpoints.getEndpoint('species'), + 'https://api.open5e.com/v2/species/?format=api', + ); + }); + + test('getEndpoint returns null for unknown resources', () { + expect(Open5eEndpoints.getEndpoint('unknown'), isNull); + }); + }); + + group('Open5eQueryOptions', () { + test('toQueryParams includes all parameters', () { + final options = Open5eQueryOptions( + search: 'dragon', + documentKey: DocumentKey.tomeOfBeasts, + gameSystemKey: GameSystemKey.edition2024, + ordering: 'name', + page: 2, + limit: 50, + filters: {'challenge_rating_decimal': '3'}, + creatureType: 'dragon', + ); + + final params = options.toQueryParams(); + + expect(params['name__icontains'], 'dragon'); + expect(params['document__key__iexact'], DocumentKey.tomeOfBeasts); + expect(params['document__gamesystem__key__iexact'], GameSystemKey.edition2024); + expect(params['ordering'], 'name'); + expect(params['page'], '2'); + expect(params['limit'], '50'); + expect(params['challenge_rating_decimal'], '3'); + expect(params['type'], 'dragon'); + }); + + test('toQueryParams handles minimal options with defaults', () { + final options = Open5eQueryOptions(); + final params = options.toQueryParams(); + + expect(params['page'], '1'); + expect(params['document__gamesystem__key__iexact'], GameSystemKey.edition2024); + expect(params.containsKey('name__icontains'), false); + expect(params.containsKey('document__key'), false); + }); + + test('GameSystemKey constants have correct values', () { + expect(GameSystemKey.edition2024, '5e-2024'); + expect(GameSystemKey.edition2014, '5e-2014'); + expect(GameSystemKey.advancedEdition, 'a5e'); + }); + + test('DocumentKey constants have correct values', () { + expect(DocumentKey.srd2024, 'srd-2024'); + expect(DocumentKey.srd2014, 'srd'); + expect(DocumentKey.tomeOfBeasts, 'tob'); + expect(DocumentKey.tomeOfBeasts2, 'tob2'); + expect(DocumentKey.creaturesCodex, 'cc'); + expect(DocumentKey.midgardHeroes, 'dmag'); + }); + }); + + group('PaginatedResponse', () { + test('fromJson parses valid response', () { + final json = { + 'count': 10, + 'next': 'https://api.example.com?page=2', + 'previous': null, + 'results': [ + { + 'url': 'https://api.open5e.com/v2/backgrounds/acolyte/', + 'key': 'acolyte', + 'name': 'Acolyte', + 'desc': 'Description 1', + }, + { + 'url': 'https://api.open5e.com/v2/backgrounds/soldier/', + 'key': 'soldier', + 'name': 'Soldier', + 'desc': 'Description 2', + }, + ], + }; + + final response = PaginatedResponse.fromJson( + json, + (item) => Background.fromJson(item), + ); + + expect(response.count, 10); + expect(response.next, 'https://api.example.com?page=2'); + expect(response.previous, isNull); + expect(response.results.length, 2); + expect(response.results[0].key, 'acolyte'); + expect(response.results[1].name, 'Soldier'); + }); + + test('fromJson handles empty results', () { + final json = { + 'count': 0, + 'results': [], + }; + + final response = PaginatedResponse.fromJson( + json, + (item) => Background.fromJson(item), + ); + + expect(response.count, 0); + expect(response.results, isEmpty); + }); + }); + + group('Open5eModels', () { + test('Background.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/backgrounds/acolyte/', + 'key': 'acolyte', + 'name': 'Acolyte', + 'desc': 'A religious devotee', + }; + + final background = Background.fromJson(json); + + expect(background.key, 'acolyte'); + expect(background.name, 'Acolyte'); + expect(background.desc, 'A religious devotee'); + }); + + test('Open5eSpell.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/spells/fireball/', + 'key': 'fireball', + 'name': 'Fireball', + 'desc': 'A burst of flame', + 'level': 3, + 'school': 'Evocation', + }; + + final spell = Open5eSpell.fromJson(json); + + expect(spell.key, 'fireball'); + expect(spell.name, 'Fireball'); + expect(spell.level, 3); + expect(spell.school, 'Evocation'); + }); + + test('Weapon.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/weapons/longsword/', + 'key': 'longsword', + 'name': 'Longsword', + 'category': 'Martial Melee Weapon', + 'type': 'Weapon', + }; + + final weapon = Weapon.fromJson(json); + + expect(weapon.key, 'longsword'); + expect(weapon.name, 'Longsword'); + expect(weapon.category, 'Martial Melee Weapon'); + }); + + test('Species.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/species/elf/', + 'key': 'elf', + 'name': 'Elf', + 'desc': 'Graceful and long-lived', + }; + + final species = Species.fromJson(json); + + expect(species.key, 'elf'); + expect(species.name, 'Elf'); + expect(species.desc, 'Graceful and long-lived'); + }); + + test('CharacterClass.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/classes/fighter/', + 'key': 'fighter', + 'name': 'Fighter', + 'desc': 'A master of martial combat', + }; + + final characterClass = CharacterClass.fromJson(json); + + expect(characterClass.key, 'fighter'); + expect(characterClass.name, 'Fighter'); + expect(characterClass.desc, 'A master of martial combat'); + }); + + test('Feat.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/feats/alert/', + 'key': 'alert', + 'name': 'Alert', + 'desc': 'Always on alert', + }; + + final feat = Feat.fromJson(json); + + expect(feat.key, 'alert'); + expect(feat.name, 'Alert'); + }); + + test('Condition.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/conditions/blinded/', + 'key': 'blinded', + 'name': 'Blinded', + 'desc': 'Cannot see', + }; + + final condition = Condition.fromJson(json); + + expect(condition.key, 'blinded'); + expect(condition.name, 'Blinded'); + }); + + test('Creature.fromJson parses correctly', () { + final json = { + 'url': 'https://api.open5e.com/v2/creatures/ancient-red-dragon/', + 'key': 'ancient-red-dragon', + 'name': 'Ancient Red Dragon', + 'type': 'Dragon', + 'challenge_rating_decimal': 24.00, + 'armor_class': 22, + }; + + final creature = Creature.fromJson(json); + + expect(creature.key, 'ancient-red-dragon'); + expect(creature.name, 'Ancient Red Dragon'); + expect(creature.type, 'Dragon'); + expect(creature.challengeRatingDecimal, 24.00); + expect(creature.armorClass, 22); + }); + }); + + group('Open5eService', () { + late MockPersistenceService mockPersistence; + late MockClient mockClient; + late Open5eService service; + + setUp(() { + mockPersistence = MockPersistenceService(); + mockClient = MockClient(); + service = Open5eService(mockPersistence, httpClient: mockClient); + + // Default stub for persistence methods + when(() => mockPersistence.read(any(), + boxName: any(named: 'boxName'))) + .thenReturn(null); + when(() => mockPersistence.write(any(), any(), + boxName: any(named: 'boxName'))) + .thenAnswer((_) async => {}); + }); + + test('service methods are available and type-safe for all 33 endpoints', () { + // Creatures + expect(service.getCreatures, isA()); + expect(service.getCreatureByKey, isA()); + expect(service.getCreatureTypes, isA()); + expect(service.getCreatureSets, isA()); + + // Spells + expect(service.getSpells, isA()); + expect(service.getSpellByKey, isA()); + expect(service.getSpellSchools, isA()); + + // Character + expect(service.getBackgrounds, isA()); + expect(service.getFeats, isA()); + expect(service.getSpecies, isA()); + expect(service.getClasses, isA()); + expect(service.getAbilities, isA()); + expect(service.getSkills, isA()); + + // Equipment + expect(service.getItems, isA()); + expect(service.getMagicItems, isA()); + expect(service.getWeapons, isA()); + expect(service.getArmor, isA()); + expect(service.getItemSets, isA()); + expect(service.getItemCategories, isA()); + expect(service.getItemRarities, isA()); + expect(service.getWeaponProperties, isA()); + + // Mechanics + expect(service.getConditions, isA()); + expect(service.getDamageTypes, isA()); + expect(service.getLanguages, isA()); + expect(service.getAlignments, isA()); + expect(service.getSizes, isA()); + expect(service.getEnvironments, isA()); + + // Documentation + expect(service.getDocuments, isA()); + expect(service.getGameSystems, isA()); + expect(service.getPublishers, isA()); + expect(service.getLicenses, isA()); + + // Rules & Media + expect(service.getRules, isA()); + expect(service.getRuleSets, isA()); + expect(service.getImages, isA()); + expect(service.getServices, isA()); + }); + }); +} diff --git a/moonforge/test/core/services/origin_resolver_test.dart b/moonforge/test/core/services/origin_resolver_test.dart index fb235fc6..509137a4 100644 --- a/moonforge/test/core/services/origin_resolver_test.dart +++ b/moonforge/test/core/services/origin_resolver_test.dart @@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:logger/logger.dart'; import 'package:moonforge/core/services/entity_gatherer.dart'; import 'package:moonforge/core/services/origin_resolver.dart'; -import 'package:moonforge/core/utils/logger.dart'; import 'package:moonforge/data/db/app_db.dart'; import 'package:moonforge/data/repo/adventure_repository.dart'; import 'package:moonforge/data/repo/campaign_repository.dart'; @@ -117,7 +116,7 @@ class FakeEncounterRepository implements EncounterRepository { void main() { // Configure logger for testing - allow warnings to help debug setUpAll(() { - logger = Logger( + var logger = Logger( printer: SimplePrinter(), level: Level.warning, // Allow warnings to see what's failing ); diff --git a/plan-navigationEnhancements.prompt.md b/plan-navigationEnhancements.prompt.md deleted file mode 100644 index 598097bb..00000000 --- a/plan-navigationEnhancements.prompt.md +++ /dev/null @@ -1,22 +0,0 @@ -# Navigation Enhancements Plan - -1. **Normalize chapter/adventure/scene navigation controls** - - Move chapter navigation controls to the bottom of the chapter detail column (after other sections) and ensure labels reflect chapter order. - - Ensure adventure detail view renders back/forward controls at the bottom (already started; verify placement and async handling). - - Add a bottom navigation footer to scene detail pages, mirroring the existing header controls, so users can move between scenes without scrolling. - -2. **Fix sidebar/auth button overflow** - - When the navigation rail is collapsed, constrain `AuthUserButton` to an icon-only chip (or hide the text) and adjust padding so the account button never clips. - - Verify expanded mode still shows the full button label. - -3. **Display adventure order numbers everywhere** - - Audit `ChapterView`, `AdventureListView`, and any other adventure listings to ensure the visible titles include their order number (fallback to index+1 if null). - -4. **Campaign Quill loading regression** - - Update the campaign view/edit controllers so the Quill editor always loads from `campaign.content['ops']` when present, falling back to summary/description only when content - is empty. - - Add regression widget tests that create a fake campaign with rich-text delta and assert the editor preloads it when entering edit mode twice. - -5. **Validation** - - Run `flutter analyze` and the affected widget/tests (at least the new regression test file) to ensure everything passes. -