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