Skip to content

Commit c5f934c

Browse files
committed
feat(lib): events are now mixin
1 parent 406e1c8 commit c5f934c

File tree

8 files changed

+123
-126
lines changed

8 files changed

+123
-126
lines changed

example/lib/main.dart

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class LiveViewPage extends StatefulWidget {
4545
}
4646

4747
class _LiveViewPageState extends State<LiveViewPage>
48-
with WidgetsBindingObserver {
48+
with WidgetsBindingObserver, ApiVideoLiveStreamEventsListener {
4949
final ButtonStyle buttonStyle =
5050
ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20));
5151
Params params = Params();
@@ -67,6 +67,7 @@ class _LiveViewPageState extends State<LiveViewPage>
6767
@override
6868
void dispose() {
6969
WidgetsBinding.instance.removeObserver(this);
70+
_controller.removeEventsListener(this);
7071
_controller.dispose();
7172
super.dispose();
7273
}
@@ -85,36 +86,43 @@ class _LiveViewPageState extends State<LiveViewPage>
8586
}
8687
}
8788

89+
void onConnectionSuccess() {
90+
print('Connection succeeded');
91+
}
92+
93+
void onConnectionFailed(String reason) {
94+
print('Connection failed: $reason');
95+
_showDialog(context, 'Connection failed', '$reason');
96+
if (mounted) {
97+
setIsStreaming(false);
98+
}
99+
}
100+
101+
void onDisconnection() {
102+
showInSnackBar('Disconnected');
103+
if (mounted) {
104+
setIsStreaming(false);
105+
}
106+
}
107+
108+
void onError(Exception error) {
109+
// Get error such as missing permission,...
110+
if (error is PlatformException) {
111+
_showDialog(
112+
context, "Error", error.message ?? "An unknown error occurred");
113+
} else {
114+
_showDialog(context, "Error", "$error");
115+
}
116+
if (mounted) {
117+
setIsStreaming(false);
118+
}
119+
}
120+
88121
ApiVideoLiveStreamController createLiveStreamController() {
89122
final controller = ApiVideoLiveStreamController(
90123
initialAudioConfig: params.audioConfig,
91124
initialVideoConfig: params.videoConfig);
92-
93-
controller.addCallbacksListener(onConnectionSuccess: () {
94-
print('Connection succeeded');
95-
}, onConnectionFailed: (error) {
96-
print('Connection failed: $error');
97-
_showDialog(context, 'Connection failed', '$error');
98-
if (mounted) {
99-
setIsStreaming(false);
100-
}
101-
}, onDisconnection: () {
102-
showInSnackBar('Disconnected');
103-
if (mounted) {
104-
setIsStreaming(false);
105-
}
106-
}, onError: (error) {
107-
// Get error such as missing permission,...
108-
if (error is PlatformException) {
109-
_showDialog(
110-
context, "Error", error.message ?? "An unknown error occurred");
111-
} else {
112-
_showDialog(context, "Error", "$error");
113-
}
114-
if (mounted) {
115-
setIsStreaming(false);
116-
}
117-
});
125+
controller.addEventsListener(this);
118126
return controller;
119127
}
120128

lib/apivideo_live_stream.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export 'src/camera_preview.dart';
22
export 'src/controller.dart';
3+
export 'src/listeners.dart' show ApiVideoLiveStreamEventsListener;
34
export 'src/platform/generated/live_stream_api.g.dart'
45
show CameraPosition, Channel;
56
export 'src/platform/mobile_platform.dart';

lib/src/camera_preview.dart

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,8 @@ class ApiVideoCameraPreview extends StatefulWidget {
2828
State<ApiVideoCameraPreview> createState() => _ApiVideoCameraPreviewState();
2929
}
3030

31-
class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview> {
32-
_ApiVideoCameraPreviewState() {
33-
_widgetListener = ApiVideoLiveStreamWidgetListener(onTextureReady: () {
34-
final int newTextureId = widget.controller.textureId;
35-
if (newTextureId != _textureId) {
36-
setState(() {
37-
_textureId = newTextureId;
38-
});
39-
}
40-
});
41-
42-
_eventsListener =
43-
ApiVideoLiveStreamEventsListener(onVideoSizeChanged: (size) {
44-
_updateAspectRatio(size);
45-
});
46-
}
47-
48-
late ApiVideoLiveStreamWidgetListener _widgetListener;
49-
late ApiVideoLiveStreamEventsListener _eventsListener;
31+
class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview>
32+
with ApiVideoLiveStreamEventsListener, ApiVideoLiveStreamWidgetListener {
5033
late int _textureId;
5134

5235
double _aspectRatio = 1.77;
@@ -56,8 +39,8 @@ class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview> {
5639
void initState() {
5740
super.initState();
5841
_textureId = widget.controller.textureId;
59-
widget.controller.addWidgetListener(_widgetListener);
60-
widget.controller.addEventsListener(_eventsListener);
42+
widget.controller.addWidgetListener(this);
43+
widget.controller.addEventsListener(this);
6144
if (widget.controller.isInitialized) {
6245
widget.controller.videoSize.then((size) {
6346
if (size != null) {
@@ -70,11 +53,24 @@ class _ApiVideoCameraPreviewState extends State<ApiVideoCameraPreview> {
7053
@override
7154
void dispose() {
7255
widget.controller.stopPreview();
73-
widget.controller.removeWidgetListener(_widgetListener);
74-
widget.controller.removeEventsListener(_eventsListener);
56+
widget.controller.removeWidgetListener(this);
57+
widget.controller.removeEventsListener(this);
7558
super.dispose();
7659
}
7760

61+
void onTextureReady() {
62+
final int newTextureId = widget.controller.textureId;
63+
if (newTextureId != _textureId) {
64+
setState(() {
65+
_textureId = newTextureId;
66+
});
67+
}
68+
}
69+
70+
void onVideoSizeChanged(Size size) {
71+
_updateAspectRatio(size);
72+
}
73+
7874
@override
7975
Widget build(BuildContext context) {
8076
return _textureId == ApiVideoLiveStreamController.kUninitializedTextureId

lib/src/controller.dart

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -30,36 +30,9 @@ class ApiVideoLiveStreamController {
3030
bool get isInitialized => _isInitialized;
3131

3232
/// Events listeners
33-
List<ApiVideoLiveStreamEventsListener> _eventsListeners = [];
33+
_EventListenersManager _eventsListenersManager = _EventListenersManager();
3434
List<ApiVideoLiveStreamWidgetListener> _widgetListeners = [];
3535

36-
late ApiVideoLiveStreamEventsListener _platformListener =
37-
ApiVideoLiveStreamEventsListener(onConnectionSuccess: () {
38-
_eventsListeners.forEach((listener) {
39-
if (listener.onConnectionSuccess != null) {
40-
listener.onConnectionSuccess!();
41-
}
42-
});
43-
}, onConnectionFailed: (error) {
44-
_eventsListeners.forEach((listener) {
45-
if (listener.onConnectionFailed != null) {
46-
listener.onConnectionFailed!(error);
47-
}
48-
});
49-
}, onDisconnection: () {
50-
_eventsListeners.forEach((listener) {
51-
if (listener.onDisconnection != null) {
52-
listener.onDisconnection!();
53-
}
54-
});
55-
}, onError: (error) {
56-
_eventsListeners.forEach((listener) {
57-
if (listener.onError != null) {
58-
listener.onError!(error);
59-
}
60-
});
61-
});
62-
6336
/// Creates a new [ApiVideoLiveStreamController] instance.
6437
ApiVideoLiveStreamController(
6538
{required AudioConfig initialAudioConfig,
@@ -71,13 +44,11 @@ class ApiVideoLiveStreamController {
7144

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

7750
for (var listener in [..._widgetListeners]) {
78-
if (listener.onTextureReady != null) {
79-
listener.onTextureReady!();
80-
}
51+
listener.onTextureReady();
8152
}
8253

8354
await setCameraPosition(_initialCameraPosition);
@@ -92,7 +63,7 @@ class ApiVideoLiveStreamController {
9263
/// Disposes the live stream instance.
9364
Future<void> dispose() async {
9465
_platform.setListener(null);
95-
_eventsListeners.clear();
66+
_eventsListenersManager.dispose();
9667
_widgetListeners.clear();
9768
await _platform.dispose();
9869
return;
@@ -197,30 +168,14 @@ class ApiVideoLiveStreamController {
197168
return Texture(textureId: textureId);
198169
}
199170

200-
/// Adds a new events listener from the direct callbacks.
201-
/// Returns the listener instance. You can remove it later with [removeEventsListener].
202-
ApiVideoLiveStreamEventsListener addCallbacksListener(
203-
{VoidCallback? onConnectionSuccess,
204-
Function(String)? onConnectionFailed,
205-
VoidCallback? onDisconnection,
206-
Function(Exception)? onError}) {
207-
final listener = ApiVideoLiveStreamEventsListener(
208-
onConnectionSuccess: onConnectionSuccess,
209-
onConnectionFailed: onConnectionFailed,
210-
onDisconnection: onDisconnection,
211-
onError: onError);
212-
_eventsListeners.add(listener);
213-
return listener;
214-
}
215-
216171
/// Adds a new widget listener from the events listener.
217172
void addEventsListener(ApiVideoLiveStreamEventsListener listener) {
218-
_eventsListeners.add(listener);
173+
_eventsListenersManager.add(listener);
219174
}
220175

221176
/// Removes an events listener.
222177
void removeEventsListener(ApiVideoLiveStreamEventsListener listener) {
223-
_eventsListeners.remove(listener);
178+
_eventsListenersManager.remove(listener);
224179
}
225180

226181
/// This is exposed for internal use only. Do not use it.
@@ -235,3 +190,49 @@ class ApiVideoLiveStreamController {
235190
_widgetListeners.remove(listener);
236191
}
237192
}
193+
194+
class _EventListenersManager with ApiVideoLiveStreamEventsListener {
195+
final List<ApiVideoLiveStreamEventsListener> listeners = [];
196+
197+
void onConnectionSuccess() {
198+
for (var listener in listeners) {
199+
listener.onConnectionSuccess();
200+
}
201+
}
202+
203+
void onConnectionFailed(String reason) {
204+
for (var listener in listeners) {
205+
listener.onConnectionFailed(reason);
206+
}
207+
}
208+
209+
void onDisconnection() {
210+
for (var listener in listeners) {
211+
listener.onDisconnection();
212+
}
213+
}
214+
215+
void onError(Exception error) {
216+
for (var listener in listeners) {
217+
listener.onError(error);
218+
}
219+
}
220+
221+
void onVideoSizeChanged(Size size) {
222+
for (var listener in listeners) {
223+
listener.onVideoSizeChanged(size);
224+
}
225+
}
226+
227+
void add(ApiVideoLiveStreamEventsListener listener) {
228+
listeners.add(listener);
229+
}
230+
231+
void remove(ApiVideoLiveStreamEventsListener listener) {
232+
listeners.remove(listener);
233+
}
234+
235+
void dispose() {
236+
listeners.clear();
237+
}
238+
}

lib/src/listeners.dart

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
11
import 'dart:ui';
22

3-
class ApiVideoLiveStreamEventsListener {
3+
mixin ApiVideoLiveStreamEventsListener {
44
/// Gets notified when the connection is successful
5-
final VoidCallback? onConnectionSuccess;
5+
void onConnectionSuccess() {}
66

77
/// Gets notified when the connection failed
8-
final Function(String)? onConnectionFailed;
8+
void onConnectionFailed(String reason) {}
99

1010
/// Gets notified when the device has been disconnected
11-
final VoidCallback? onDisconnection;
11+
void onDisconnection() {}
1212

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

1616
/// Gets notified when an error occurs
17-
final Function(Exception)? onError;
18-
19-
ApiVideoLiveStreamEventsListener(
20-
{this.onConnectionSuccess,
21-
this.onConnectionFailed,
22-
this.onDisconnection,
23-
this.onVideoSizeChanged,
24-
this.onError});
17+
void onError(Exception error) {}
2518
}
2619

27-
class ApiVideoLiveStreamWidgetListener {
28-
final VoidCallback? onTextureReady;
29-
30-
ApiVideoLiveStreamWidgetListener({this.onTextureReady});
20+
mixin ApiVideoLiveStreamWidgetListener {
21+
void onTextureReady() {}
3122
}

lib/src/platform/mobile_platform.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,26 +112,25 @@ class ApiVideoMobileLiveStreamPlatform extends ApiVideoLiveStreamPlatform
112112

113113
@override
114114
void onConnectionFailed(String message) {
115-
_eventsListener?.onConnectionFailed?.call(message);
115+
_eventsListener?.onConnectionFailed(message);
116116
}
117117

118118
@override
119119
void onIsConnectedChanged(bool isConnected) {
120120
if (isConnected) {
121-
_eventsListener?.onConnectionSuccess?.call();
121+
_eventsListener?.onConnectionSuccess();
122122
} else {
123-
_eventsListener?.onDisconnection?.call();
123+
_eventsListener?.onDisconnection();
124124
}
125125
}
126126

127127
@override
128128
void onVideoSizeChanged(NativeResolution resolution) {
129-
_eventsListener?.onVideoSizeChanged?.call(resolution.toSize());
129+
_eventsListener?.onVideoSizeChanged(resolution.toSize());
130130
}
131131

132132
@override
133133
void onError(String code, String message) {
134-
_eventsListener?.onError
135-
?.call(PlatformException(code: code, message: message));
134+
_eventsListener?.onError(PlatformException(code: code, message: message));
136135
}
137136
}

lib/src/platform/platform_interface.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import 'package:apivideo_live_stream/apivideo_live_stream.dart';
21
import 'package:apivideo_live_stream/src/listeners.dart';
2+
import 'package:apivideo_live_stream/src/platform/generated/live_stream_api.g.dart';
3+
import 'package:apivideo_live_stream/src/platform/mobile_platform.dart';
4+
import 'package:apivideo_live_stream/src/types/types.dart';
35
import 'package:flutter/widgets.dart';
46
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
57

test/controller_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:async';
22

33
import 'package:apivideo_live_stream/apivideo_live_stream.dart';
4-
import 'package:apivideo_live_stream/src/listeners.dart';
54
import 'package:apivideo_live_stream/src/platform/platform_interface.dart';
65
import 'package:flutter_test/flutter_test.dart';
76

0 commit comments

Comments
 (0)