Switch to new event system (#9)

* `SignalEvents` and `synchronized` mode for `EventsListenable`

* cascade syntax

* clean up

* `RoomEvents`

* `ParticipantEvents`

* all events implemented

* make it compile with M1 macs

* dispose logic

* cleaner connect logic

* ask to publish

* fix initial EngineTrackAddedEvent glitch

* fix unpublishTrack bug

* clean up

* better events docs

* organize event types

* clean up

* cleaner wait logic

* wait for event instead of using Completer

* notifyListeners
This commit is contained in:
Hiroshi Horie
2021-09-24 23:37:26 +09:00
committed by GitHub
parent f4bd82a919
commit 6445b8d2a8
36 changed files with 1270 additions and 948 deletions
+7 -3
View File
@@ -62,6 +62,9 @@ class _ConnectPageState extends State<ConnectPage> {
_busy = true;
});
// Save for next time
await _writePrefs();
print('Connecting with url: ${_uriCtrl.text}, token: ${_tokenCtrl.text}...');
final room = await LiveKitClient.connect(
@@ -74,9 +77,6 @@ class _ConnectPageState extends State<ConnectPage> {
),
);
// Save for next time
await _writePrefs();
await Navigator.push<void>(
ctx,
MaterialPageRoute(builder: (_) => RoomPage(room)),
@@ -122,10 +122,14 @@ class _ConnectPageState extends State<ConnectPage> {
mainAxisSize: MainAxisSize.min,
children: [
TextField(
enableSuggestions: false,
autocorrect: false,
controller: _uriCtrl,
decoration: const InputDecoration(labelText: 'URL'),
),
TextField(
enableSuggestions: false,
autocorrect: false,
controller: _tokenCtrl,
decoration: const InputDecoration(labelText: 'Token'),
),
+64 -57
View File
@@ -2,12 +2,12 @@ import 'dart:convert';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:livekit_client/livekit_client.dart';
import 'package:provider/provider.dart';
import '../exts.dart';
import '../widgets/controls.dart';
import '../widgets/participant.dart';
import '../exts.dart';
class RoomPage extends StatefulWidget {
//
@@ -22,29 +22,51 @@ class RoomPage extends StatefulWidget {
State<StatefulWidget> createState() => _RoomPageState();
}
class _RoomPageState extends State<RoomPage> with RoomDelegate {
class _RoomPageState extends State<RoomPage> {
//
List<Participant> participants = [];
late final _listener = EventsListener<LiveKitEvent>(widget.room.events);
@override
void initState() {
super.initState();
widget.room.delegate = this;
widget.room.addListener(_onChange);
_onConnected();
widget.room.addListener(_onRoomDidUpdate);
_setUpListeners();
_sortParticipants();
WidgetsBinding.instance?.addPostFrameCallback((_) => _askPublish());
}
@override
void dispose() {
widget.room.delegate = null;
widget.room.removeListener(_onChange);
// always dispose listener
(() async {
widget.room.removeListener(_onRoomDidUpdate);
await _listener.dispose();
await widget.room.dispose();
})();
super.dispose();
}
void _onConnected() async {
void _setUpListeners() => _listener
..on<RoomDisconnectedEvent>((_) => Navigator.pop(context))
..on<DataReceivedEvent>((event) {
String decoded = 'Failed to decode';
try {
decoded = utf8.decode(event.data);
} catch (_) {
print('Failed to decode: $_');
}
context.showDataReceivedDialog(decoded);
});
void _askPublish() async {
final result = await context.showPublishDialog();
if (result != true) return;
// video will fail when running in ios simulator
try {
final localVideo = await LocalVideoTrack.createCameraTrack(); // Defaults to camera
// Create video track
final localVideo = await LocalVideoTrack.createCameraTrack();
// Try to publish the video
await widget.room.localParticipant.publishVideoTrack(
localVideo,
// options: TrackPublishOptions(
@@ -52,20 +74,22 @@ class _RoomPageState extends State<RoomPage> with RoomDelegate {
// videoEncoding: VideoParameters.presetQVGA169.encoding,
// ),
);
} catch (e) {
print('could not publish video: $e');
// Create mic track
final localAudio = await LocalAudioTrack.create();
// // Try to publish audio
await widget.room.localParticipant.publishAudioTrack(localAudio);
} catch (error) {
print('could not publish video: $error');
await context.showErrorDialog(error);
}
final localAudio = await LocalAudioTrack.create();
await widget.room.localParticipant.publishAudioTrack(localAudio);
sortParticipants();
}
void _onChange() {
sortParticipants();
void _onRoomDidUpdate() {
_sortParticipants();
}
void sortParticipants() {
void _sortParticipants() {
List<Participant> participants = [];
participants.addAll(widget.room.participants.values);
// sort speakers for the grid
@@ -106,48 +130,31 @@ class _RoomPageState extends State<RoomPage> with RoomDelegate {
});
}
@override
void onDataReceived(RemoteParticipant participant, List<int> data) async {
await context.showDataReceivedDialog(utf8.decode(data));
}
@override
void onDisconnected() {
print('disconnected: $context');
Navigator.pop(context);
}
@override
Widget build(BuildContext context) => Scaffold(
// with a provider, any child/descendent widget can be updated if they
// are a Consumer of Room.
body: ChangeNotifierProvider.value(
value: widget.room,
child: Column(
children: [
Expanded(
child: participants.isNotEmpty
? ParticipantWidget(participants.first)
: Container()),
SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: math.max(0, participants.length - 1),
itemBuilder: (BuildContext context, int index) => Container(
width: 100,
height: 100,
padding: const EdgeInsets.all(2),
child: ParticipantWidget(participants[index + 1], quality: VideoQuality.LOW),
),
body: Column(
children: [
Expanded(
child:
participants.isNotEmpty ? ParticipantWidget(participants.first) : Container()),
SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: math.max(0, participants.length - 1),
itemBuilder: (BuildContext context, int index) => Container(
width: 100,
height: 100,
padding: const EdgeInsets.all(2),
child: ParticipantWidget(participants[index + 1], quality: VideoQuality.LOW),
),
),
SafeArea(
top: false,
child: ControlsWidget(widget.room),
),
],
),
),
SafeArea(
top: false,
child: ControlsWidget(widget.room),
),
],
),
);
}