Skip to content

Commit

Permalink
feat(lib): events are now mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibaultBee committed Oct 1, 2024
1 parent 406e1c8 commit c5f934c
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 126 deletions.
62 changes: 35 additions & 27 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class LiveViewPage extends StatefulWidget {
}

class _LiveViewPageState extends State<LiveViewPage>
with WidgetsBindingObserver {
with WidgetsBindingObserver, ApiVideoLiveStreamEventsListener {
final ButtonStyle buttonStyle =
ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20));
Params params = Params();
Expand All @@ -67,6 +67,7 @@ class _LiveViewPageState extends State<LiveViewPage>
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_controller.removeEventsListener(this);
_controller.dispose();
super.dispose();
}
Expand All @@ -85,36 +86,43 @@ class _LiveViewPageState extends State<LiveViewPage>
}
}

void onConnectionSuccess() {
print('Connection succeeded');
}

void onConnectionFailed(String reason) {
print('Connection failed: $reason');
_showDialog(context, 'Connection failed', '$reason');
if (mounted) {
setIsStreaming(false);
}
}

void onDisconnection() {
showInSnackBar('Disconnected');
if (mounted) {
setIsStreaming(false);
}
}

void onError(Exception error) {
// Get error such as missing permission,...
if (error is PlatformException) {
_showDialog(
context, "Error", error.message ?? "An unknown error occurred");
} else {
_showDialog(context, "Error", "$error");
}
if (mounted) {
setIsStreaming(false);
}
}

ApiVideoLiveStreamController createLiveStreamController() {
final controller = ApiVideoLiveStreamController(
initialAudioConfig: params.audioConfig,
initialVideoConfig: params.videoConfig);

controller.addCallbacksListener(onConnectionSuccess: () {
print('Connection succeeded');
}, onConnectionFailed: (error) {
print('Connection failed: $error');
_showDialog(context, 'Connection failed', '$error');
if (mounted) {
setIsStreaming(false);
}
}, onDisconnection: () {
showInSnackBar('Disconnected');
if (mounted) {
setIsStreaming(false);
}
}, onError: (error) {
// Get error such as missing permission,...
if (error is PlatformException) {
_showDialog(
context, "Error", error.message ?? "An unknown error occurred");
} else {
_showDialog(context, "Error", "$error");
}
if (mounted) {
setIsStreaming(false);
}
});
controller.addEventsListener(this);
return controller;
}

Expand Down
1 change: 1 addition & 0 deletions lib/apivideo_live_stream.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export 'src/camera_preview.dart';
export 'src/controller.dart';
export 'src/listeners.dart' show ApiVideoLiveStreamEventsListener;
export 'src/platform/generated/live_stream_api.g.dart'
show CameraPosition, Channel;
export 'src/platform/mobile_platform.dart';
Expand Down
42 changes: 19 additions & 23 deletions lib/src/camera_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,8 @@ class ApiVideoCameraPreview extends StatefulWidget {
State<ApiVideoCameraPreview> createState() => _ApiVideoCameraPreviewState();
}

class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview> {
_ApiVideoCameraPreviewState() {
_widgetListener = ApiVideoLiveStreamWidgetListener(onTextureReady: () {
final int newTextureId = widget.controller.textureId;
if (newTextureId != _textureId) {
setState(() {
_textureId = newTextureId;
});
}
});

_eventsListener =
ApiVideoLiveStreamEventsListener(onVideoSizeChanged: (size) {
_updateAspectRatio(size);
});
}

late ApiVideoLiveStreamWidgetListener _widgetListener;
late ApiVideoLiveStreamEventsListener _eventsListener;
class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview>
with ApiVideoLiveStreamEventsListener, ApiVideoLiveStreamWidgetListener {
late int _textureId;

double _aspectRatio = 1.77;
Expand All @@ -56,8 +39,8 @@ class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview> {
void initState() {
super.initState();
_textureId = widget.controller.textureId;
widget.controller.addWidgetListener(_widgetListener);
widget.controller.addEventsListener(_eventsListener);
widget.controller.addWidgetListener(this);
widget.controller.addEventsListener(this);
if (widget.controller.isInitialized) {
widget.controller.videoSize.then((size) {
if (size != null) {
Expand All @@ -70,11 +53,24 @@ class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview> {
@override
void dispose() {
widget.controller.stopPreview();
widget.controller.removeWidgetListener(_widgetListener);
widget.controller.removeEventsListener(_eventsListener);
widget.controller.removeWidgetListener(this);
widget.controller.removeEventsListener(this);
super.dispose();
}

void onTextureReady() {
final int newTextureId = widget.controller.textureId;
if (newTextureId != _textureId) {
setState(() {
_textureId = newTextureId;
});
}
}

void onVideoSizeChanged(Size size) {
_updateAspectRatio(size);
}

@override
Widget build(BuildContext context) {
return _textureId == ApiVideoLiveStreamController.kUninitializedTextureId
Expand Down
103 changes: 52 additions & 51 deletions lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,9 @@ class ApiVideoLiveStreamController {
bool get isInitialized => _isInitialized;

/// Events listeners
List<ApiVideoLiveStreamEventsListener> _eventsListeners = [];
_EventListenersManager _eventsListenersManager = _EventListenersManager();
List<ApiVideoLiveStreamWidgetListener> _widgetListeners = [];

late ApiVideoLiveStreamEventsListener _platformListener =
ApiVideoLiveStreamEventsListener(onConnectionSuccess: () {
_eventsListeners.forEach((listener) {
if (listener.onConnectionSuccess != null) {
listener.onConnectionSuccess!();
}
});
}, onConnectionFailed: (error) {
_eventsListeners.forEach((listener) {
if (listener.onConnectionFailed != null) {
listener.onConnectionFailed!(error);
}
});
}, onDisconnection: () {
_eventsListeners.forEach((listener) {
if (listener.onDisconnection != null) {
listener.onDisconnection!();
}
});
}, onError: (error) {
_eventsListeners.forEach((listener) {
if (listener.onError != null) {
listener.onError!(error);
}
});
});

/// Creates a new [ApiVideoLiveStreamController] instance.
ApiVideoLiveStreamController(
{required AudioConfig initialAudioConfig,
Expand All @@ -71,13 +44,11 @@ class ApiVideoLiveStreamController {

/// Creates a new live stream instance with initial audio and video configurations.
Future<void> initialize() async {
_platform.setListener(_platformListener);
_platform.setListener(_eventsListenersManager);
_textureId = await _platform.initialize() ?? kUninitializedTextureId;

for (var listener in [..._widgetListeners]) {
if (listener.onTextureReady != null) {
listener.onTextureReady!();
}
listener.onTextureReady();
}

await setCameraPosition(_initialCameraPosition);
Expand All @@ -92,7 +63,7 @@ class ApiVideoLiveStreamController {
/// Disposes the live stream instance.
Future<void> dispose() async {
_platform.setListener(null);
_eventsListeners.clear();
_eventsListenersManager.dispose();
_widgetListeners.clear();
await _platform.dispose();
return;
Expand Down Expand Up @@ -197,30 +168,14 @@ class ApiVideoLiveStreamController {
return Texture(textureId: textureId);
}

/// Adds a new events listener from the direct callbacks.
/// Returns the listener instance. You can remove it later with [removeEventsListener].
ApiVideoLiveStreamEventsListener addCallbacksListener(
{VoidCallback? onConnectionSuccess,
Function(String)? onConnectionFailed,
VoidCallback? onDisconnection,
Function(Exception)? onError}) {
final listener = ApiVideoLiveStreamEventsListener(
onConnectionSuccess: onConnectionSuccess,
onConnectionFailed: onConnectionFailed,
onDisconnection: onDisconnection,
onError: onError);
_eventsListeners.add(listener);
return listener;
}

/// Adds a new widget listener from the events listener.
void addEventsListener(ApiVideoLiveStreamEventsListener listener) {
_eventsListeners.add(listener);
_eventsListenersManager.add(listener);
}

/// Removes an events listener.
void removeEventsListener(ApiVideoLiveStreamEventsListener listener) {
_eventsListeners.remove(listener);
_eventsListenersManager.remove(listener);
}

/// This is exposed for internal use only. Do not use it.
Expand All @@ -235,3 +190,49 @@ class ApiVideoLiveStreamController {
_widgetListeners.remove(listener);
}
}

class _EventListenersManager with ApiVideoLiveStreamEventsListener {
final List<ApiVideoLiveStreamEventsListener> listeners = [];

void onConnectionSuccess() {
for (var listener in listeners) {
listener.onConnectionSuccess();
}
}

void onConnectionFailed(String reason) {
for (var listener in listeners) {
listener.onConnectionFailed(reason);
}
}

void onDisconnection() {
for (var listener in listeners) {
listener.onDisconnection();
}
}

void onError(Exception error) {
for (var listener in listeners) {
listener.onError(error);
}
}

void onVideoSizeChanged(Size size) {
for (var listener in listeners) {
listener.onVideoSizeChanged(size);
}
}

void add(ApiVideoLiveStreamEventsListener listener) {
listeners.add(listener);
}

void remove(ApiVideoLiveStreamEventsListener listener) {
listeners.remove(listener);
}

void dispose() {
listeners.clear();
}
}
25 changes: 8 additions & 17 deletions lib/src/listeners.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
import 'dart:ui';

class ApiVideoLiveStreamEventsListener {
mixin ApiVideoLiveStreamEventsListener {
/// Gets notified when the connection is successful
final VoidCallback? onConnectionSuccess;
void onConnectionSuccess() {}

/// Gets notified when the connection failed
final Function(String)? onConnectionFailed;
void onConnectionFailed(String reason) {}

/// Gets notified when the device has been disconnected
final VoidCallback? onDisconnection;
void onDisconnection() {}

/// Gets notified when the video size has changed. Mostly designed to update Widget aspect ratio.
final Function(Size)? onVideoSizeChanged;
void onVideoSizeChanged(Size size) {}

/// Gets notified when an error occurs
final Function(Exception)? onError;

ApiVideoLiveStreamEventsListener(
{this.onConnectionSuccess,
this.onConnectionFailed,
this.onDisconnection,
this.onVideoSizeChanged,
this.onError});
void onError(Exception error) {}
}

class ApiVideoLiveStreamWidgetListener {
final VoidCallback? onTextureReady;

ApiVideoLiveStreamWidgetListener({this.onTextureReady});
mixin ApiVideoLiveStreamWidgetListener {
void onTextureReady() {}
}
11 changes: 5 additions & 6 deletions lib/src/platform/mobile_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,25 @@ class ApiVideoMobileLiveStreamPlatform extends ApiVideoLiveStreamPlatform

@override
void onConnectionFailed(String message) {
_eventsListener?.onConnectionFailed?.call(message);
_eventsListener?.onConnectionFailed(message);
}

@override
void onIsConnectedChanged(bool isConnected) {
if (isConnected) {
_eventsListener?.onConnectionSuccess?.call();
_eventsListener?.onConnectionSuccess();
} else {
_eventsListener?.onDisconnection?.call();
_eventsListener?.onDisconnection();
}
}

@override
void onVideoSizeChanged(NativeResolution resolution) {
_eventsListener?.onVideoSizeChanged?.call(resolution.toSize());
_eventsListener?.onVideoSizeChanged(resolution.toSize());
}

@override
void onError(String code, String message) {
_eventsListener?.onError
?.call(PlatformException(code: code, message: message));
_eventsListener?.onError(PlatformException(code: code, message: message));
}
}
4 changes: 3 additions & 1 deletion lib/src/platform/platform_interface.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:apivideo_live_stream/apivideo_live_stream.dart';
import 'package:apivideo_live_stream/src/listeners.dart';
import 'package:apivideo_live_stream/src/platform/generated/live_stream_api.g.dart';
import 'package:apivideo_live_stream/src/platform/mobile_platform.dart';
import 'package:apivideo_live_stream/src/types/types.dart';
import 'package:flutter/widgets.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

Expand Down
1 change: 0 additions & 1 deletion test/controller_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:async';

import 'package:apivideo_live_stream/apivideo_live_stream.dart';
import 'package:apivideo_live_stream/src/listeners.dart';
import 'package:apivideo_live_stream/src/platform/platform_interface.dart';
import 'package:flutter_test/flutter_test.dart';

Expand Down

0 comments on commit c5f934c

Please sign in to comment.