builder method

Widget builder(
  1. BuildContext context,
  2. BoxConstraints constraints
)

Implementation

Widget builder(BuildContext context, BoxConstraints constraints)
{
  Log().debug('Build called on framework view => <FML name=${widget.model.templateName} url="${widget.model.url}"/>');

  // model is initializing
  if (!widget.model.initialized) return Scaffold(body: Center(child: BusyView(BusyModel(null, visible: true))));

  // fire navigator change
  onNavigatorChange();

  // set orientation
  String ori = widget.model.orientation ?? 'all';
  switch (ori.toLowerCase())
  {
    case "landscape":
      orientation = [DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft];
      break;
    case "portrait":
      orientation = [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown];
      break;
    case "all":
      orientation = [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft];
      break;
    default:
      orientation = [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft];
      break;
  }
  SystemChrome.setPreferredOrientations(orientation);

  // set constraints
  widget.model.minWidth  = constraints.minWidth;
  widget.model.maxWidth  = constraints.maxWidth;
  widget.model.minHeight = constraints.minHeight;
  widget.model.maxHeight = constraints.maxHeight;

  // build body
  List<Widget> children = [];
  widget.model.children?.forEach((model)
  {
    if (model is IViewableWidget) {
      children.add((model as IViewableWidget).getView());
    }
  });
  if (children.isEmpty) children.add(Container());

  // post onstart callback
  if (!started)
  {
    started = true;
    WidgetsBinding.instance.addPostFrameCallback((_) => widget.model.onStart(context));
  }

  viewportWidth  = constraints.maxWidth;
  viewportHeight = constraints.maxHeight;

  viewportSafeArea = MediaQuery.of(context).padding.top;

  // build header model
  Widget header = Container();
  if (widget.model.header != null && widget.model.header!.visible != false)
  {
    // setting the min and max heights from the constraint
    // sets the height if height is a percentage
    widget.model.header!.minHeight = constraints.minHeight;
    widget.model.header!.maxHeight = constraints.maxHeight;

    // set width && height
    headerModel.width  = viewportWidth;
    headerModel.height = widget.model.header!.height ?? widget.model.header!.maxheight;

    // build the header
    header = BoxView(headerModel, child: HeaderView(widget.model.header!));
  }
  else headerModel.height = 0;

  // build footer model
  Widget footer = Container();
  if (widget.model.footer != null && widget.model.footer!.visible != false)
  {
    widget.model.footer!.minHeight = constraints.minHeight;
    widget.model.footer!.maxHeight = constraints.maxHeight;

    // set width && height
    footerModel.width  = viewportWidth;
    footerModel.height = widget.model.footer!.height;

    footer = BoxView(footerModel, child: FooterView(widget.model.footer!));
  }
  else footerModel.height = 0;

  bodyModel.height = viewportHeight - (headerModel.height ?? 0) - (footerModel.height ?? 0) - viewportSafeArea.ceil();
  bodyModel.width  = viewportWidth;
  Widget body = NotificationListener<ScrollNotification>(onNotification: onScroll, child: BoxView(bodyModel, child: Stack(fit: StackFit.loose, children: children)));

  List<Widget> stackChildren = [];
  stackChildren.add(header);
  stackChildren.add(body);
  stackChildren.add(footer);

  // We need to provide the stacks children to drawer because positioned
  // widgets must be direct children but the drawer uses a builder widget
  drawerView = (widget.model.drawer != null) ? DrawerView(widget.model.drawer!, Column(mainAxisSize: MainAxisSize.min, children: [...stackChildren])) : null;
  Widget? drawer = drawerView != null ? drawerView : Container();

  // primary view
  Widget? view = drawerView != null ? drawer : Container(child: SingleChildScrollView( controller: _scrollController, child: Column(mainAxisSize: MainAxisSize.min, children: [...stackChildren])));

  // scaffold with safe area
  view = SafeArea(child: Scaffold(resizeToAvoidBottomInset: true, body: view));

  // simulate a swipe to move back on all desktop applications
  // and mobile IOS applications
  bool enableSwipeBack = isDesktop || (isMobile && System().useragent == "ios");

  final detector = (drawerView != null) ?
    GestureDetector(
    behavior: HitTestBehavior.translucent,
    onTap: () =>  WidgetModel.unfocus(),
    onVerticalDragStart: (dragStartDetails) => drawerView!.onDragOpen(dragStartDetails, 'vertical'),
    onHorizontalDragStart: (dragStartDetails) => drawerView!.onDragOpen(dragStartDetails, 'horizontal'),
    onVerticalDragUpdate: (dragUpdateDetails) => drawerView!.onDragSheet(dragUpdateDetails, 'vertical', true),
    onHorizontalDragUpdate: (dragUpdateDetails) => drawerView!.onDragSheet(dragUpdateDetails, 'horizontal', true),
    onVerticalDragEnd: (dragEndDetails) => drawerView!.onDragEnd(dragEndDetails, 'vertical', false),
    onHorizontalDragEnd: (dragEndDetails) => drawerView!.onDragEnd(dragEndDetails, 'horizontal', false),
    onLongPressStart: kDebugMode ? (_) => onLongPressStart() : null,
    onLongPressEnd:   kDebugMode ? (_) => onLongPressEnd()   : null,
    child: view)
   :
   enableSwipeBack ?
   GestureDetector(behavior: HitTestBehavior.translucent,
    onHorizontalDragStart: onDragStart,
    onHorizontalDragEnd: onDragEnd,
    onHorizontalDragUpdate: onDragUpdate,
    onTap: () =>  WidgetModel.unfocus(),
    onLongPressStart: kDebugMode ? (_) => onLongPressStart() : null,
    onLongPressEnd:   kDebugMode ? (_) => onLongPressEnd()   : null,
    child: view) :
   GestureDetector(behavior: HitTestBehavior.translucent,
       onTap: () =>  WidgetModel.unfocus(),
       onLongPressStart: kDebugMode ? (_) => onLongPressStart() : null,
       onLongPressEnd:   kDebugMode ? (_) => onLongPressEnd()   : null,
       child: view);

  return detector;
}