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:
-
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); }, ), )
-
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
-
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
-
- Object
- DiagnosticableTree
- Widget
- StatelessWidget
- Pagination
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