Listening for Events
The UserView Flutter SDK exposes all events as Dart Streams. Subscribe to them for reactive event handling.
Listening for Events
import 'dart:async';
import 'package:upscopeio_flutter_sdk/upscopeio_flutter_sdk.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final List<StreamSubscription> _subscriptions = [];
@override
void initState() {
super.initState();
_subscriptions.add(
Upscope.instance.connectionState.listen((state) {
switch (state) {
case ConnectionState.inactive:
print('Inactive');
case ConnectionState.connecting:
print('Connecting...');
case ConnectionState.connected:
print('Connected');
case ConnectionState.reconnecting:
print('Reconnecting...');
case ConnectionState.error:
print('Error');
}
}),
);
_subscriptions.add(
Upscope.instance.onSessionStarted.listen((_) {
print('Session started');
}),
);
_subscriptions.add(
Upscope.instance.onSessionEnded.listen((reason) {
switch (reason) {
case SessionEndReason.userStopped:
print('User ended session');
case SessionEndReason.agentStopped:
print('Agent ended session');
case SessionEndReason.timeout:
print('Session timed out');
case SessionEndReason.error:
print('Session error');
}
}),
);
_subscriptions.add(
Upscope.instance.onCustomMessageReceived.listen((msg) {
print('Message from ${msg.viewerId}: ${msg.message}');
}),
);
_subscriptions.add(
Upscope.instance.onError.listen((error) {
print('Error: ${error.code} - ${error.message}');
}),
);
_subscriptions.add(
Upscope.instance.onViewerJoined.listen((viewer) {
print('Viewer joined: ${viewer.name ?? viewer.id}');
}),
);
_subscriptions.add(
Upscope.instance.onViewerLeft.listen((viewerId) {
print('Viewer left: $viewerId');
}),
);
_subscriptions.add(
Upscope.instance.onViewerCountChanged.listen((count) {
print('Viewers: $count');
}),
);
_subscriptions.add(
Upscope.instance.remoteControlState.listen((state) {
print('Remote control: ${state.name}');
}),
);
_subscriptions.add(
Upscope.instance.fullDeviceSharingState.listen((state) {
print('Full device sharing: ${state.name}');
}),
);
_subscriptions.add(
Upscope.instance.onFullDeviceRequest.listen((request) {
print('Full device request from ${request.agentName ?? "agent"}');
// Only fires when the configuration sets customFullDeviceRequestUI:
// true (otherwise the SDK proceeds directly to the system prompt).
// accept: true proceeds to the system permission prompt; false declines
Upscope.instance
.respondToFullDeviceRequest(request.requestId, accept: true);
}),
);
_subscriptions.add(
Upscope.instance.onControlRequest.listen((request) {
print('Control request from ${request.agentName ?? "agent"}');
// Only fires when the configuration sets customControlRequestUI: true
// (replacing the native control request prompt).
// accept: true grants remote control; false declines
Upscope.instance
.respondToControlRequest(request.requestId, accept: true);
}),
);
_subscriptions.add(
Upscope.instance.onSessionRequest.listen((request) {
print('Session request from ${request.agentName ?? "agent"}');
// Only fires when the configuration sets customSessionRequestUI: true
// (replacing the native authorization dialog) and authorization is
// required.
// accept: true starts the session; false declines
Upscope.instance
.respondToSessionRequest(request.requestId, accept: true);
}),
);
}
@override
void dispose() {
for (final sub in _subscriptions) {
sub.cancel();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}
Event Reference
| Stream | Type | Description |
|---|---|---|
connectionState | ConnectionState | Connection state changed. |
onSessionStarted | String? | A screen sharing session has started. Emits the agent's name, if available. |
onSessionEnded | SessionEndReason | A session has ended. Reason indicates why (userStopped, agentStopped, timeout, or error). |
onCustomMessageReceived | CustomMessage | A custom message was received from a viewer. Includes message and viewerId. |
onError | UpscopeError | An SDK error occurred. Includes code and message. |
onViewerJoined | Viewer | An agent started viewing the session. The Viewer includes id, name, and screen metrics. |
onViewerLeft | String | An agent stopped viewing the session. Emits the viewer ID. |
onViewerCountChanged | int | The total number of active viewers changed. |
remoteControlState | RemoteControlState | Emits when whether an agent has remote control of the device changes (ability to tap and scroll). Enum values: inactive, pendingRequest, active. Independent of the session being active. |
fullDeviceSharingState | FullDeviceSharingState | Emits when whether full-device (entire screen) sharing is running changes, as opposed to default in-app screen sharing. Enum values: inactive, pendingRequest, active. |
onFullDeviceRequest | FullDeviceRequest | Fires when an agent requests full-device sharing, before the system permission prompt. Only fires when customFullDeviceRequestUI: true is set in the configuration — without the flag, the SDK proceeds directly to the system prompt. Emits a FullDeviceRequest with requestId and agentName. Respond with Upscope.instance.respondToFullDeviceRequest(request.requestId, accept: ...) — true allows (proceeds to the system prompt), false declines (stays in in-app mode). Without a listener that responds, full-device requests stall. |
onControlRequest | ControlRequest | Fires when an agent requests remote control of the device. Only fires when customControlRequestUI: true is set in the configuration and requireControlRequest is enabled (note: requireControlRequest defaults to false, so control is otherwise granted without a request); the native control request prompt is not shown. Emits a ControlRequest with requestId and agentName. Respond with Upscope.instance.respondToControlRequest(request.requestId, accept: ...) — true grants control, false declines. Without a listener that responds, control requests stall. |
onSessionRequest | SessionRequest | Fires when an agent requests to start a cobrowsing session. Only fires when customSessionRequestUI: true is set in the configuration and requireAuthorizationForSession is enabled; the native authorization dialog is not shown. Emits a SessionRequest with requestId and agentName. Respond with Upscope.instance.respondToSessionRequest(request.requestId, accept: ...) — true starts the session, false declines. Without a listener that responds, session requests stall and the session never starts. |
Using StreamBuilder
For reactive UI updates, use StreamBuilder instead of manual subscriptions:
StreamBuilder<ConnectionState>(
stream: Upscope.instance.connectionState,
builder: (context, snapshot) {
if (!snapshot.hasData) return const SizedBox.shrink();
return Text('Status: ${snapshot.data!.name}');
},
)
