MainAspectComponent class

A stateful widget rendering the primary responsive video area with real-time screen size detection.

Manages the main video/content container that adapts to screen dimensions, orientation changes, and control visibility. Implements WidgetsBindingObserver to detect screen metric changes and invokes callbacks to update parent state for responsive layout adjustments across the app.

Lifecycle & Observers:

  • Implements WidgetsBindingObserver to listen for screen metric changes
  • Registers observer in initState() (adds addPostFrameCallback for initial calculation)
  • Removes observer in dispose() to prevent memory leaks
  • didChangeMetrics() called automatically on screen rotation, resize, keyboard visibility

Dimension Calculation (performed in _updateAspectStyles()):

// Computed dimensions:
parentWidth = screenWidth * containerWidthFraction

// Height depends on showControls flag:
if (showControls) {
  parentHeight = screenHeight * containerHeightFraction * defaultFraction
  // Example: 1920 * 1.0 * 0.94 = 1804.8px (reserves 6% for controls)
} else {
  parentHeight = screenHeight * containerHeightFraction - safeAreaTop
  // Example: 1920 * 1.0 - 44 = 1876px (full height minus notch)
}

Screen Size Classification Logic:

// Initial classification based on width:
isWideScreen = parentWidth > 768
isMediumScreen = parentWidth > 576 && parentWidth <= 768
isSmallScreen = parentWidth <= 576

// Override for very wide aspect ratios:
if (parentWidth > 1.5 * parentHeight) {
  isWideScreen = true
  isMediumScreen = false
  isSmallScreen = false
}
// This handles landscape tablets/desktops with wide aspect ratios

Callback Execution Flow:

1. Screen metric change detected (rotation, resize, keyboard)
2. didChangeMetrics() called by WidgetsBinding
3. _updateAspectStyles() calculates new dimensions
4. Screen size breakpoints evaluated
5. Callbacks invoked with new boolean states:
   - updateIsWideScreen(bool)
   - updateIsMediumScreen(bool)
   - updateIsSmallScreen(bool)
6. setState() called to trigger rebuild with new dimensions
7. Parent state updates (via callbacks) trigger other responsive adjustments

Rendering Structure:

Container
  ├─ color: backgroundColor
  ├─ width: parentWidth (calculated)
  ├─ height: parentHeight (calculated)
  └─ child: Stack
     ├─ children[0] (typically MainGridComponent)
     ├─ children[1] (e.g., audio indicators)
     └─ children[N] (e.g., overlays)

Common Use Cases:

  1. Full-Screen Video Conference:

    MainAspectComponent(
      options: MainAspectComponentOptions(
        backgroundColor: Colors.black,
        children: [
          MainGridComponent(
            options: MainGridComponentOptions(
              mainSize: mainGridStream != null ? mainGridStream!.length : 0,
              height: parameters.componentSizes.mainHeight,
              width: parameters.componentSizes.mainWidth,
              backgroundColor: Colors.grey[900]!,
              children: mainGridStreams,
              showAspect: showMainVideo,
              timeBackgroundColor: Colors.green,
              meetingProgressTime: parameters.meetingProgressTime,
            ),
          ),
        ],
        showControls: true, // reserves space for control bar
        containerWidthFraction: 1.0,
        containerHeightFraction: 1.0,
        defaultFraction: 0.94, // 94% height for video, 6% for controls
        updateIsWideScreen: (isWide) {
          parameters.updateIsWideScreen(isWide);
          // Trigger grid layout recalculation
        },
        updateIsMediumScreen: (isMed) {
          parameters.updateIsMediumScreen(isMed);
        },
        updateIsSmallScreen: (isSmall) {
          parameters.updateIsSmallScreen(isSmall);
        },
      ),
    )
    
  2. Screenshare Display (No Control Bar):

    MainAspectComponent(
      options: MainAspectComponentOptions(
        backgroundColor: Colors.black,
        children: [
          VideoCard(
            options: VideoCardOptions(
              videoStream: screenshareStream,
              participant: presenter,
              parameters: parameters,
            ),
          ),
        ],
        showControls: false, // full height minus safe area
        containerWidthFraction: 1.0,
        containerHeightFraction: 1.0,
        defaultFraction: 1.0, // not applied when showControls=false
        updateIsWideScreen: (isWide) => handleScreenResize(isWide),
        updateIsMediumScreen: (_) {},
        updateIsSmallScreen: (_) {},
      ),
    )
    
  3. Split-Screen Layout:

    MainAspectComponent(
      options: MainAspectComponentOptions(
        backgroundColor: Colors.grey[900]!,
        children: [
          Row(
            children: [
              Expanded(child: videoGrid), // main participants
              Expanded(child: screenshareView), // shared content
            ],
          ),
        ],
        showControls: true,
        containerWidthFraction: 1.0,
        containerHeightFraction: 1.0,
        defaultFraction: 0.92, // slightly more space for controls
        updateIsWideScreen: (isWide) {
          // Switch to vertical layout if not wide
          if (!isWide) {
            updateLayout(LayoutMode.vertical);
          } else {
            updateLayout(LayoutMode.horizontal);
          }
        },
        updateIsMediumScreen: (_) {},
        updateIsSmallScreen: (_) {},
      ),
    )
    
  4. Responsive Gallery Mode:

    MainAspectComponent(
      options: MainAspectComponentOptions(
        backgroundColor: Colors.black,
        children: [
          FlexibleGrid(
            options: FlexibleGridOptions(
              customWidth: parameters.componentSizes.mainWidth,
              customHeight: parameters.componentSizes.mainHeight,
              rows: parameters.gridRows,
              columns: parameters.gridCols,
              componentsToRender: allParticipantCards,
              backgroundColor: Colors.transparent,
            ),
          ),
        ],
        showControls: true,
        containerWidthFraction: 1.0,
        containerHeightFraction: 1.0,
        defaultFraction: 0.94,
        updateIsWideScreen: (isWide) {
          // Adjust grid dimensions based on screen size
          parameters.updateIsWideScreen(isWide);
          if (isWide) {
            parameters.updateGridCols(4); // more columns on wide screens
          } else {
            parameters.updateGridCols(2); // fewer columns on narrow screens
          }
        },
        updateIsMediumScreen: (isMed) {
          parameters.updateIsMediumScreen(isMed);
          if (isMed) parameters.updateGridCols(3);
        },
        updateIsSmallScreen: (isSmall) {
          parameters.updateIsSmallScreen(isSmall);
          if (isSmall) parameters.updateGridCols(1);
        },
      ),
    )
    

Override Integration: Override not typically used for MainAspectComponent (core layout component), but dimensions can be influenced via parameters:

// In parameters initialization:
parameters.updateComponentSizes(ComponentSizesType(
  mainHeight: MediaQuery.of(context).size.height * 0.94,
  mainWidth: MediaQuery.of(context).size.width,
  otherHeight: MediaQuery.of(context).size.height * 0.06,
  otherWidth: MediaQuery.of(context).size.width,
));

Responsive Behavior:

  • Automatically recalculates dimensions on orientation change (portrait ↔ landscape)
  • Updates screen size states when keyboard appears/disappears (height change)
  • Adjusts for safe area insets (notch, status bar) when showControls=false
  • Invokes callbacks to propagate screen size changes to parent state
  • Rebuilds only when dimensions change (not on every frame)

State Update Triggers:

  • Orientation change → didChangeMetrics() → _updateAspectStyles() → callbacks + setState()
  • Screen resize (desktop window) → didChangeMetrics() → recalculation
  • Keyboard visibility change → didChangeMetrics() → height recalculation
  • Initial build → addPostFrameCallback → _updateAspectStyles()
  • showControls prop change → widget update → build with new height logic

Performance Notes:

  • Stateful widget (maintains no internal state beyond component lifecycle)
  • Uses WidgetsBindingObserver for efficient screen metric listening
  • Callbacks invoked only on actual dimension changes (not every frame)
  • setState() called only when screen metrics change (efficient rebuilds)
  • Stack renders all children without lazy loading (suitable for small child count)

Implementation Details:

  • Calculates parentWidth/parentHeight fresh on every build (no caching)
  • Safe area insets include both padding and systemGestureInsets
  • Aspect ratio override (width > 1.5 * height) handles ultra-wide displays
  • Checks mounted before setState() to prevent errors after dispose
  • Container uses calculated dimensions (no intrinsic sizing)

Typical Usage Context:

  • Primary video area in video conferencing apps
  • Main stage for webinar/broadcast applications
  • Central content area for screenshare display
  • Gallery view container for participant grid
  • Spotlight mode for single active speaker
Inheritance

Constructors

MainAspectComponent.new({Key? key, required MainAspectComponentOptions options})
const

Properties

hashCode int
The hash code for this object.
no setterinherited
key Key?
Controls how one widget replaces another widget in the tree.
finalinherited
options MainAspectComponentOptions
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited

Methods

createElement() StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() → _MainAspectComponentState
Creates the mutable state for this widget at a given location in the tree.
override
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object.
inherited
toStringShort() String
A short, textual description of this widget.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited