Pagination class

A stateless widget rendering pagination controls with breakout room access management.

Displays page navigation buttons for switching between main room and breakout rooms in video conferencing. Implements role-based access control (host can visit any room, participants restricted to assigned room), socket-based room switching, and server synchronization via updateHostBreakout events.

Lifecycle & State Management:

  • Stateless widget (no internal state)
  • Reads current page from options.currentUserPage
  • Page changes trigger handlePageChange callback (typically updates parent state + server)
  • Access control checks performed in handleClick() before page change

Access Control Logic (in handleClick):

if (breakOutRoomStarted && !breakOutRoomEnded && targetPage != 0) {
  // Calculate which breakout room the page represents
  breakRoomIndex = targetPage - (mainRoomsLength - 1);
  
  // Find user's assigned breakout room
  userBreakoutRoom = breakoutRooms.findIndex(room => room.contains(member));
  
  if (userBreakoutRoom != breakRoomIndex && breakRoomIndex >= 0) {
    // User trying to access non-assigned room
    if (islevel != '2') {
      // Non-host: deny access with alert
      showAlert("You are not part of the breakout room N");
      return;
    } else {
      // Host: allow access, emit updateHostBreakout to server
      handlePageChange(page, breakRoom: breakRoomIndex, inBreakRoom: true);
      socket.emit('updateHostBreakout', newRoom);
    }
  } else {
    // User accessing assigned room or main room
    handlePageChange(page, breakRoom: breakRoomIndex, inBreakRoom: true);
    if (host leaving previous room) socket.emit('updateHostBreakout', -1);
  }
} else {
  // Not in breakout session: allow any page navigation
  handlePageChange(page, breakRoom: 0, inBreakRoom: false);
}

Page Button Rendering Logic:

1. Determine page state:
   - isActive = page == currentUserPage
   - isHomePage = page == 0
   - isLocked = (breakout session active) && (page is breakout room) && (user not member) && (user not host)
   - displayLabel = isHomePage ? star icon : page number or "Room N" or "Room N πŸ”’"

2. Build baseContent:
   - isHomePage: Icon(Icons.star, color: isActive ? yellow : grey)
   - else: Text(displayLabel, fontSize: 16, fontWeight: bold)

3. Apply pageContentBuilder hook (if provided)

4. Wrap in GestureDetector + Container:
   - onTap: handleClick(page) if !isActive
   - decoration: activeDecoration (blue shadow) or inactiveDecoration (black border)
   - margin: 5px horizontal/vertical
   - constraints: buttonsContainerStyle (if provided)

5. Apply pageButtonBuilder hook (if provided)

Socket Event Emission:

Event: 'updateHostBreakout'
Payload:
  - newRoom: breakRoomIndex (host entering new room)
  - prevRoom: hostNewRoom (host leaving previous room, optional)
  - roomName: roomName (current meeting room name)

Emitted when:
  - Host switches to breakout room (newRoom = breakRoomIndex)
  - Host returns to main room (newRoom = -1, prevRoom = previous breakRoomIndex)

Common Use Cases:

  1. Basic Main Room Pagination:

    Pagination(
      options: PaginationOptions(
        totalPages: 5, // 0 (main) + 1-5 (participant pages)
        currentUserPage: 0,
        parameters: parameters,
        activePageColor: Colors.blue,
        inactivePageColor: Colors.grey[300],
        handlePageChange: (options) async {
          // Switch displayed participants based on page
          await updateMainGrid(options.page);
        },
      ),
    )
    
  2. Breakout Room Navigation (Participant):

    // Scenario: 4 main pages, 3 breakout rooms; user in room 2
    Pagination(
      options: PaginationOptions(
        totalPages: 7, // 0-3 (main) + 4-6 (rooms 1-3)
        currentUserPage: 0,
        parameters: PaginationParameters(
          mainRoomsLength: 4,
          memberRoom: 1, // user in breakout room 2 (0-indexed)
          breakOutRoomStarted: true,
          breakOutRoomEnded: false,
          member: 'john_doe',
          breakoutRooms: [
            [BreakoutParticipant(name: 'alice')],
            [BreakoutParticipant(name: 'john_doe')], // user's room
            [BreakoutParticipant(name: 'charlie')],
          ],
          islevel: '1', // participant level
          showAlert: showAlertFunction,
        ),
      ),
    )
    // Result:
    // - Page 0-3: numeric labels (1-3, main room)
    // - Page 4: "Room 1 πŸ”’" (locked)
    // - Page 5: "Room 2" (unlocked, user's room)
    // - Page 6: "Room 3 πŸ”’" (locked)
    // - Clicking locked room shows alert
    
  3. Breakout Room Navigation (Host):

    // Scenario: Host can visit any breakout room
    Pagination(
      options: PaginationOptions(
        totalPages: 7,
        currentUserPage: 5, // currently in breakout room 2
        parameters: PaginationParameters(
          mainRoomsLength: 4,
          memberRoom: -1, // host not assigned to any room
          breakOutRoomStarted: true,
          breakOutRoomEnded: false,
          member: 'host_user',
          breakoutRooms: [[...], [...], [...]],
          hostNewRoom: 1, // host currently in room 2 (0-indexed)
          islevel: '2', // host level
          socket: socketInstance,
          roomName: 'meeting_room_123',
        ),
      ),
    )
    // Result:
    // - All pages unlocked (no πŸ”’ symbols)
    // - Clicking room 1 (page 4):
    //   1. Emit socket event
    //   2. Update local state: hostNewRoom = 0
    //   3. Switch to room 1 view
    

Override Integration: Integrates with MediasfuUICustomOverrides for global styling:

overrides: MediasfuUICustomOverrides(
  paginationOptions: ComponentOverride<PaginationOptions>(
    builder: (existingOptions) => PaginationOptions(
      totalPages: existingOptions.totalPages,
      currentUserPage: existingOptions.currentUserPage,
      parameters: existingOptions.parameters,
      handlePageChange: existingOptions.handlePageChange,
      activePageColor: Colors.deepPurple,
      inactivePageColor: Colors.grey[100],
      backgroundColor: Colors.grey[50]!,
      buttonsContainerStyle: BoxConstraints.tightFor(width: 55, height: 45),
    ),
  ),
),

Responsive Behavior:

  • Horizontal mode: maxHeight = paginationHeight, width expands
  • Vertical mode: maxWidth = paginationHeight (acts as width), height expands
  • ListView.builder creates buttons on demand (efficient for many pages)
  • Visibility widget hides entire component when showAspect=false

Performance Notes:

  • Stateless widget (no internal state to manage)
  • ListView.builder lazily builds page buttons (efficient for large page counts)
  • Access control checks only when button clicked (not during render)
  • Socket events emitted with ack for reliable delivery
  • Builder hooks called during every build (not cached)

Implementation Details:

  • Uses ListView.builder for efficient pagination rendering
  • Pages list generated via List.generate (0 to totalPages inclusive)
  • Active/inactive decorations use BoxShadow for depth effect
  • Home page (0) always uses star icon, others use text labels
  • Breakout room numbers calculated as: page - (mainRoomsLength - 1)
  • Socket emitWithAck ensures server receives updateHostBreakout events
  • getUpdatedAllParams() called before access checks to get latest state

Typical Usage Context:

  • Video conference main room pagination
  • Breakout room navigation with role-based access
  • Multi-page participant gallery
  • Host-controlled breakout session management
  • Room-based content switching with server sync
Inheritance

Constructors

Pagination({Key? key, required PaginationOptions 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 β†’ PaginationOptions
final
runtimeType β†’ Type
A representation of the runtime type of the object.
no setterinherited

Methods

build(BuildContext context) β†’ Widget
Describes the part of the user interface represented by this widget.
override
createElement() β†’ StatelessElement
Creates a StatelessElement to manage this widget's location in the tree.
inherited
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
handleClick(int page, int offSet) β†’ Future<void>
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