diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index b028ee8..90b4f0b 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -16,9 +16,9 @@ name: Build
on:
push:
- branches: [ main ]
+ branches: [main]
pull_request:
- branches: [ main ]
+ branches: [main]
jobs:
dart-format-and-analyze-check:
@@ -29,15 +29,15 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '17.x'
+ java-version: "17.x"
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Dart Format Check
- run: dart format lib/ test/ --set-exit-if-changed
+ run: dart format lib/ test/ --set-exit-if-changed -l 120
- name: Import Sorter Check
run: dart run import_sorter:main --no-comments --exit-if-changed
- name: Dart Analyze Check
@@ -51,11 +51,11 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '17.x'
+ java-version: "17.x"
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Build for Android
@@ -70,7 +70,7 @@ jobs:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Build for iOS
@@ -85,7 +85,7 @@ jobs:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v1
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Build for Windows
@@ -100,7 +100,7 @@ jobs:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v1
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Build for macOS
@@ -115,11 +115,11 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '12.x'
+ java-version: "12.x"
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Run apt update
@@ -138,11 +138,11 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '12.x'
+ java-version: "12.x"
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
- channel: 'stable'
+ channel: "stable"
- name: Install project dependencies
run: flutter pub get
- name: Build for Web
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index 0c95301..2373429 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -17,7 +17,7 @@ name: Publish to pub.dev
on:
push:
tags:
- - 'v[0-9]+.[0-9]+.[0-9]+*'
+ - "v[0-9]+.[0-9]+.[0-9]+*"
jobs:
publish:
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 1923cb6..f9517a1 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,18 +1,24 @@
-include: package:lints/recommended.yaml
+include: package:flutter_lints/flutter.yaml
analyzer:
errors:
constant_identifier_names: ignore
- must_be_immutable: ignore
no_wildcard_variable_uses: ignore
use_super_parameters: ignore
+ avoid_print: ignore
linter:
rules:
- #
- # Additional recommended rules
- #
+ # Preference of the SDK
prefer_single_quotes: true
+ prefer_final_locals: true
unnecessary_brace_in_string_interps: false
+ avoid_print: true
+
+ # Enforce this for correct async logic
unawaited_futures: true
- depend_on_referenced_packages: false
+ discarded_futures: true
+
+formatter:
+ page_width: 120
+ trailing_commas: preserve
diff --git a/dart_dependency_validator.yaml b/dart_dependency_validator.yaml
new file mode 100644
index 0000000..73c22fe
--- /dev/null
+++ b/dart_dependency_validator.yaml
@@ -0,0 +1,8 @@
+# dart_dependency_validator.yaml
+
+# Set true if you allow pinned packages in your project.
+allow_pins: true
+
+# Exclude one or more paths from being scanned. Supports glob syntax.
+exclude:
+ - "./example/**"
diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml
index 822aed2..f9517a1 100644
--- a/example/analysis_options.yaml
+++ b/example/analysis_options.yaml
@@ -1,31 +1,24 @@
-# This file configures the analyzer, which statically analyzes Dart code to
-# check for errors, warnings, and lints.
-#
-# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
-# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
-# invoked from the command line by running `flutter analyze`.
+include: package:flutter_lints/flutter.yaml
-# The following line activates a set of recommended lints for Flutter apps,
-# packages, and plugins designed to encourage good coding practices.
analyzer:
errors:
- must_be_immutable: ignore
-include: package:flutter_lints/flutter.yaml
+ constant_identifier_names: ignore
+ no_wildcard_variable_uses: ignore
+ use_super_parameters: ignore
+ avoid_print: ignore
linter:
- # The lint rules applied to this project can be customized in the
- # section below to disable rules from the `package:flutter_lints/flutter.yaml`
- # included above or to enable additional rules. A list of all available lints
- # and their documentation is published at https://dart.dev/lints.
- #
- # Instead of disabling a lint rule for the entire project in the
- # section below, it can also be suppressed for a single line of code
- # or a specific dart file by using the `// ignore: name_of_lint` and
- # `// ignore_for_file: name_of_lint` syntax on the line or in the file
- # producing the lint.
rules:
- # avoid_print: false # Uncomment to disable the `avoid_print` rule
- # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+ # Preference of the SDK
+ prefer_single_quotes: true
+ prefer_final_locals: true
+ unnecessary_brace_in_string_interps: false
+ avoid_print: true
+
+ # Enforce this for correct async logic
+ unawaited_futures: true
+ discarded_futures: true
-# Additional information about this file can be found at
-# https://dart.dev/guides/language/analysis-options
+formatter:
+ page_width: 120
+ trailing_commas: preserve
diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties
index 7bb2df6..afa1e8e 100644
--- a/example/android/gradle/wrapper/gradle-wrapper.properties
+++ b/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
diff --git a/example/android/settings.gradle b/example/android/settings.gradle
index b9e43bd..72e8d42 100644
--- a/example/android/settings.gradle
+++ b/example/android/settings.gradle
@@ -18,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "8.1.0" apply false
- id "org.jetbrains.kotlin.android" version "1.8.22" apply false
+ id "com.android.application" version "8.7.2" apply false
+ id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}
include ":app"
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index 7c56964..1dc6cf7 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 12.0
+ 13.0
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index 7f735ce..2720e0d 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -455,7 +455,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -584,7 +584,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -635,7 +635,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 46e4108..26f892d 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -115,11 +115,10 @@ class _MyHomePageState extends State {
},
),
builder: (context, roomCtx) {
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
return Scaffold(
appBar: AppBar(
- title: const Text('LiveKit Components',
- style: TextStyle(color: Colors.white)),
+ title: const Text('LiveKit Components', style: TextStyle(color: Colors.white)),
actions: [
/// show clear pin button
if (roomCtx.connected) const ClearPinButton(),
@@ -141,16 +140,13 @@ class _MyHomePageState extends State {
Row(
children: [
/// show chat widget on mobile
- (deviceScreenType == DeviceScreenType.mobile &&
- roomCtx.isChatEnabled)
+ (deviceScreenType == DeviceScreenType.mobile && roomCtx.isChatEnabled)
? Expanded(
child: ChatBuilder(
- builder:
- (context, enabled, chatCtx, messages) {
+ builder: (context, enabled, chatCtx, messages) {
return ChatWidget(
messages: messages,
- onSend: (message) =>
- chatCtx.sendMessage(message),
+ onSend: (message) => chatCtx.sendMessage(message),
onClose: () {
chatCtx.toggleChat(false);
},
@@ -179,37 +175,28 @@ class _MyHomePageState extends State {
showParticipantPlaceholder: true,
/// layout builder
- layoutBuilder:
- roomCtx.pinnedTracks.isNotEmpty
- ? const CarouselLayoutBuilder()
- : const GridLayoutBuilder(),
+ layoutBuilder: roomCtx.pinnedTracks.isNotEmpty
+ ? const CarouselLayoutBuilder()
+ : const GridLayoutBuilder(),
/// participant builder
- participantTrackBuilder:
- (context, identifier) {
+ participantTrackBuilder: (context, identifier) {
// build participant widget for each Track
return Padding(
padding: const EdgeInsets.all(2.0),
child: Stack(
children: [
/// video track widget in the background
- identifier.isAudio &&
- roomCtx
- .enableAudioVisulizer
+ identifier.isAudio && roomCtx.enableAudioVisulizer
? const AudioVisualizerWidget(
- backgroundColor:
- LKColors.lkDarkBlue,
+ backgroundColor: LKColors.lkDarkBlue,
)
: IsSpeakingIndicator(
- builder: (context,
- isSpeaking) {
- return isSpeaking !=
- null
+ builder: (context, isSpeaking) {
+ return isSpeaking != null
? IsSpeakingIndicatorWidget(
- isSpeaking:
- isSpeaking,
- child:
- const VideoTrackWidget(),
+ isSpeaking: isSpeaking,
+ child: const VideoTrackWidget(),
)
: const VideoTrackWidget();
},
@@ -254,19 +241,16 @@ class _MyHomePageState extends State {
),
/// show chat widget on desktop
- (deviceScreenType != DeviceScreenType.mobile &&
- roomCtx.isChatEnabled)
+ (deviceScreenType != DeviceScreenType.mobile && roomCtx.isChatEnabled)
? Expanded(
flex: 2,
child: SizedBox(
width: 400,
child: ChatBuilder(
- builder:
- (context, enabled, chatCtx, messages) {
+ builder: (context, enabled, chatCtx, messages) {
return ChatWidget(
messages: messages,
- onSend: (message) =>
- chatCtx.sendMessage(message),
+ onSend: (message) => chatCtx.sendMessage(message),
onClose: () {
chatCtx.toggleChat(false);
},
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 6031ef6..cd7f8b4 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -19,14 +19,8 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
- sdk: ^3.5.2
+ sdk: ">=3.6.0 <4.0.0"
-# Dependencies specify other packages that your package needs in order to work.
-# To automatically upgrade your package dependencies to the latest versions
-# consider running `flutter pub upgrade --major-versions`. Alternatively,
-# dependencies can be manually updated by changing the version numbers below to
-# the latest version available on pub.dev. To see which dependencies have newer
-# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
@@ -42,19 +36,12 @@ dependencies:
provider: ^6.1.2
fluttertoast: ^8.2.12
responsive_builder: ^0.7.1
- http: ^1.2.2
shared_preferences: ^2.5.3
dev_dependencies:
flutter_test:
sdk: flutter
-
- # The "flutter_lints" package below contains a set of recommended lints to
- # encourage good coding practices. The lint set provided by the package is
- # activated in the `analysis_options.yaml` file located at the root of your
- # package. See that file for information about deactivating specific lint
- # rules and activating additional ones.
- flutter_lints: ^4.0.0
+ flutter_lints: ^6.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
@@ -65,34 +52,3 @@ flutter:
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
-
- # To add assets to your application, add an assets section, like this:
- # assets:
- # - images/a_dot_burr.jpeg
- # - images/a_dot_ham.jpeg
-
- # An image asset can refer to one or more resolution-specific "variants", see
- # https://flutter.dev/to/resolution-aware-images
-
- # For details regarding adding assets from package dependencies, see
- # https://flutter.dev/to/asset-from-package
-
- # To add custom fonts to your application, add a fonts section here,
- # in this "flutter" section. Each entry in this list should have a
- # "family" key with the font family name, and a "fonts" key with a
- # list giving the asset and other descriptors for the font. For
- # example:
- # fonts:
- # - family: Schyler
- # fonts:
- # - asset: fonts/Schyler-Regular.ttf
- # - asset: fonts/Schyler-Italic.ttf
- # style: italic
- # - family: Trajan Pro
- # fonts:
- # - asset: fonts/TrajanPro.ttf
- # - asset: fonts/TrajanPro_Bold.ttf
- # weight: 700
- #
- # For details regarding fonts from package dependencies,
- # see https://flutter.dev/to/font-from-package
diff --git a/lib/livekit_components.dart b/lib/livekit_components.dart
index 12f7918..61f4f3e 100644
--- a/lib/livekit_components.dart
+++ b/lib/livekit_components.dart
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-library livekit_components;
-
export 'src/context/chat_context.dart';
export 'src/context/media_device_context.dart';
export 'src/context/participant_context.dart';
diff --git a/lib/src/context/chat_context.dart b/lib/src/context/chat_context.dart
index f6ad1d6..c4a7f1c 100644
--- a/lib/src/context/chat_context.dart
+++ b/lib/src/context/chat_context.dart
@@ -48,14 +48,13 @@ class ChatMessage {
String toJson() => const JsonEncoder().convert(toMap());
factory ChatMessage.fromJsonString(String source, Participant? participant) =>
- ChatMessage.fromMap(const JsonDecoder().convert(source), participant);
+ ChatMessage.fromMap(const JsonDecoder().convert(source) as Map, participant);
- factory ChatMessage.fromMap(
- Map map, Participant? participant) {
+ factory ChatMessage.fromMap(Map map, Participant? participant) {
return ChatMessage(
- message: map['message'],
- timestamp: map['timestamp'],
- id: map['id'],
+ message: map['message'] as String,
+ timestamp: map['timestamp'] as int,
+ id: map['id'] as String,
participant: participant,
sender: false,
);
@@ -68,8 +67,7 @@ mixin ChatContextMixin on ChangeNotifier {
LocalParticipant? _localParticipant;
EventsListener? _listener;
- void chatContextSetup(
- EventsListener? listener, LocalParticipant? localParticipant) {
+ void chatContextSetup(EventsListener? listener, LocalParticipant? localParticipant) {
_listener = listener;
_localParticipant = localParticipant;
if (listener != null) {
@@ -77,8 +75,7 @@ mixin ChatContextMixin on ChangeNotifier {
Debug.event('ChatContext: DataReceivedEvent');
if (event.topic == 'lk-chat-topic') {
- addMessageFromMap(
- const Utf8Decoder().convert(event.data), event.participant);
+ addMessageFromMap(const Utf8Decoder().convert(event.data), event.participant);
}
});
} else {
@@ -87,7 +84,7 @@ mixin ChatContextMixin on ChangeNotifier {
}
}
- void sendMessage(String message) {
+ Future sendMessage(String message) async {
final msg = ChatMessage(
message: message,
timestamp: DateTime.now().millisecondsSinceEpoch,
@@ -96,8 +93,10 @@ mixin ChatContextMixin on ChangeNotifier {
participant: _localParticipant,
);
addMessage(msg);
- _localParticipant?.publishData(const Utf8Encoder().convert(msg.toJson()),
- topic: 'lk-chat-topic');
+ await _localParticipant?.publishData(
+ const Utf8Encoder().convert(msg.toJson()),
+ topic: 'lk-chat-topic',
+ );
}
void addMessage(ChatMessage message) {
diff --git a/lib/src/context/media_device_context.dart b/lib/src/context/media_device_context.dart
index fa7e96e..97196bb 100644
--- a/lib/src/context/media_device_context.dart
+++ b/lib/src/context/media_device_context.dart
@@ -35,7 +35,7 @@ class MediaDeviceContext extends ChangeNotifier {
required RoomContext roomCtx,
}) : _roomCtx = roomCtx,
_room = roomCtx.room {
- loadDevices();
+ unawaited(loadDevices());
}
final RoomContext _roomCtx;
final Room? _room;
@@ -62,14 +62,14 @@ class MediaDeviceContext extends ChangeNotifier {
LocalAudioTrack? get localAudioTrack => _roomCtx.localAudioTrack;
- StreamSubscription? _deviceChangeSub;
+ StreamSubscription>? _deviceChangeSub;
Future loadDevices() async {
_loadDevices(await Hardware.instance.enumerateDevices());
_deviceChangeSub = Hardware.instance.onDeviceChange.stream.listen(_loadDevices);
}
- _loadDevices(List devices) {
+ void _loadDevices(List devices) {
_audioInputs = devices.where((d) => d.kind == 'audioinput').toList();
_audioOutputs = devices.where((d) => d.kind == 'audiooutput').toList();
_videoInputs = devices.where((d) => d.kind == 'videoinput').toList();
@@ -187,7 +187,7 @@ class MediaDeviceContext extends ChangeNotifier {
bool get isScreenShareEnabled => _room?.localParticipant?.isScreenShareEnabled() ?? false;
- Future enableScreenShare(context) async {
+ Future enableScreenShare(BuildContext context) async {
if (lkPlatformIsDesktop()) {
try {
final source = await showDialog(
@@ -199,7 +199,7 @@ class MediaDeviceContext extends ChangeNotifier {
return;
}
Debug.log('DesktopCapturerSource: ${source.id}');
- var track = await LocalVideoTrack.createScreenShareTrack(
+ final track = await LocalVideoTrack.createScreenShareTrack(
ScreenShareCaptureOptions(
sourceId: source.id,
maxFrameRate: 15.0,
@@ -213,7 +213,7 @@ class MediaDeviceContext extends ChangeNotifier {
}
if (lkPlatformIs(PlatformType.android)) {
// Android specific
- bool hasCapturePermission = await Helper.requestCapturePermission();
+ final hasCapturePermission = await Helper.requestCapturePermission();
if (!hasCapturePermission) {
return;
}
@@ -245,7 +245,7 @@ class MediaDeviceContext extends ChangeNotifier {
await requestBackgroundPermission();
}
if (lkPlatformIs(PlatformType.iOS)) {
- var track = await LocalVideoTrack.createScreenShareTrack(
+ final track = await LocalVideoTrack.createScreenShareTrack(
const ScreenShareCaptureOptions(
useiOSBroadcastExtension: true,
maxFrameRate: 15.0,
@@ -256,7 +256,7 @@ class MediaDeviceContext extends ChangeNotifier {
}
if (lkPlatformIsWebMobile()) {
- await context.showErrorDialog('Screen share is not supported on mobile web');
+ logger.warning('Screen share is not supported on mobile web');
return;
}
@@ -291,7 +291,7 @@ class MediaDeviceContext extends ChangeNotifier {
try {
await track.setCameraPosition(newPosition);
} catch (error) {
- print('could not restart track: $error');
+ logger.warning('could not restart track: $error');
return;
}
notifyListeners();
@@ -307,7 +307,7 @@ class MediaDeviceContext extends ChangeNotifier {
try {
await track.setCameraPosition(newPosition);
} catch (error) {
- print('could not restart track: $error');
+ logger.warning('could not restart track: $error');
return;
}
@@ -317,6 +317,6 @@ class MediaDeviceContext extends ChangeNotifier {
@override
void dispose() {
super.dispose();
- _deviceChangeSub?.cancel();
+ unawaited(_deviceChangeSub?.cancel());
}
}
diff --git a/lib/src/context/participant_context.dart b/lib/src/context/participant_context.dart
index 12a2b44..7cb28df 100644
--- a/lib/src/context/participant_context.dart
+++ b/lib/src/context/participant_context.dart
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import 'dart:async';
+
import 'package:flutter/material.dart';
import 'package:livekit_client/livekit_client.dart';
@@ -28,12 +30,10 @@ class ParticipantContext extends ChangeNotifier {
return Provider.of(context);
}
- ParticipantContext(this._participant)
- : _listener = _participant.createListener() {
+ ParticipantContext(this._participant) : _listener = _participant.createListener() {
_listener
..on((event) {
- if (event.participant.identity == identity &&
- isSpeaking != event.speaking) {
+ if (event.participant.identity == identity && isSpeaking != event.speaking) {
Debug.event(
'ParticipantContext: SpeakingChangedEvent identity = ${_participant.identity}, speaking = ${event.speaking}');
_isSpeaking = event.speaking;
@@ -41,14 +41,12 @@ class ParticipantContext extends ChangeNotifier {
}
})
..on((event) {
- Debug.event(
- 'ParticipantContext: ParticipantNameUpdatedEvent name = ${event.name}');
+ Debug.event('ParticipantContext: ParticipantNameUpdatedEvent name = ${event.name}');
notifyListeners();
})
..on((event) {
if (event.metadata != _metadata) {
- Debug.event(
- 'ParticipantContext: ParticipantMetadataUpdatedEvent metadata = ${event.metadata}');
+ Debug.event('ParticipantContext: ParticipantMetadataUpdatedEvent metadata = ${event.metadata}');
_metadata = event.metadata;
notifyListeners();
@@ -67,10 +65,8 @@ class ParticipantContext extends ChangeNotifier {
if (_permissions?.canPublish != event.permissions.canPublish ||
_permissions?.canSubscribe != event.permissions.canSubscribe ||
_permissions?.canPublishData != event.permissions.canPublishData ||
- _permissions?.canUpdateMetadata !=
- event.permissions.canUpdateMetadata ||
- _permissions?.canPublishSources !=
- event.permissions.canPublishSources) {
+ _permissions?.canUpdateMetadata != event.permissions.canUpdateMetadata ||
+ _permissions?.canPublishSources != event.permissions.canPublishSources) {
Debug.event(
'ParticipantContext: ParticipantPermissionsUpdatedEvent permissions canPublish = ${event.permissions.canPublish}, canSubscribe = ${event.permissions.canSubscribe}, canPublishData = ${event.permissions.canPublishData}, canUpdateMetadata = ${event.permissions.canUpdateMetadata}, canPublishSources = ${event.permissions.canPublishSources}');
_permissions = event.permissions;
@@ -86,23 +82,19 @@ class ParticipantContext extends ChangeNotifier {
notifyListeners();
})
..on((event) {
- Debug.event(
- 'ParticipantContext: ParticipantAttributesChanged attributes = ${event.attributes}');
+ Debug.event('ParticipantContext: ParticipantAttributesChanged attributes = ${event.attributes}');
_attributes = event.attributes;
notifyListeners();
})
..on((event) {
- if (event.participant.identity == identity &&
- event.publication.kind == TrackType.AUDIO) {
+ if (event.participant.identity == identity && event.publication.kind == TrackType.AUDIO) {
Debug.event('ParticipantContext: TrackMutedEvent for ${_participant.sid}');
notifyListeners();
}
})
..on((event) {
- if (event.participant.identity == identity &&
- event.publication.kind == TrackType.AUDIO) {
- Debug.event(
- 'ParticipantContext: TrackUnmutedEvent for ${_participant.sid}');
+ if (event.participant.identity == identity && event.publication.kind == TrackType.AUDIO) {
+ Debug.event('ParticipantContext: TrackUnmutedEvent for ${_participant.sid}');
notifyListeners();
}
})
@@ -125,21 +117,23 @@ class ParticipantContext extends ChangeNotifier {
@override
void dispose() {
super.dispose();
- _listener.dispose();
+ unawaited(_disposeListener());
createCount--;
Debug.log('Participant::dispose count $createCount');
}
+ Future _disposeListener() async {
+ await _listener.dispose();
+ }
+
bool get isLocal => _participant is LocalParticipant;
- List get tracks =>
- _participant.trackPublications.values.toList();
+ List get tracks => _participant.trackPublications.values.toList();
final Participant _participant;
final EventsListener _listener;
- bool get isEncrypted =>
- _participant.trackPublications.isNotEmpty && _participant.isEncrypted;
+ bool get isEncrypted => _participant.trackPublications.isNotEmpty && _participant.isEncrypted;
String get identity => _participant.identity;
@@ -152,8 +146,7 @@ class ParticipantContext extends ChangeNotifier {
String? _metadata;
String? get metadata => _metadata;
- String get name =>
- _participant.name == '' ? _participant.identity : _participant.name;
+ String get name => _participant.name == '' ? _participant.identity : _participant.name;
bool get isMuted => _participant.isMuted;
diff --git a/lib/src/context/room_context.dart b/lib/src/context/room_context.dart
index e98ece3..b611347 100644
--- a/lib/src/context/room_context.dart
+++ b/lib/src/context/room_context.dart
@@ -19,12 +19,11 @@ import 'package:flutter/material.dart' hide ConnectionState;
import 'package:livekit_client/livekit_client.dart';
import 'package:provider/provider.dart';
-import 'package:livekit_components/src/context/transcription_context.dart';
+import '../context/transcription_context.dart';
import '../debug/logger.dart';
import 'chat_context.dart';
-class RoomContext extends ChangeNotifier
- with ChatContextMixin, TranscriptionContextMixin {
+class RoomContext extends ChangeNotifier with ChatContextMixin, TranscriptionContextMixin {
/// Get the [RoomContext] from the [context].
/// this method must be called under the [LivekitRoom] widget.
static RoomContext? of(BuildContext context) {
@@ -96,27 +95,22 @@ class RoomContext extends ChangeNotifier
notifyListeners();
})
..on((event) {
- Debug.event(
- 'RoomContext: RoomMetadataChangedEvent $roomName metadata = ${event.metadata}');
+ Debug.event('RoomContext: RoomMetadataChangedEvent $roomName metadata = ${event.metadata}');
_roomMetadata = event.metadata;
notifyListeners();
})
..on((event) {
- Debug.event(
- 'RoomContext: RoomRecordingStatusChanged activeRecording = ${event.activeRecording}');
+ Debug.event('RoomContext: RoomRecordingStatusChanged activeRecording = ${event.activeRecording}');
_activeRecording = event.activeRecording;
notifyListeners();
})
..on((event) {
- Debug.event(
- 'RoomContext: ParticipantConnectedEvent $roomName participant = ${event.participant.identity}');
+ Debug.event('RoomContext: ParticipantConnectedEvent $roomName participant = ${event.participant.identity}');
_buildParticipants();
})
..on((event) {
- Debug.event(
- 'RoomContext: ParticipantDisconnectedEvent $roomName participant = ${event.participant.identity}');
- _participants
- .removeWhere((p) => p.identity == event.participant.identity);
+ Debug.event('RoomContext: ParticipantDisconnectedEvent $roomName participant = ${event.participant.identity}');
+ _participants.removeWhere((p) => p.identity == event.participant.identity);
notifyListeners();
})
..on((event) {
@@ -130,13 +124,11 @@ class RoomContext extends ChangeNotifier
_buildParticipants();
})
..on((event) {
- Debug.event(
- 'RoomContext: LocalTrackPublishedEvent track = ${event.publication.sid}');
+ Debug.event('RoomContext: LocalTrackPublishedEvent track = ${event.publication.sid}');
_buildParticipants();
})
..on((event) {
- Debug.event(
- 'RoomContext: LocalTrackUnpublishedEvent track = ${event.publication.sid}');
+ Debug.event('RoomContext: LocalTrackUnpublishedEvent track = ${event.publication.sid}');
_buildParticipants();
})
..on((event) {
@@ -153,7 +145,11 @@ class RoomContext extends ChangeNotifier
if (connect && url != null && token != null) {
_url = url;
_token = token;
- this.connect(url: url, token: token);
+ unawaited(this.connect(url: url, token: token).catchError((error, stack) {
+ Debug.event('RoomContext: auto connect failed: $error');
+ // Preserve original behavior by rethrowing after logging.
+ throw error;
+ }));
}
}
@@ -198,11 +194,11 @@ class RoomContext extends ChangeNotifier
notifyListeners();
}
- final Function()? onConnected;
+ final void Function()? onConnected;
- final Function()? onDisconnected;
+ final void Function()? onDisconnected;
- final Function(LiveKitException? error)? onError;
+ final void Function(LiveKitException? error)? onError;
final ConnectOptions? _connectOptions;
FastConnectOptions? _fastConnectOptions;
@@ -320,8 +316,7 @@ class RoomContext extends ChangeNotifier
bool get microphoneOpened => isMicrophoneEnabled ?? _localAudioTrack != null;
- bool? get isMicrophoneEnabled =>
- _room.localParticipant?.isMicrophoneEnabled();
+ bool? get isMicrophoneEnabled => _room.localParticipant?.isMicrophoneEnabled();
Future resetLocalTracks() async {
_localAudioTrack = null;
diff --git a/lib/src/context/track_reference_context.dart b/lib/src/context/track_reference_context.dart
index 87e9af8..1cc0656 100644
--- a/lib/src/context/track_reference_context.dart
+++ b/lib/src/context/track_reference_context.dart
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import 'dart:async';
+
import 'package:flutter/material.dart';
import 'package:livekit_client/livekit_client.dart';
@@ -39,29 +41,25 @@ class TrackReferenceContext extends ChangeNotifier {
})
..on((event) {
if (event.publication.sid == pub?.sid) {
- Debug.event(
- 'TrackContext: TrackUnmutedEvent for ${_participant.sid}');
+ Debug.event('TrackContext: TrackUnmutedEvent for ${_participant.sid}');
notifyListeners();
}
})
..on((event) {
if (event.publication.sid == pub?.sid) {
- Debug.event(
- 'TrackContext: LocalTrackPublishedEvent for ${_participant.sid}');
+ Debug.event('TrackContext: LocalTrackPublishedEvent for ${_participant.sid}');
notifyListeners();
}
})
..on((event) {
if (event.publication.sid == pub?.sid) {
- Debug.event(
- 'TrackContext: TrackSubscribedEvent for ${_participant.sid}');
+ Debug.event('TrackContext: TrackSubscribedEvent for ${_participant.sid}');
notifyListeners();
}
})
..on((event) {
if (event.publication.sid == pub?.sid) {
- Debug.event(
- 'TrackContext: TrackStreamStateUpdatedEvent for ${_participant.sid}');
+ Debug.event('TrackContext: TrackStreamStateUpdatedEvent for ${_participant.sid}');
notifyListeners();
}
});
@@ -70,10 +68,10 @@ class TrackReferenceContext extends ChangeNotifier {
@override
void dispose() {
super.dispose();
- _listener.cancelAll();
- _listener.dispose();
+ unawaited(_listener.cancelAll());
+ unawaited(_disposeListener());
if (_statsListener != null) {
- _statsListener!.dispose();
+ unawaited(_disposeStatsListener());
}
}
@@ -113,7 +111,7 @@ class TrackReferenceContext extends ChangeNotifier {
}
} else {
if (_statsListener != null) {
- _statsListener!.dispose();
+ unawaited(_disposeStatsListener());
}
_stats = {};
}
@@ -127,30 +125,27 @@ class TrackReferenceContext extends ChangeNotifier {
void _setUpListener(Track track) {
if (_statsListener != null) {
- _statsListener!.dispose();
+ unawaited(_disposeStatsListener());
}
_statsListener = track.createListener();
if (track is LocalVideoTrack) {
_statsListener?.on((event) {
- Map stats = {};
+ final stats = {};
stats['tx'] = 'total sent ${event.currentBitrate.toInt()} kpbs';
event.stats.forEach((key, value) {
stats['layer-$key'] =
'${value.frameWidth ?? 0}x${value.frameHeight ?? 0} ${value.framesPerSecond?.toDouble() ?? 0} fps, ${event.bitrateForLayers[key] ?? 0} kbps';
});
- var firstStats =
- event.stats['f'] ?? event.stats['h'] ?? event.stats['q'];
+ final firstStats = event.stats['f'] ?? event.stats['h'] ?? event.stats['q'];
if (firstStats != null) {
stats['encoder'] = firstStats.encoderImplementation ?? '';
if (firstStats.mimeType != null) {
- stats['codec'] =
- '${firstStats.mimeType!.split('/')[1]}/${firstStats.clockRate}';
+ stats['codec'] = '${firstStats.mimeType!.split('/')[1]}/${firstStats.clockRate}';
}
stats['payload'] = '${firstStats.payloadType}';
- stats['qualityLimitationReason'] =
- firstStats.qualityLimitationReason ?? '';
+ stats['qualityLimitationReason'] = firstStats.qualityLimitationReason ?? '';
}
_stats = stats;
@@ -158,11 +153,10 @@ class TrackReferenceContext extends ChangeNotifier {
});
} else if (track is RemoteVideoTrack) {
_statsListener?.on((event) {
- Map stats = {};
+ final stats = {};
stats['rx'] = '${event.currentBitrate.toInt()} kpbs';
if (event.stats.mimeType != null) {
- stats['codec'] =
- '${event.stats.mimeType!.split('/')[1]}/${event.stats.clockRate}';
+ stats['codec'] = '${event.stats.mimeType!.split('/')[1]}/${event.stats.clockRate}';
}
stats['payload'] = '${event.stats.payloadType}';
stats['size/fps'] =
@@ -180,11 +174,10 @@ class TrackReferenceContext extends ChangeNotifier {
});
} else if (track is LocalAudioTrack) {
_statsListener?.on((event) {
- Map stats = {};
+ final stats = {};
stats['tx'] = '${event.currentBitrate.toInt()} kpbs';
if (event.stats.mimeType != null) {
- stats['codec'] =
- '${event.stats.mimeType!.split('/')[1]}/${event.stats.clockRate}/${event.stats.channels}';
+ stats['codec'] = '${event.stats.mimeType!.split('/')[1]}/${event.stats.clockRate}/${event.stats.channels}';
}
stats['payload'] = '${event.stats.payloadType}';
_stats = stats;
@@ -192,12 +185,11 @@ class TrackReferenceContext extends ChangeNotifier {
});
} else if (track is RemoteAudioTrack) {
_statsListener?.on((event) {
- Map stats = {};
+ final stats = {};
stats['rx'] = '${event.currentBitrate.toInt()} kpbs';
if (event.stats.mimeType != null) {
- stats['codec'] =
- '${event.stats.mimeType!.split('/')[1]}/${event.stats.clockRate}/${event.stats.channels}';
+ stats['codec'] = '${event.stats.mimeType!.split('/')[1]}/${event.stats.clockRate}/${event.stats.channels}';
}
stats['payload'] = '${event.stats.payloadType}';
stats['jitter'] = '${event.stats.jitter} s';
@@ -211,4 +203,12 @@ class TrackReferenceContext extends ChangeNotifier {
});
}
}
+
+ Future _disposeStatsListener() async {
+ await _statsListener?.dispose();
+ }
+
+ Future _disposeListener() async {
+ await _listener.dispose();
+ }
}
diff --git a/lib/src/context/transcription_context.dart b/lib/src/context/transcription_context.dart
index 98f30ae..5907670 100644
--- a/lib/src/context/transcription_context.dart
+++ b/lib/src/context/transcription_context.dart
@@ -12,8 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import 'package:collection/collection.dart';
+import 'dart:async';
+
import 'package:flutter/material.dart';
+
+import 'package:collection/collection.dart';
import 'package:livekit_client/livekit_client.dart';
import '../types/transcription.dart';
@@ -27,8 +30,11 @@ mixin TranscriptionContextMixin on ChangeNotifier {
CancelListenFunc? _cancelListener;
void transcriptionContextCleanUp() {
- _cancelListener?.call();
+ final cancel = _cancelListener;
_cancelListener = null;
+ if (cancel != null) {
+ unawaited(cancel());
+ }
_transcriptionMap.clear();
}
diff --git a/lib/src/types/track_identifier.dart b/lib/src/types/track_identifier.dart
index f9e2a45..39ebe0b 100644
--- a/lib/src/types/track_identifier.dart
+++ b/lib/src/types/track_identifier.dart
@@ -32,13 +32,10 @@ class TrackIdentifier {
TrackSource get source => track?.source ?? TrackSource.unknown;
/// Returns true if the track is an audio source.
- bool get isAudio =>
- source == TrackSource.microphone ||
- source == TrackSource.screenShareAudio;
+ bool get isAudio => source == TrackSource.microphone || source == TrackSource.screenShareAudio;
/// Returns true if the track is a video source.
- bool get isVideo =>
- source == TrackSource.camera || source == TrackSource.screenShareVideo;
+ bool get isVideo => source == TrackSource.camera || source == TrackSource.screenShareVideo;
/// Returns true if the participant is local.
bool get isLocal => participant is LocalParticipant;
diff --git a/lib/src/types/transcription.dart b/lib/src/types/transcription.dart
index 9e5ff25..fd1c69e 100644
--- a/lib/src/types/transcription.dart
+++ b/lib/src/types/transcription.dart
@@ -1,4 +1,5 @@
import 'package:flutter/foundation.dart';
+
import 'package:livekit_client/livekit_client.dart' as sdk;
@immutable
diff --git a/lib/src/ui/builder/camera_preview.dart b/lib/src/ui/builder/camera_preview.dart
index 99efd1d..b31e38c 100644
--- a/lib/src/ui/builder/camera_preview.dart
+++ b/lib/src/ui/builder/camera_preview.dart
@@ -25,14 +25,12 @@ class CameraPreview extends StatelessWidget {
required this.builder,
});
- final Widget Function(BuildContext context, LocalVideoTrack? videoTrack)
- builder;
+ final Widget Function(BuildContext context, LocalVideoTrack? videoTrack) builder;
@override
Widget build(BuildContext context) {
return Consumer(
- builder: (context, roomCtx, child) =>
- Selector(
+ builder: (context, roomCtx, child) => Selector(
selector: (context, track) => roomCtx.localVideoTrack,
builder: (context, track, child) => builder(context, track),
),
diff --git a/lib/src/ui/builder/participant/participant_attributes.dart b/lib/src/ui/builder/participant/participant_attributes.dart
index 05a6106..4ff94e8 100644
--- a/lib/src/ui/builder/participant/participant_attributes.dart
+++ b/lib/src/ui/builder/participant/participant_attributes.dart
@@ -25,15 +25,12 @@ class ParticipantAttributes extends StatelessWidget {
required this.builder,
});
- final Widget Function(BuildContext context, Map? attributes)
- builder;
+ final Widget Function(BuildContext context, Map? attributes) builder;
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> ParticipantAttributes for ${participantContext.attributes}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> ParticipantAttributes for ${participantContext.attributes}');
return Selector?>(
selector: (context, attributes) => participantContext.attributes,
builder: (context, attributes, child) {
diff --git a/lib/src/ui/builder/participant/participant_kind.dart b/lib/src/ui/builder/participant/participant_kind.dart
index f6a4b86..0d7d709 100644
--- a/lib/src/ui/builder/participant/participant_kind.dart
+++ b/lib/src/ui/builder/participant/participant_kind.dart
@@ -30,8 +30,7 @@ class ParticipantKind extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
+ return Consumer(builder: (context, participantContext, child) {
Debug.log('====> ParticipantKind for ${participantContext.kind}');
return Selector(
selector: (context, name) => participantContext.kind,
diff --git a/lib/src/ui/builder/participant/participant_loop.dart b/lib/src/ui/builder/participant/participant_loop.dart
index ac9cc7b..22ba54c 100644
--- a/lib/src/ui/builder/participant/participant_loop.dart
+++ b/lib/src/ui/builder/participant/participant_loop.dart
@@ -25,8 +25,7 @@ import '../../layout/layouts.dart';
import '../../layout/sorting.dart';
import 'participant_track.dart';
-typedef PaticipantTrackBuilder = Widget Function(
- BuildContext context, TrackIdentifier identifier);
+typedef PaticipantTrackBuilder = Widget Function(BuildContext context, TrackIdentifier identifier);
class ParticipantLoop extends StatelessWidget {
const ParticipantLoop({
@@ -54,7 +53,7 @@ class ParticipantLoop extends StatelessWidget {
for (Participant participant in participants) {
Debug.log('=> participant ${participant.identity}, index: $index');
index++;
- var tracks = participant.trackPublications.values;
+ final tracks = participant.trackPublications.values;
for (var track in tracks) {
if (track.kind == TrackType.AUDIO && !audio) {
continue;
@@ -64,8 +63,7 @@ class ParticipantLoop extends StatelessWidget {
}
trackMap.add(MapEntry(TrackIdentifier(participant, track), track));
- Debug.log(
- '=> ${track.source.toString()} track ${track.sid} for ${participant.identity}');
+ Debug.log('=> ${track.source.toString()} track ${track.sid} for ${participant.identity}');
}
if (!audio && !tracks.any((t) => t.kind == TrackType.VIDEO) ||
@@ -92,12 +90,11 @@ class ParticipantLoop extends StatelessWidget {
builder: (context, participants, child) {
List trackWidgets = [];
- var trackMap = buildTracksMap(
- showAudioTracks, showVideoTracks, participants);
+ final trackMap = buildTracksMap(showAudioTracks, showVideoTracks, participants);
for (var item in trackMap) {
- var identifier = item.key;
- var track = item.value;
+ final identifier = item.key;
+ final track = item.value;
if (track != null) {
trackWidgets.add(
TrackWidget(
@@ -105,8 +102,7 @@ class ParticipantLoop extends StatelessWidget {
ParticipantTrack(
participant: identifier.participant,
track: track,
- builder: (context) =>
- participantTrackBuilder(context, identifier),
+ builder: (context) => participantTrackBuilder(context, identifier),
),
),
);
@@ -116,8 +112,7 @@ class ParticipantLoop extends StatelessWidget {
identifier,
ParticipantTrack(
participant: identifier.participant,
- builder: (context) =>
- participantTrackBuilder(context, identifier),
+ builder: (context) => participantTrackBuilder(context, identifier),
),
),
);
@@ -129,8 +124,7 @@ class ParticipantLoop extends StatelessWidget {
return Selector>(
selector: (context, pinnedTracks) => roomCtx.pinnedTracks,
builder: (context, pinnedTracks, child) {
- return layoutBuilder.build(
- context, trackWidgets, pinnedTracks);
+ return layoutBuilder.build(context, trackWidgets, pinnedTracks);
});
});
},
diff --git a/lib/src/ui/builder/participant/participant_metadata.dart b/lib/src/ui/builder/participant/participant_metadata.dart
index 71e6f41..9c52931 100644
--- a/lib/src/ui/builder/participant/participant_metadata.dart
+++ b/lib/src/ui/builder/participant/participant_metadata.dart
@@ -29,10 +29,8 @@ class ParticipantMetadata extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> ParticipantMetadata for ${participantContext.metadata}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> ParticipantMetadata for ${participantContext.metadata}');
return Selector(
selector: (context, metadata) => participantContext.metadata,
builder: (context, metadata, child) {
diff --git a/lib/src/ui/builder/participant/participant_muted_indicator.dart b/lib/src/ui/builder/participant/participant_muted_indicator.dart
index e0ebc6a..a028937 100644
--- a/lib/src/ui/builder/participant/participant_muted_indicator.dart
+++ b/lib/src/ui/builder/participant/participant_muted_indicator.dart
@@ -29,10 +29,8 @@ class ParticipantMutedIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> ParticipantMutedIndicator for ${participantContext.name}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> ParticipantMutedIndicator for ${participantContext.name}');
return Selector(
selector: (context, isMuted) => participantContext.isMuted,
builder: (context, isMuted, child) => builder(context, isMuted),
diff --git a/lib/src/ui/builder/participant/participant_name.dart b/lib/src/ui/builder/participant/participant_name.dart
index d898277..73846e8 100644
--- a/lib/src/ui/builder/participant/participant_name.dart
+++ b/lib/src/ui/builder/participant/participant_name.dart
@@ -30,15 +30,14 @@ class ParticipantName extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
+ return Consumer(builder: (context, participantContext, child) {
Debug.log('====> ParticipantName for ${participantContext.name}');
- var trackCtx = Provider.of(context);
- bool isScreenShare = trackCtx?.isScreenShare ?? false;
+ final trackCtx = Provider.of(context);
+ final isScreenShare = trackCtx?.isScreenShare ?? false;
return Selector(
selector: (context, name) => participantContext.name,
builder: (context, name, child) {
- var str = isScreenShare ? '$name\'s screen' : name;
+ final str = isScreenShare ? '$name\'s screen' : name;
return builder(context, str);
},
);
diff --git a/lib/src/ui/builder/participant/participant_permissions.dart b/lib/src/ui/builder/participant/participant_permissions.dart
index b3de588..4e1048f 100644
--- a/lib/src/ui/builder/participant/participant_permissions.dart
+++ b/lib/src/ui/builder/participant/participant_permissions.dart
@@ -26,15 +26,12 @@ class ParticipantPermissions extends StatelessWidget {
required this.builder,
});
- final Widget Function(BuildContext context, lk.ParticipantPermissions?)
- builder;
+ final Widget Function(BuildContext context, lk.ParticipantPermissions?) builder;
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> ParticipantPermissions for ${participantContext.permissions}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> ParticipantPermissions for ${participantContext.permissions}');
return Selector(
selector: (context, permissions) => participantContext.permissions,
builder: (context, permissions, child) {
diff --git a/lib/src/ui/builder/participant/participant_selector.dart b/lib/src/ui/builder/participant/participant_selector.dart
index 4cd59f4..ee37922 100644
--- a/lib/src/ui/builder/participant/participant_selector.dart
+++ b/lib/src/ui/builder/participant/participant_selector.dart
@@ -4,15 +4,14 @@ import 'package:collection/collection.dart';
import 'package:livekit_client/livekit_client.dart';
import 'package:provider/provider.dart';
-import 'package:livekit_components/src/types/track_identifier.dart';
import '../../../context/room_context.dart';
import '../../../debug/logger.dart';
+import '../../../types/track_identifier.dart';
import 'participant_track.dart';
class ParticipantSelector extends StatelessWidget {
final bool Function(TrackIdentifier identifier) filter;
- final Widget Function(BuildContext context, TrackIdentifier identifier)
- builder;
+ final Widget Function(BuildContext context, TrackIdentifier identifier) builder;
const ParticipantSelector({
required this.filter,
required this.builder,
@@ -26,7 +25,7 @@ class ParticipantSelector extends StatelessWidget {
for (Participant participant in participants) {
Debug.log('=> participant ${participant.identity}, index: $index');
index++;
- var tracks = participant.trackPublications.values;
+ final tracks = participant.trackPublications.values;
for (var track in tracks) {
if (track.kind == TrackType.AUDIO && !audio) {
continue;
@@ -36,8 +35,7 @@ class ParticipantSelector extends StatelessWidget {
}
trackMap.add(MapEntry(TrackIdentifier(participant, track), track));
- Debug.log(
- '=> ${track.source.toString()} track ${track.sid} for ${participant.identity}');
+ Debug.log('=> ${track.source.toString()} track ${track.sid} for ${participant.identity}');
}
if (!audio && !tracks.any((t) => t.kind == TrackType.VIDEO) ||
@@ -60,9 +58,8 @@ class ParticipantSelector extends StatelessWidget {
selector: (context, participants) => roomCtx.participants,
shouldRebuild: (previous, next) => previous.length != next.length,
builder: (context, participants, child) {
- var trackMap = buildTracksMap(true, true, participants);
- var identifier =
- trackMap.firstWhereOrNull((entry) => filter(entry.key))?.key;
+ final trackMap = buildTracksMap(true, true, participants);
+ final identifier = trackMap.firstWhereOrNull((entry) => filter(entry.key))?.key;
if (identifier == null) {
return const SizedBox();
diff --git a/lib/src/ui/builder/participant/participant_transcription.dart b/lib/src/ui/builder/participant/participant_transcription.dart
index 523d23b..3b1a682 100644
--- a/lib/src/ui/builder/participant/participant_transcription.dart
+++ b/lib/src/ui/builder/participant/participant_transcription.dart
@@ -26,15 +26,12 @@ class ParticipantTranscription extends StatelessWidget {
required this.builder,
});
- final Widget Function(
- BuildContext context, List segments) builder;
+ final Widget Function(BuildContext context, List segments) builder;
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> ParticipantTranscription for ${participantContext.segments}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> ParticipantTranscription for ${participantContext.segments}');
return Selector>(
selector: (context, segments) => participantContext.segments,
builder: (context, segments, child) {
diff --git a/lib/src/ui/builder/room/camera_switch.dart b/lib/src/ui/builder/room/camera_switch.dart
index 1eac20b..291c01f 100644
--- a/lib/src/ui/builder/room/camera_switch.dart
+++ b/lib/src/ui/builder/room/camera_switch.dart
@@ -28,8 +28,8 @@ class CameraSwitch extends StatelessWidget {
required this.builder,
});
- final Function(BuildContext context, RoomContext roomCtx,
- MediaDeviceContext deviceCtx, CameraPosition? position) builder;
+ final Widget Function(
+ BuildContext context, RoomContext roomCtx, MediaDeviceContext deviceCtx, CameraPosition? position) builder;
@override
Widget build(BuildContext context) {
diff --git a/lib/src/ui/builder/room/chat.dart b/lib/src/ui/builder/room/chat.dart
index d924cc9..b4aee50 100644
--- a/lib/src/ui/builder/room/chat.dart
+++ b/lib/src/ui/builder/room/chat.dart
@@ -25,8 +25,8 @@ class ChatBuilder extends StatelessWidget {
required this.builder,
});
- final Function(BuildContext context, bool enabled, ChatContextMixin chatCtx,
- List messages) builder;
+ final Widget Function(BuildContext context, bool enabled, ChatContextMixin chatCtx, List messages)
+ builder;
@override
Widget build(BuildContext context) {
diff --git a/lib/src/ui/builder/room/chat_toggle.dart b/lib/src/ui/builder/room/chat_toggle.dart
index aed7955..86d936a 100644
--- a/lib/src/ui/builder/room/chat_toggle.dart
+++ b/lib/src/ui/builder/room/chat_toggle.dart
@@ -21,16 +21,14 @@ import '../../../context/room_context.dart';
class ChatToggle extends StatelessWidget {
const ChatToggle({super.key, required this.builder});
- final Widget Function(
- BuildContext context, RoomContext roomCtx, bool isChatEnabled) builder;
+ final Widget Function(BuildContext context, RoomContext roomCtx, bool isChatEnabled) builder;
@override
Widget build(BuildContext context) {
return Consumer(builder: (context, roomCtx, child) {
return Selector(
selector: (context, isChatEnabled) => roomCtx.isChatEnabled,
- builder: (context, isChatEnabled, child) =>
- builder(context, roomCtx, isChatEnabled),
+ builder: (context, isChatEnabled, child) => builder(context, roomCtx, isChatEnabled),
);
});
}
diff --git a/lib/src/ui/builder/room/disconnect_button.dart b/lib/src/ui/builder/room/disconnect_button.dart
index bde1836..fccc286 100644
--- a/lib/src/ui/builder/room/disconnect_button.dart
+++ b/lib/src/ui/builder/room/disconnect_button.dart
@@ -21,8 +21,7 @@ import '../../../context/room_context.dart';
class DisconnectButton extends StatelessWidget {
const DisconnectButton({super.key, required this.builder});
- final Function(BuildContext context, RoomContext roomCtx, bool connected)
- builder;
+ final Widget Function(BuildContext context, RoomContext roomCtx, bool connected) builder;
@override
Widget build(BuildContext context) {
@@ -30,8 +29,7 @@ class DisconnectButton extends StatelessWidget {
builder: (context, roomCtx, child) {
return Selector(
selector: (context, connected) => roomCtx.connected,
- builder: (context, connected, child) =>
- builder(context, roomCtx, connected),
+ builder: (context, connected, child) => builder(context, roomCtx, connected),
);
},
);
diff --git a/lib/src/ui/builder/room/join_button.dart b/lib/src/ui/builder/room/join_button.dart
index 5db5c5a..777abba 100644
--- a/lib/src/ui/builder/room/join_button.dart
+++ b/lib/src/ui/builder/room/join_button.dart
@@ -24,16 +24,14 @@ class JoinButton extends StatelessWidget {
required this.builder,
});
- final Function(BuildContext context, RoomContext roomCtx, bool connected)
- builder;
+ final Widget Function(BuildContext context, RoomContext roomCtx, bool connected) builder;
@override
Widget build(BuildContext context) {
return Consumer(builder: (context, roomCtx, child) {
return Selector(
selector: (context, connected) => roomCtx.connected,
- builder: (context, connected, child) =>
- builder(context, roomCtx, connected),
+ builder: (context, connected, child) => builder(context, roomCtx, connected),
);
});
}
diff --git a/lib/src/ui/builder/room/media_device.dart b/lib/src/ui/builder/room/media_device.dart
index c660f4d..66eaf18 100644
--- a/lib/src/ui/builder/room/media_device.dart
+++ b/lib/src/ui/builder/room/media_device.dart
@@ -22,8 +22,7 @@ import '../../../context/room_context.dart';
class MediaDeviceContextBuilder extends StatelessWidget {
const MediaDeviceContextBuilder({super.key, required this.builder});
- final Widget Function(BuildContext context, RoomContext roomContext,
- MediaDeviceContext mediaDeviceContext) builder;
+ final Widget Function(BuildContext context, RoomContext roomContext, MediaDeviceContext mediaDeviceContext) builder;
@override
Widget build(BuildContext context) {
@@ -31,8 +30,7 @@ class MediaDeviceContextBuilder extends StatelessWidget {
builder: (context, roomCtx, child) => ChangeNotifierProvider(
create: (_) => MediaDeviceContext(roomCtx: roomCtx),
child: Consumer(
- builder: (context, mediaDeviceCtx, child) =>
- builder(context, roomCtx, mediaDeviceCtx),
+ builder: (context, mediaDeviceCtx, child) => builder(context, roomCtx, mediaDeviceCtx),
),
),
);
diff --git a/lib/src/ui/builder/room/media_device_select_button.dart b/lib/src/ui/builder/room/media_device_select_button.dart
index 678c11c..45a7e87 100644
--- a/lib/src/ui/builder/room/media_device_select_button.dart
+++ b/lib/src/ui/builder/room/media_device_select_button.dart
@@ -35,8 +35,7 @@ class MediaDeviceSelectButton extends StatelessWidget {
Widget build(BuildContext context) {
return Consumer(
builder: (context, roomCtx, child) => Consumer(
- builder: (context, deviceCtx, child) =>
- builder(context, roomCtx, deviceCtx),
+ builder: (context, deviceCtx, child) => builder(context, roomCtx, deviceCtx),
),
);
}
diff --git a/lib/src/ui/builder/room/room.dart b/lib/src/ui/builder/room/room.dart
index 10e0bda..38747ba 100644
--- a/lib/src/ui/builder/room/room.dart
+++ b/lib/src/ui/builder/room/room.dart
@@ -20,8 +20,7 @@ import '../../../context/room_context.dart';
import 'media_device.dart';
class LivekitRoom extends StatelessWidget {
- const LivekitRoom(
- {super.key, required this.roomContext, required this.builder});
+ const LivekitRoom({super.key, required this.roomContext, required this.builder});
final RoomContext roomContext;
final Widget Function(BuildContext context, RoomContext roomCtx) builder;
@@ -32,8 +31,7 @@ class LivekitRoom extends StatelessWidget {
create: (_) => roomContext,
child: Consumer(
builder: (context, roomCtx, child) => MediaDeviceContextBuilder(
- builder: (context, roomCtx, mediaDeviceCtx) =>
- builder(context, roomCtx),
+ builder: (context, roomCtx, mediaDeviceCtx) => builder(context, roomCtx),
),
),
);
diff --git a/lib/src/ui/builder/room/room_active_recording_indicator.dart b/lib/src/ui/builder/room/room_active_recording_indicator.dart
index 737c222..c89c965 100644
--- a/lib/src/ui/builder/room/room_active_recording_indicator.dart
+++ b/lib/src/ui/builder/room/room_active_recording_indicator.dart
@@ -31,8 +31,7 @@ class RoomActiveRecording extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer(builder: (context, roomCtx, child) {
- Debug.log(
- '====> RoomActiveRecording for ${roomCtx.activeRecording}');
+ Debug.log('====> RoomActiveRecording for ${roomCtx.activeRecording}');
return Selector(
selector: (context, activeRecording) => roomCtx.activeRecording,
builder: (context, activeRecording, child) {
diff --git a/lib/src/ui/builder/room/room_connection_state.dart b/lib/src/ui/builder/room/room_connection_state.dart
index d7a0e24..3464f2b 100644
--- a/lib/src/ui/builder/room/room_connection_state.dart
+++ b/lib/src/ui/builder/room/room_connection_state.dart
@@ -22,18 +22,16 @@ import '../../../debug/logger.dart';
class RoomConnectionState extends StatelessWidget {
const RoomConnectionState({
- Key? key,
+ super.key,
required this.builder,
});
- final Widget Function(BuildContext context, ConnectionState connectionState)
- builder;
+ final Widget Function(BuildContext context, ConnectionState connectionState) builder;
@override
Widget build(BuildContext context) {
return Consumer(builder: (context, roomCtx, child) {
- Debug.log(
- '====> RoomConnectionState for ${roomCtx.connectionState}');
+ Debug.log('====> RoomConnectionState for ${roomCtx.connectionState}');
return Selector(
selector: (context, connectionState) => roomCtx.connectionState,
builder: (context, connectionState, child) {
diff --git a/lib/src/ui/builder/room/room_participants.dart b/lib/src/ui/builder/room/room_participants.dart
index 64989fc..827b241 100644
--- a/lib/src/ui/builder/room/room_participants.dart
+++ b/lib/src/ui/builder/room/room_participants.dart
@@ -26,8 +26,7 @@ class RoomParticipants extends StatelessWidget {
required this.builder,
});
- final Widget Function(BuildContext context, List participants)
- builder;
+ final Widget Function(BuildContext context, List participants) builder;
@override
Widget build(BuildContext context) {
diff --git a/lib/src/ui/builder/room/screenshare_toggle.dart b/lib/src/ui/builder/room/screenshare_toggle.dart
index 2b77fa7..caaabdb 100644
--- a/lib/src/ui/builder/room/screenshare_toggle.dart
+++ b/lib/src/ui/builder/room/screenshare_toggle.dart
@@ -25,8 +25,8 @@ class ScreenShareToggle extends StatelessWidget {
required this.builder,
});
- final Function(BuildContext context, RoomContext roomCtx,
- MediaDeviceContext deviceCtx, bool screenShareEnabled) builder;
+ final Widget Function(
+ BuildContext context, RoomContext roomCtx, MediaDeviceContext deviceCtx, bool screenShareEnabled) builder;
@override
Widget build(BuildContext context) {
@@ -35,8 +35,7 @@ class ScreenShareToggle extends StatelessWidget {
return Consumer(
builder: (context, deviceCtx, child) {
return Selector(
- selector: (context, screenShareEnabled) =>
- deviceCtx.isScreenShareEnabled,
+ selector: (context, screenShareEnabled) => deviceCtx.isScreenShareEnabled,
builder: (context, screenShareEnabled, child) => builder(
context,
roomCtx,
diff --git a/lib/src/ui/builder/room/speaker_switch.dart b/lib/src/ui/builder/room/speaker_switch.dart
index 8a10ea5..0a47dfa 100644
--- a/lib/src/ui/builder/room/speaker_switch.dart
+++ b/lib/src/ui/builder/room/speaker_switch.dart
@@ -25,8 +25,8 @@ class SpeakerSwitch extends StatelessWidget {
required this.builder,
});
- final Function(BuildContext context, RoomContext roomCtx,
- MediaDeviceContext deviceCtx, bool? isSpeakerOn) builder;
+ final Widget Function(BuildContext context, RoomContext roomCtx, MediaDeviceContext deviceCtx, bool? isSpeakerOn)
+ builder;
@override
Widget build(BuildContext context) {
diff --git a/lib/src/ui/builder/room/transcription.dart b/lib/src/ui/builder/room/transcription.dart
index 8a07dcb..92e0081 100644
--- a/lib/src/ui/builder/room/transcription.dart
+++ b/lib/src/ui/builder/room/transcription.dart
@@ -13,6 +13,7 @@
// limitations under the License.
import 'package:flutter/material.dart';
+
import 'package:provider/provider.dart';
import '../../../context/room_context.dart';
@@ -27,7 +28,7 @@ import '../../../types/transcription.dart';
/// The builder function receives the current build context and a list of transcriptions,
/// allowing you to build custom UI components that display transcription data.
class TranscriptionBuilder extends StatelessWidget {
- final Function(BuildContext context, List transcriptions) builder;
+ final Widget Function(BuildContext context, List transcriptions) builder;
const TranscriptionBuilder({
super.key,
diff --git a/lib/src/ui/builder/track/connection_quality_indicator.dart b/lib/src/ui/builder/track/connection_quality_indicator.dart
index e304627..9afecf9 100644
--- a/lib/src/ui/builder/track/connection_quality_indicator.dart
+++ b/lib/src/ui/builder/track/connection_quality_indicator.dart
@@ -12,20 +12,15 @@ class ConnectionQualityIndicator extends StatelessWidget {
required this.builder,
});
- final Widget Function(
- BuildContext context, ConnectionQuality connectionQuality) builder;
+ final Widget Function(BuildContext context, ConnectionQuality connectionQuality) builder;
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> ConnectionQualityIndicator for ${participantContext.name}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> ConnectionQualityIndicator for ${participantContext.name}');
return Selector(
- selector: (context, connectionQuality) =>
- participantContext.connectionQuality,
- builder: (context, connectionQuality, child) =>
- builder(context, connectionQuality),
+ selector: (context, connectionQuality) => participantContext.connectionQuality,
+ builder: (context, connectionQuality, child) => builder(context, connectionQuality),
);
});
}
diff --git a/lib/src/ui/builder/track/e2e_encryption_indicator.dart b/lib/src/ui/builder/track/e2e_encryption_indicator.dart
index 70fb300..2bc9822 100644
--- a/lib/src/ui/builder/track/e2e_encryption_indicator.dart
+++ b/lib/src/ui/builder/track/e2e_encryption_indicator.dart
@@ -15,10 +15,8 @@ class E2EEncryptionIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, participantContext, child) {
- Debug.log(
- '====> E2EEncryptionIndicator for ${participantContext.name}');
+ return Consumer(builder: (context, participantContext, child) {
+ Debug.log('====> E2EEncryptionIndicator for ${participantContext.name}');
return Selector(
selector: (context, isEncrypted) => participantContext.isEncrypted,
builder: (context, isEncrypted, child) => builder(context, isEncrypted),
diff --git a/lib/src/ui/builder/track/is_speaking_indicator.dart b/lib/src/ui/builder/track/is_speaking_indicator.dart
index 8629ce2..4265731 100644
--- a/lib/src/ui/builder/track/is_speaking_indicator.dart
+++ b/lib/src/ui/builder/track/is_speaking_indicator.dart
@@ -16,16 +16,15 @@ class IsSpeakingIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var participantContext = Provider.of(context);
- var trackCtx = Provider.of(context);
+ final participantContext = Provider.of(context);
+ final trackCtx = Provider.of(context);
/// Show speaking indicator only if the participant is not sharing screen
- var showSpeakingIndicator = !(trackCtx?.isScreenShare ?? true);
+ final showSpeakingIndicator = !(trackCtx?.isScreenShare ?? true);
Debug.log('===> IsSpeakingIndicator for ${participantContext.name}');
return Selector(
selector: (context, isSpeaking) => participantContext.isSpeaking,
- builder: (context, isSpeaking, child) =>
- builder(context, showSpeakingIndicator ? isSpeaking : null),
+ builder: (context, isSpeaking, child) => builder(context, showSpeakingIndicator ? isSpeaking : null),
);
}
}
diff --git a/lib/src/ui/layout/carousel_layout.dart b/lib/src/ui/layout/carousel_layout.dart
index c22c8d8..74ecd94 100644
--- a/lib/src/ui/layout/carousel_layout.dart
+++ b/lib/src/ui/layout/carousel_layout.dart
@@ -30,15 +30,13 @@ class CarouselLayoutBuilder implements ParticipantLayoutBuilder {
List children,
List pinnedTracks,
) {
- List pinnedWidgets = [];
- List otherWidgets = [];
+ final pinnedWidgets = [];
+ final otherWidgets = [];
/// Move focused tracks to the pinned list
for (var sid in pinnedTracks) {
- var widget = children
- .where((element) => element.trackIdentifier.identifier == sid)
- .map((e) => e.widget)
- .firstOrNull;
+ final widget =
+ children.where((element) => element.trackIdentifier.identifier == sid).map((e) => e.widget).firstOrNull;
if (widget != null) {
pinnedWidgets.add(widget);
}
@@ -62,9 +60,9 @@ class CarouselLayoutBuilder implements ParticipantLayoutBuilder {
}
}
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
- var orientation = MediaQuery.of(context).orientation;
- var isMobile = deviceScreenType == DeviceScreenType.mobile;
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final orientation = MediaQuery.of(context).orientation;
+ final isMobile = deviceScreenType == DeviceScreenType.mobile;
if (isMobile && orientation == Orientation.portrait) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
diff --git a/lib/src/ui/layout/grid_layout.dart b/lib/src/ui/layout/grid_layout.dart
index d5132a1..286229f 100644
--- a/lib/src/ui/layout/grid_layout.dart
+++ b/lib/src/ui/layout/grid_layout.dart
@@ -27,13 +27,10 @@ class GridLayoutBuilder implements ParticipantLayoutBuilder {
List children,
List pinnedTracks,
) {
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
- var orientation = MediaQuery.of(context).orientation;
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final orientation = MediaQuery.of(context).orientation;
return GridView.count(
- crossAxisCount: deviceScreenType == DeviceScreenType.mobile &&
- orientation == Orientation.portrait
- ? 2
- : 4,
+ crossAxisCount: deviceScreenType == DeviceScreenType.mobile && orientation == Orientation.portrait ? 2 : 4,
childAspectRatio: 1.5,
children: children.map((e) => e.widget).toList(),
);
diff --git a/lib/src/ui/layout/sorting.dart b/lib/src/ui/layout/sorting.dart
index 80d9236..8b3e0a0 100644
--- a/lib/src/ui/layout/sorting.dart
+++ b/lib/src/ui/layout/sorting.dart
@@ -17,7 +17,7 @@ import 'package:livekit_client/livekit_client.dart';
import 'layouts.dart';
List defaultSorting(List trackWidgets) {
- List trackWidgetsSorted = [];
+ final trackWidgetsSorted = [];
/// sort screen shares and local participant first
for (var element in trackWidgets) {
@@ -32,8 +32,8 @@ List defaultSorting(List trackWidgets) {
// sort speakers for the grid
trackWidgetsSorted.sort((a, b) {
// loudest speaker first
- var participantA = a.trackIdentifier.participant;
- var participantB = b.trackIdentifier.participant;
+ final participantA = a.trackIdentifier.participant;
+ final participantB = b.trackIdentifier.participant;
if (participantA.isSpeaking && participantB.isSpeaking) {
if (participantA.audioLevel > participantB.audioLevel) {
return -1;
@@ -56,8 +56,7 @@ List defaultSorting(List trackWidgets) {
}
// joinedAt
- return participantA.joinedAt.millisecondsSinceEpoch -
- participantB.joinedAt.millisecondsSinceEpoch;
+ return participantA.joinedAt.millisecondsSinceEpoch - participantB.joinedAt.millisecondsSinceEpoch;
});
return trackWidgetsSorted;
diff --git a/lib/src/ui/prejoin/prejoin.dart b/lib/src/ui/prejoin/prejoin.dart
index daa2109..9c50cfd 100644
--- a/lib/src/ui/prejoin/prejoin.dart
+++ b/lib/src/ui/prejoin/prejoin.dart
@@ -26,26 +26,58 @@ import '../widgets/room/join_button.dart';
import '../widgets/room/microphone_select_button.dart';
import 'text_input.dart';
-class Prejoin extends StatelessWidget {
- Prejoin(
- {super.key, required this.token, required this.url, this.onJoinPressed});
+class Prejoin extends StatefulWidget {
+ const Prejoin({super.key, required this.token, required this.url, this.onJoinPressed});
- final Function(RoomContext roomCtx, String url, String token)? onJoinPressed;
+ final void Function(RoomContext roomCtx, String url, String token)? onJoinPressed;
- String token;
+ final String token;
- String url;
+ final String url;
- void onTextTokenChanged(String token) async {
- this.token = token;
+ @override
+ State createState() => _PrejoinState();
+}
+
+class _PrejoinState extends State {
+ late String _token;
+
+ late String _url;
+
+ @override
+ void initState() {
+ super.initState();
+ _token = widget.token;
+ _url = widget.url;
+ }
+
+ @override
+ void didUpdateWidget(covariant Prejoin oldWidget) {
+ super.didUpdateWidget(oldWidget);
+ if (oldWidget.token != widget.token) {
+ _token = widget.token;
+ }
+ if (oldWidget.url != widget.url) {
+ _url = widget.url;
+ }
+ }
+
+ void onTextTokenChanged(String token) {
+ setState(() {
+ _token = token;
+ });
}
- void onTextUrlChanged(String url) async {
- this.url = url;
+ void onTextUrlChanged(String url) {
+ setState(() {
+ _url = url;
+ });
}
- void _handleJoinPressed(RoomContext roomCtx) async {
- if (onJoinPressed == null) {
+ Future _handleJoinPressed(RoomContext roomCtx) async {
+ final token = _token;
+ final url = _url;
+ if (widget.onJoinPressed == null) {
Debug.event('Joining room: $url');
try {
await roomCtx.connect(
@@ -57,14 +89,13 @@ class Prejoin extends StatelessWidget {
}
return;
}
- onJoinPressed?.call(roomCtx, url, token);
+ widget.onJoinPressed?.call(roomCtx, url, token);
}
@override
Widget build(BuildContext context) {
return Consumer(
- builder: (context, roomCtx, child) => !roomCtx.connected &&
- !roomCtx.connecting
+ builder: (context, roomCtx, child) => !roomCtx.connected && !roomCtx.connecting
? Center(
child: SizedBox(
width: 480,
@@ -77,8 +108,7 @@ class Prejoin extends StatelessWidget {
Container(
padding: const EdgeInsets.all(8.0),
child: CameraPreview(
- builder: (context, videoTrack) =>
- CameraPreviewWidget(track: videoTrack),
+ builder: (context, videoTrack) => CameraPreviewWidget(track: videoTrack),
),
),
SizedBox(
@@ -86,8 +116,7 @@ class Prejoin extends StatelessWidget {
child: Container(
padding: const EdgeInsets.all(8.0),
child: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceEvenly,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MicrophoneSelectButton(),
CameraSelectButton(
@@ -103,7 +132,7 @@ class Prejoin extends StatelessWidget {
child: TextInput(
onTextChanged: onTextUrlChanged,
hintText: 'Enter Livekit Server URL',
- text: url,
+ text: _url,
),
),
),
@@ -114,7 +143,7 @@ class Prejoin extends StatelessWidget {
child: TextInput(
onTextChanged: onTextTokenChanged,
hintText: 'Enter Token',
- text: token,
+ text: _token,
),
),
),
@@ -124,8 +153,7 @@ class Prejoin extends StatelessWidget {
child: Container(
padding: const EdgeInsets.all(8.0),
child: JoinButton(
- builder: (context, roomCtx, connected) =>
- JoinButtonWidget(
+ builder: (context, roomCtx, connected) => JoinButtonWidget(
roomCtx: roomCtx,
connected: connected,
onPressed: () => _handleJoinPressed(roomCtx),
diff --git a/lib/src/ui/prejoin/text_input.dart b/lib/src/ui/prejoin/text_input.dart
index 36403ca..a4d41ce 100644
--- a/lib/src/ui/prejoin/text_input.dart
+++ b/lib/src/ui/prejoin/text_input.dart
@@ -15,16 +15,12 @@
import 'package:flutter/material.dart';
class TextInput extends StatelessWidget {
- TextInput(
- {super.key,
- required this.onTextChanged,
- required this.hintText,
- String? text})
+ TextInput({super.key, required this.onTextChanged, required this.hintText, String? text})
: _textController = TextEditingController(text: text ?? '');
final TextEditingController _textController;
- final Function(String) onTextChanged;
+ final void Function(String) onTextChanged;
final String hintText;
@@ -45,8 +41,7 @@ class TextInput extends StatelessWidget {
decoration: InputDecoration(
hintText: hintText,
hintMaxLines: 1,
- contentPadding:
- const EdgeInsets.symmetric(horizontal: 8.0, vertical: 10),
+ contentPadding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 10),
hintStyle: const TextStyle(
fontSize: 16,
color: Colors.grey,
diff --git a/lib/src/ui/widgets/camera_preview.dart b/lib/src/ui/widgets/camera_preview.dart
index f528fd3..2b16208 100644
--- a/lib/src/ui/widgets/camera_preview.dart
+++ b/lib/src/ui/widgets/camera_preview.dart
@@ -42,9 +42,7 @@ class CameraPreviewWidget extends StatelessWidget {
builder: (context, constraints) => Icon(
Icons.videocam_off_outlined,
color: iconColor,
- size:
- math.min(constraints.maxHeight, constraints.maxWidth) *
- 0.33,
+ size: math.min(constraints.maxHeight, constraints.maxWidth) * 0.33,
),
),
),
diff --git a/lib/src/ui/widgets/participant/connection_quality_indicator.dart b/lib/src/ui/widgets/participant/connection_quality_indicator.dart
index 37702bf..93e9824 100644
--- a/lib/src/ui/widgets/participant/connection_quality_indicator.dart
+++ b/lib/src/ui/widgets/participant/connection_quality_indicator.dart
@@ -19,16 +19,14 @@ import 'package:livekit_client/livekit_client.dart';
class ConnectionQualityIndicatorWidget extends StatelessWidget {
final ConnectionQuality connectionQuality;
- ConnectionQualityIndicatorWidget({required this.connectionQuality});
+ const ConnectionQualityIndicatorWidget({super.key, required this.connectionQuality});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
- connectionQuality == ConnectionQuality.poor
- ? Icons.wifi_off_outlined
- : Icons.wifi,
+ connectionQuality == ConnectionQuality.poor ? Icons.wifi_off_outlined : Icons.wifi,
color: {
ConnectionQuality.excellent: Colors.green,
ConnectionQuality.good: Colors.orange,
diff --git a/lib/src/ui/widgets/participant/participant_status_bar.dart b/lib/src/ui/widgets/participant/participant_status_bar.dart
index bd1afa6..a27f9b0 100644
--- a/lib/src/ui/widgets/participant/participant_status_bar.dart
+++ b/lib/src/ui/widgets/participant/participant_status_bar.dart
@@ -43,67 +43,63 @@ class ParticipantStatusBar extends StatelessWidget {
Widget build(BuildContext context) {
return Consumer(
builder: (context, participantContext, child) {
- Debug.log(
- '===> ParticipantStatusBar for ${participantContext.name}');
- var trackCtx = Provider.of(context);
- var isScreenShare = trackCtx?.isScreenShare ?? false;
+ Debug.log('===> ParticipantStatusBar for ${participantContext.name}');
+ final trackCtx = Provider.of(context);
+ final isScreenShare = trackCtx?.isScreenShare ?? false;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 6),
color: Colors.black.withValues(alpha: 0.6),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.end,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- if (showMuteStatus && !isScreenShare)
- ParticipantMutedIndicator(
- builder: (context, isMuted) => isMuted
- ? const Icon(
- Icons.mic_off,
+ child:
+ Row(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.center, children: [
+ if (showMuteStatus && !isScreenShare)
+ ParticipantMutedIndicator(
+ builder: (context, isMuted) => isMuted
+ ? const Icon(
+ Icons.mic_off,
+ color: Colors.white54,
+ size: 20,
+ )
+ : const SizedBox(),
+ ),
+ if (isScreenShare)
+ const Icon(
+ Icons.screen_share,
+ color: Colors.white54,
+ size: 20,
+ ),
+ if (showName)
+ ParticipantName(
+ builder: (context, name) => name != null
+ ? Flexible(
+ child: Text(
+ isScreenShare ? '$name\'s screen' : name,
+ style: const TextStyle(
color: Colors.white54,
- size: 20,
- )
- : const SizedBox(),
- ),
- if (isScreenShare)
- const Icon(
- Icons.screen_share,
+ fontSize: 16,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ )
+ : Container(),
+ ),
+ if (showConnectionQuality)
+ ConnectionQualityIndicator(
+ builder: (context, connectionQuality) => ConnectionQualityIndicatorWidget(
+ connectionQuality: connectionQuality,
+ ),
+ ),
+ if (showE2EEStatus)
+ E2EEncryptionIndicator(
+ builder: (context, isEncrypted) => Padding(
+ padding: const EdgeInsets.only(left: 5),
+ child: Icon(
+ isEncrypted ? Icons.lock : Icons.lock_open,
color: Colors.white54,
size: 20,
),
- if (showName)
- ParticipantName(
- builder: (context, name) => name != null
- ? Flexible(
- child: Text(
- isScreenShare ? '$name\'s screen' : name,
- style: const TextStyle(
- color: Colors.white54,
- fontSize: 16,
- ),
- overflow: TextOverflow.ellipsis,
- ),
- )
- : Container(),
- ),
- if (showConnectionQuality)
- ConnectionQualityIndicator(
- builder: (context, connectionQuality) =>
- ConnectionQualityIndicatorWidget(
- connectionQuality: connectionQuality,
- ),
- ),
- if (showE2EEStatus)
- E2EEncryptionIndicator(
- builder: (context, isEncrypted) => Padding(
- padding: const EdgeInsets.only(left: 5),
- child: Icon(
- isEncrypted ? Icons.lock : Icons.lock_open,
- color: Colors.white54,
- size: 20,
- ),
- ),
- ),
- ]),
+ ),
+ ),
+ ]),
);
},
);
diff --git a/lib/src/ui/widgets/participant/participant_tile_widget.dart b/lib/src/ui/widgets/participant/participant_tile_widget.dart
index 156f3a5..c81e794 100644
--- a/lib/src/ui/widgets/participant/participant_tile_widget.dart
+++ b/lib/src/ui/widgets/participant/participant_tile_widget.dart
@@ -32,9 +32,8 @@ class ParticipantTileWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var trackCtx = Provider.of(context);
- Debug.log(
- '> ParticipantTile for track ${trackCtx?.sid}@${trackCtx?.participant.identity}');
+ final trackCtx = Provider.of(context);
+ Debug.log('> ParticipantTile for track ${trackCtx?.sid}@${trackCtx?.participant.identity}');
return Stack(
children: [
diff --git a/lib/src/ui/widgets/participant/transcription_widget.dart b/lib/src/ui/widgets/participant/transcription_widget.dart
index baa0457..bddf53e 100644
--- a/lib/src/ui/widgets/participant/transcription_widget.dart
+++ b/lib/src/ui/widgets/participant/transcription_widget.dart
@@ -13,6 +13,7 @@
// limitations under the License.
import 'package:flutter/material.dart';
+
import 'package:livekit_client/livekit_client.dart';
import '../../../types/transcription.dart';
@@ -20,7 +21,7 @@ import '../../../types/transcription.dart';
class TranscriptionMessageBubble extends StatelessWidget {
final TranscriptionForParticipant transcriptionForParticipant;
- TranscriptionMessageBubble({required this.transcriptionForParticipant});
+ const TranscriptionMessageBubble({super.key, required this.transcriptionForParticipant});
@override
Widget build(BuildContext context) {
@@ -51,7 +52,7 @@ class TranscriptionMessageBubble extends StatelessWidget {
}
class TranscriptionWidget extends StatelessWidget {
- TranscriptionWidget({
+ const TranscriptionWidget({
super.key,
required this.transcriptions,
this.padding,
diff --git a/lib/src/ui/widgets/room/camera_select_button.dart b/lib/src/ui/widgets/room/camera_select_button.dart
index 8916b81..8537215 100644
--- a/lib/src/ui/widgets/room/camera_select_button.dart
+++ b/lib/src/ui/widgets/room/camera_select_button.dart
@@ -14,8 +14,8 @@
import 'package:flutter/material.dart';
-import 'package:livekit_components/src/ui/widgets/theme.dart';
import '../../builder/room/media_device_select_button.dart';
+import '../../widgets/theme.dart';
import 'media_device_select_button.dart';
class CameraSelectButton extends StatelessWidget {
@@ -58,8 +58,7 @@ class CameraSelectButton extends StatelessWidget {
selectedDeviceId: deviceCtx.selectedVideoInputDeviceId,
deviceIsOpened: deviceCtx.cameraOpened,
onSelect: (device) => deviceCtx.selectVideoInput(device),
- onToggle: (enabled) =>
- enabled ? deviceCtx.enableCamera() : deviceCtx.disableCamera(),
+ onToggle: (enabled) => enabled ? deviceCtx.enableCamera() : deviceCtx.disableCamera(),
showTitleWidget: showTitleWidget,
),
);
diff --git a/lib/src/ui/widgets/room/camera_switch_button.dart b/lib/src/ui/widgets/room/camera_switch_button.dart
index 139433a..0db5818 100644
--- a/lib/src/ui/widgets/room/camera_switch_button.dart
+++ b/lib/src/ui/widgets/room/camera_switch_button.dart
@@ -28,7 +28,7 @@ class CameraSwitchButton extends StatelessWidget {
});
final CameraPosition? currentPosition;
- final Function(CameraPosition position)? onToggle;
+ final void Function(CameraPosition position)? onToggle;
final bool disabled;
final Color backgroundColor;
final Color foregroundColor;
@@ -38,25 +38,21 @@ class CameraSwitchButton extends StatelessWidget {
Widget build(BuildContext context) {
return ElevatedButton(
style: ButtonStyle(
- backgroundColor:
- WidgetStateProperty.all(backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor: WidgetStateProperty.all(backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
overlayColor: WidgetStateProperty.all(overlayColor),
- shape: WidgetStateProperty.all(const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(20.0)))),
+ shape: WidgetStateProperty.all(
+ const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20.0)))),
padding: WidgetStateProperty.all(
const EdgeInsets.all(12),
),
),
- onPressed: () => onToggle?.call(currentPosition == CameraPosition.front
- ? CameraPosition.back
- : CameraPosition.front),
+ onPressed: () =>
+ onToggle?.call(currentPosition == CameraPosition.front ? CameraPosition.back : CameraPosition.front),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- Icon(currentPosition == CameraPosition.back
- ? Icons.video_camera_back
- : Icons.video_camera_front),
+ Icon(currentPosition == CameraPosition.back ? Icons.video_camera_back : Icons.video_camera_front),
],
),
);
diff --git a/lib/src/ui/widgets/room/chat_toggle.dart b/lib/src/ui/widgets/room/chat_toggle.dart
index bc9c26d..0db78f5 100644
--- a/lib/src/ui/widgets/room/chat_toggle.dart
+++ b/lib/src/ui/widgets/room/chat_toggle.dart
@@ -20,7 +20,8 @@ import 'package:responsive_builder/responsive_builder.dart';
import '../theme.dart';
class ChatToggleWidget extends StatelessWidget {
- ChatToggleWidget({
+ const ChatToggleWidget({
+ super.key,
required this.isChatOpen,
required this.toggleChat,
this.showLabel = true,
@@ -32,7 +33,7 @@ class ChatToggleWidget extends StatelessWidget {
});
final bool isChatOpen;
- final Function(bool enabled) toggleChat;
+ final void Function(bool enabled) toggleChat;
final bool showLabel;
final Color backgroundColor;
final Color foregroundColor;
@@ -42,15 +43,12 @@ class ChatToggleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
return ElevatedButton(
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(isChatOpen
- ? selectedColor
- : backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor: WidgetStateProperty.all(isChatOpen ? selectedColor : backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
- overlayColor: WidgetStateProperty.all(
- isChatOpen ? selectedOverlayColor : backgroundColor),
+ overlayColor: WidgetStateProperty.all(isChatOpen ? selectedOverlayColor : backgroundColor),
shape: WidgetStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
diff --git a/lib/src/ui/widgets/room/chat_widget.dart b/lib/src/ui/widgets/room/chat_widget.dart
index 06600ef..19b2cc3 100644
--- a/lib/src/ui/widgets/room/chat_widget.dart
+++ b/lib/src/ui/widgets/room/chat_widget.dart
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import 'dart:async';
+
import 'package:flutter/material.dart';
import 'package:chat_bubbles/chat_bubbles.dart';
@@ -29,24 +31,22 @@ class ChatWidget extends StatelessWidget {
});
final List messages;
- final Function(String) onSend;
- final Function() onClose;
+ final void Function(String) onSend;
+ final void Function() onClose;
final ScrollController _scrollController = ScrollController();
List _buildMessages(List messages) {
- List msgWidgets = [];
+ final msgWidgets = [];
int lastTimestamp = 0;
String lastPartcipantId = '';
for (ChatMessage msg in messages) {
if (DateTime.fromMillisecondsSinceEpoch(msg.timestamp)
- .difference(
- DateTime.fromMillisecondsSinceEpoch(lastTimestamp))
+ .difference(DateTime.fromMillisecondsSinceEpoch(lastTimestamp))
.inMinutes >
1 ||
lastPartcipantId != msg.participant?.identity) {
msgWidgets.add(CustomDateNameChip(
- name: msg.participant?.name ?? 'Unknown',
- date: DateTime.fromMillisecondsSinceEpoch(msg.timestamp)));
+ name: msg.participant?.name ?? 'Unknown', date: DateTime.fromMillisecondsSinceEpoch(msg.timestamp)));
}
msgWidgets.add(BubbleNormal(
text: msg.message,
@@ -62,8 +62,8 @@ class ChatWidget extends StatelessWidget {
}
void scrollToBottom() {
- _scrollController.animateTo(_scrollController.position.maxScrollExtent,
- duration: const Duration(milliseconds: 300), curve: Curves.easeOut);
+ unawaited(_scrollController.animateTo(_scrollController.position.maxScrollExtent,
+ duration: const Duration(milliseconds: 300), curve: Curves.easeOut));
}
@override
@@ -83,10 +83,7 @@ class ChatWidget extends StatelessWidget {
child: Center(
child: Text(
'Messages',
- style: TextStyle(
- color: Colors.white,
- fontSize: 20.0,
- fontWeight: FontWeight.bold),
+ style: TextStyle(color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
),
diff --git a/lib/src/ui/widgets/room/control_bar.dart b/lib/src/ui/widgets/room/control_bar.dart
index 21c96dc..a8abdb3 100644
--- a/lib/src/ui/widgets/room/control_bar.dart
+++ b/lib/src/ui/widgets/room/control_bar.dart
@@ -16,13 +16,13 @@ import 'package:flutter/material.dart';
import 'package:livekit_client/livekit_client.dart';
-import 'package:livekit_components/src/ui/builder/room/camera_switch.dart';
-import 'package:livekit_components/src/ui/widgets/room/speaker_switch_button.dart';
+import '../../builder/room/camera_switch.dart';
import '../../builder/room/chat_toggle.dart';
import '../../builder/room/disconnect_button.dart';
import '../../builder/room/media_device_select_button.dart';
import '../../builder/room/screenshare_toggle.dart';
import '../../builder/room/speaker_switch.dart';
+import '../../widgets/room/speaker_switch_button.dart';
import '../theme.dart';
import 'camera_switch_button.dart';
import 'chat_toggle.dart';
@@ -94,14 +94,11 @@ class ControlBar extends StatelessWidget {
selectedDeviceId: deviceCtx.selectedAudioInputDeviceId,
deviceIsOpened: deviceCtx.microphoneOpened,
onSelect: (device) => deviceCtx.selectAudioInput(device),
- onToggle: (enabled) => enabled
- ? deviceCtx.enableMicrophone()
- : deviceCtx.disableMicrophone(),
+ onToggle: (enabled) => enabled ? deviceCtx.enableMicrophone() : deviceCtx.disableMicrophone(),
showTitleWidget: showTitleWidget,
),
),
- if (audioOutput &&
- (lkPlatformIsDesktop() || lkPlatformIs(PlatformType.web)))
+ if (audioOutput && (lkPlatformIsDesktop() || lkPlatformIs(PlatformType.web)))
MediaDeviceSelectButton(
builder: (context, roomCtx, deviceCtx) => MediaDeviceSelectWidget(
titleWidget: Text(
@@ -142,32 +139,25 @@ class ControlBar extends StatelessWidget {
selectedDeviceId: deviceCtx.selectedVideoInputDeviceId,
deviceIsOpened: deviceCtx.cameraOpened,
onSelect: (device) => deviceCtx.selectVideoInput(device),
- onToggle: (enabled) => enabled
- ? deviceCtx.enableCamera()
- : deviceCtx.disableCamera(),
+ onToggle: (enabled) => enabled ? deviceCtx.enableCamera() : deviceCtx.disableCamera(),
showTitleWidget: showTitleWidget,
),
),
if (isMobile && microphone)
SpeakerSwitch(
- builder: (context, roomCtx, deviceCtx, isSpeakerOn) =>
- SpeakerSwitchButton(
+ builder: (context, roomCtx, deviceCtx, isSpeakerOn) => SpeakerSwitchButton(
isSpeakerOn: isSpeakerOn ?? false,
- onToggle: (speakerOn) =>
- deviceCtx.setSpeakerphoneOn(speakerOn),
+ onToggle: (speakerOn) => deviceCtx.setSpeakerphoneOn(speakerOn),
)),
if (isMobile && camera)
CameraSwitch(
- builder: (context, roomCtx, deviceCtx, position) =>
- CameraSwitchButton(
+ builder: (context, roomCtx, deviceCtx, position) => CameraSwitchButton(
currentPosition: position,
- onToggle: (newPosition) =>
- deviceCtx.switchCameraPosition(newPosition),
+ onToggle: (newPosition) => deviceCtx.switchCameraPosition(newPosition),
)),
if (screenShare)
ScreenShareToggle(
- builder: (context, roomCtx, deviceCtx, screenShareEnabled) =>
- ScreenShareToggleWidget(
+ builder: (context, roomCtx, deviceCtx, screenShareEnabled) => ScreenShareToggleWidget(
roomCtx: roomCtx,
deviceCtx: deviceCtx,
screenShareEnabled: screenShareEnabled,
diff --git a/lib/src/ui/widgets/room/disconnect_button.dart b/lib/src/ui/widgets/room/disconnect_button.dart
index 6d9c524..9388b0e 100644
--- a/lib/src/ui/widgets/room/disconnect_button.dart
+++ b/lib/src/ui/widgets/room/disconnect_button.dart
@@ -45,18 +45,16 @@ class DisconnectButtonWidget extends StatelessWidget {
final Color selectedColor;
final Color selectedOverlayColor;
- final Function()? onPressed;
+ final void Function()? onPressed;
@override
Widget build(BuildContext context) {
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
return ElevatedButton(
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(
- connected ? selectedColor : backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor: WidgetStateProperty.all(connected ? selectedColor : backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
- overlayColor: WidgetStateProperty.all(
- connected ? selectedOverlayColor : overlayColor),
+ overlayColor: WidgetStateProperty.all(connected ? selectedOverlayColor : overlayColor),
shape: WidgetStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
@@ -70,8 +68,13 @@ class DisconnectButtonWidget extends StatelessWidget {
: const EdgeInsets.fromLTRB(12, 20, 12, 20),
),
),
- onPressed: () =>
- onPressed?.call() ?? connected ? roomCtx.disconnect() : null,
+ onPressed: () async {
+ if (onPressed != null) {
+ onPressed!();
+ } else if (connected) {
+ await roomCtx.disconnect();
+ }
+ },
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
diff --git a/lib/src/ui/widgets/room/join_button.dart b/lib/src/ui/widgets/room/join_button.dart
index 2f1baf0..0d69dfb 100644
--- a/lib/src/ui/widgets/room/join_button.dart
+++ b/lib/src/ui/widgets/room/join_button.dart
@@ -18,7 +18,7 @@ import '../../../context/room_context.dart';
import '../theme.dart';
class JoinButtonWidget extends StatelessWidget {
- JoinButtonWidget({
+ const JoinButtonWidget({
Key? key,
required this.roomCtx,
required this.connected,
@@ -30,9 +30,9 @@ class JoinButtonWidget extends StatelessWidget {
this.disabledOverlayColor = LKColors.lkLightBlue,
}) : super(key: key);
- RoomContext roomCtx;
- bool connected;
- final Function()? onPressed;
+ final RoomContext roomCtx;
+ final bool connected;
+ final void Function()? onPressed;
final Color backgroundColor;
final Color foregroundColor;
@@ -49,11 +49,9 @@ class JoinButtonWidget extends StatelessWidget {
? roomCtx.connect()
: null,
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(
- connected ? disabledColor : backgroundColor),
+ backgroundColor: WidgetStateProperty.all(connected ? disabledColor : backgroundColor),
foregroundColor: WidgetStateProperty.all(foregroundColor),
- overlayColor: WidgetStateProperty.all(
- connected ? overlayColor : disabledOverlayColor),
+ overlayColor: WidgetStateProperty.all(connected ? overlayColor : disabledOverlayColor),
shape: WidgetStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
diff --git a/lib/src/ui/widgets/room/media_device_select_button.dart b/lib/src/ui/widgets/room/media_device_select_button.dart
index ca6baaa..1b2a815 100644
--- a/lib/src/ui/widgets/room/media_device_select_button.dart
+++ b/lib/src/ui/widgets/room/media_device_select_button.dart
@@ -50,28 +50,24 @@ class MediaDeviceSelectWidget extends StatelessWidget {
final Color foregroundColor;
final String? selectedDeviceId;
final List deviceList;
- final Function(MediaDevice device)? onSelect;
- final Function(bool enabled)? onToggle;
+ final void Function(MediaDevice device)? onSelect;
+ final void Function(bool enabled)? onToggle;
final bool toggleAvailable;
final bool defaultSelectable;
@override
Widget build(BuildContext context) {
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
return Row(mainAxisSize: MainAxisSize.min, children: [
ElevatedButton(
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(deviceIsOpened
- ? selectedColor
- : backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor:
+ WidgetStateProperty.all(deviceIsOpened ? selectedColor : backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
- overlayColor: WidgetStateProperty.all(
- deviceIsOpened ? selectedOverlayColor : backgroundColor),
+ overlayColor: WidgetStateProperty.all(deviceIsOpened ? selectedOverlayColor : backgroundColor),
shadowColor: WidgetStateProperty.all(Colors.transparent),
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(20.0),
- bottomLeft: Radius.circular(20.0)))),
+ borderRadius: BorderRadius.only(topLeft: Radius.circular(20.0), bottomLeft: Radius.circular(20.0)))),
padding: WidgetStateProperty.all(
(lkPlatformIsMobile() || lkPlatformIsWebMobile())
? const EdgeInsets.all(12)
@@ -82,13 +78,9 @@ class MediaDeviceSelectWidget extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- Icon(deviceIsOpened || defaultSelectable ? iconOn : iconOff,
- color: iconColor),
+ Icon(deviceIsOpened || defaultSelectable ? iconOn : iconOff, color: iconColor),
const SizedBox(width: 2),
- if (titleWidget != null &&
- (deviceScreenType != DeviceScreenType.mobile ||
- showTitleWidget))
- titleWidget!,
+ if (titleWidget != null && (deviceScreenType != DeviceScreenType.mobile || showTitleWidget)) titleWidget!,
],
),
),
@@ -100,19 +92,14 @@ class MediaDeviceSelectWidget extends StatelessWidget {
Icons.arrow_drop_down,
color: iconColor,
),
- offset: Offset(
- 0, ((deviceList.isNotEmpty ? deviceList.length : 1) * -55.0)),
+ offset: Offset(0, ((deviceList.isNotEmpty ? deviceList.length : 1) * -55.0)),
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(deviceIsOpened
- ? selectedColor
- : backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor:
+ WidgetStateProperty.all(deviceIsOpened ? selectedColor : backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
- overlayColor: WidgetStateProperty.all(
- deviceIsOpened ? selectedOverlayColor : backgroundColor),
+ overlayColor: WidgetStateProperty.all(deviceIsOpened ? selectedOverlayColor : backgroundColor),
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
- borderRadius: BorderRadius.only(
- topRight: Radius.circular(20.0),
- bottomRight: Radius.circular(20.0)))),
+ borderRadius: BorderRadius.only(topRight: Radius.circular(20.0), bottomRight: Radius.circular(20.0)))),
),
enabled: deviceIsOpened || defaultSelectable,
itemBuilder: (BuildContext context) {
@@ -127,9 +114,7 @@ class MediaDeviceSelectWidget extends StatelessWidget {
leading: (device.deviceId == selectedDeviceId)
? Icon(
Icons.check_box_outlined,
- color: (device.deviceId == selectedDeviceId)
- ? selectedColor
- : backgroundColor,
+ color: (device.deviceId == selectedDeviceId) ? selectedColor : backgroundColor,
)
: Icon(
Icons.check_box_outline_blank,
diff --git a/lib/src/ui/widgets/room/microphone_select_button.dart b/lib/src/ui/widgets/room/microphone_select_button.dart
index f8458a6..cba27ec 100644
--- a/lib/src/ui/widgets/room/microphone_select_button.dart
+++ b/lib/src/ui/widgets/room/microphone_select_button.dart
@@ -58,9 +58,7 @@ class MicrophoneSelectButton extends StatelessWidget {
selectedDeviceId: deviceCtx.selectedAudioInputDeviceId,
deviceIsOpened: deviceCtx.microphoneOpened,
onSelect: (device) => deviceCtx.selectAudioInput(device),
- onToggle: (enabled) => enabled
- ? deviceCtx.enableMicrophone()
- : deviceCtx.disableMicrophone(),
+ onToggle: (enabled) => enabled ? deviceCtx.enableMicrophone() : deviceCtx.disableMicrophone(),
showTitleWidget: showtitleWidget,
),
);
diff --git a/lib/src/ui/widgets/room/screenshare_toggle.dart b/lib/src/ui/widgets/room/screenshare_toggle.dart
index 18b4809..cc7dc00 100644
--- a/lib/src/ui/widgets/room/screenshare_toggle.dart
+++ b/lib/src/ui/widgets/room/screenshare_toggle.dart
@@ -47,15 +47,13 @@ class ScreenShareToggleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var deviceScreenType = getDeviceType(MediaQuery.of(context).size);
+ final deviceScreenType = getDeviceType(MediaQuery.of(context).size);
return ElevatedButton(
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.all(screenShareEnabled
- ? selectedColor
- : backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor:
+ WidgetStateProperty.all(screenShareEnabled ? selectedColor : backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
- overlayColor: WidgetStateProperty.all(
- screenShareEnabled ? selectedOverlayColor : overlayColor),
+ overlayColor: WidgetStateProperty.all(screenShareEnabled ? selectedOverlayColor : overlayColor),
shape: WidgetStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
@@ -69,15 +67,11 @@ class ScreenShareToggleWidget extends StatelessWidget {
: const EdgeInsets.fromLTRB(12, 20, 12, 20),
),
),
- onPressed: () => screenShareEnabled
- ? deviceCtx.disableScreenShare()
- : deviceCtx.enableScreenShare(context),
+ onPressed: () => screenShareEnabled ? deviceCtx.disableScreenShare() : deviceCtx.enableScreenShare(context),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- Icon(screenShareEnabled
- ? Icons.stop_screen_share_outlined
- : Icons.screen_share_outlined),
+ Icon(screenShareEnabled ? Icons.stop_screen_share_outlined : Icons.screen_share_outlined),
const SizedBox(width: 2),
if (deviceScreenType != DeviceScreenType.mobile || showLabel)
Text(
diff --git a/lib/src/ui/widgets/room/speaker_switch_button.dart b/lib/src/ui/widgets/room/speaker_switch_button.dart
index a35be40..311aac8 100644
--- a/lib/src/ui/widgets/room/speaker_switch_button.dart
+++ b/lib/src/ui/widgets/room/speaker_switch_button.dart
@@ -26,7 +26,7 @@ class SpeakerSwitchButton extends StatelessWidget {
});
final bool isSpeakerOn;
- final Function(bool speakerOn)? onToggle;
+ final void Function(bool speakerOn)? onToggle;
final bool disabled;
final Color backgroundColor;
@@ -36,12 +36,11 @@ class SpeakerSwitchButton extends StatelessWidget {
Widget build(BuildContext context) {
return ElevatedButton(
style: ButtonStyle(
- backgroundColor:
- WidgetStateProperty.all(backgroundColor.withValues(alpha: 0.9)),
+ backgroundColor: WidgetStateProperty.all(backgroundColor.withValues(alpha: 0.9)),
foregroundColor: WidgetStateProperty.all(foregroundColor),
overlayColor: WidgetStateProperty.all(overlayColor),
- shape: WidgetStateProperty.all(const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(20.0)))),
+ shape: WidgetStateProperty.all(
+ const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20.0)))),
padding: WidgetStateProperty.all(const EdgeInsets.all(12)),
),
onPressed: () => onToggle?.call(!isSpeakerOn),
diff --git a/lib/src/ui/widgets/theme.dart b/lib/src/ui/widgets/theme.dart
index 6dc7cfa..39c803b 100644
--- a/lib/src/ui/widgets/theme.dart
+++ b/lib/src/ui/widgets/theme.dart
@@ -48,14 +48,12 @@ class LiveKitTheme {
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
- textStyle:
- WidgetStateProperty.all(GoogleFonts.montserrat(
+ textStyle: WidgetStateProperty.all(GoogleFonts.montserrat(
fontSize: 15,
)),
- padding: WidgetStateProperty.all(
- const EdgeInsets.symmetric(vertical: 20, horizontal: 25)),
- shape: WidgetStateProperty.all(
- RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
+ padding: WidgetStateProperty.all(const EdgeInsets.symmetric(vertical: 20, horizontal: 25)),
+ shape:
+ WidgetStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
foregroundColor: WidgetStateProperty.all(Colors.white),
// backgroundColor: WidgetStateProperty.all(accentColor),
backgroundColor: WidgetStateProperty.resolveWith((states) {
diff --git a/lib/src/ui/widgets/toast.dart b/lib/src/ui/widgets/toast.dart
index 2629f4d..0ad51e3 100644
--- a/lib/src/ui/widgets/toast.dart
+++ b/lib/src/ui/widgets/toast.dart
@@ -39,20 +39,19 @@ class ToastWidget extends StatefulWidget {
ToastState createState() => ToastState();
}
-class ToastState extends State
- with SingleTickerProviderStateMixin {
+class ToastState extends State with SingleTickerProviderStateMixin {
AnimationController? _animationController;
- late Animation _fadeAnimation;
+ late Animation _fadeAnimation;
Timer? _timer;
ConnectionState _connectionState = ConnectionState.disconnected;
- showIt() {
- _animationController!.forward();
+ void showIt() {
+ unawaited(_animationController?.forward());
}
- hideIt() {
- _animationController!.reverse();
+ void hideIt() {
+ unawaited(_animationController?.reverse());
_timer?.cancel();
_timer = null;
}
@@ -71,8 +70,7 @@ class ToastState extends State
vsync: this,
duration: widget.fadeDuration,
);
- _fadeAnimation =
- CurvedAnimation(parent: _animationController!, curve: Curves.easeIn);
+ _fadeAnimation = CurvedAnimation(parent: _animationController!, curve: Curves.easeIn);
super.initState();
}
@@ -93,8 +91,7 @@ class ToastState extends State
@override
Widget build(BuildContext context) {
return Consumer(
- builder: (context, roomCtx, child) =>
- Selector(
+ builder: (context, roomCtx, child) => Selector(
selector: (context, connectionState) => roomCtx.connectionState,
builder: (context, connectionState, child) {
if (connectionState != _connectionState) {
@@ -107,7 +104,7 @@ class ToastState extends State
child: IgnorePointer(
ignoring: widget.ignorePointer,
child: FadeTransition(
- opacity: _fadeAnimation as Animation,
+ opacity: _fadeAnimation,
child: Center(
child: Material(
color: Colors.transparent,
diff --git a/lib/src/ui/widgets/track/audio_visualizer_widget.dart b/lib/src/ui/widgets/track/audio_visualizer_widget.dart
index fb1234c..f1fe80a 100644
--- a/lib/src/ui/widgets/track/audio_visualizer_widget.dart
+++ b/lib/src/ui/widgets/track/audio_visualizer_widget.dart
@@ -1,7 +1,9 @@
+import 'dart:async';
import 'dart:math' show max;
-import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
+
+import 'package:collection/collection.dart';
import 'package:livekit_client/livekit_client.dart' as sdk;
import 'package:provider/provider.dart';
@@ -133,8 +135,7 @@ class _SoundWaveformWidgetState extends State with SingleTi
if (didUpdateParams) {
// Re-attach listeners
- _detachListeners();
- _attachListeners();
+ unawaited(_detachListeners().then((_) => _attachListeners()));
}
}
@@ -198,20 +199,21 @@ class _SoundWaveformWidgetState extends State with SingleTi
_controller = AnimationController(
duration: Duration(milliseconds: widget.options.durationInMilliseconds),
vsync: this,
- )..repeat(reverse: true);
+ );
+ unawaited(_controller.repeat(reverse: true));
_pulseAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
- _attachListeners();
+ unawaited(_attachListeners());
}
@override
void dispose() {
_controller.dispose();
- _detachListeners();
+ unawaited(_detachListeners());
super.dispose();
}
diff --git a/lib/src/ui/widgets/track/focus_toggle.dart b/lib/src/ui/widgets/track/focus_toggle.dart
index d64565e..868409e 100644
--- a/lib/src/ui/widgets/track/focus_toggle.dart
+++ b/lib/src/ui/widgets/track/focus_toggle.dart
@@ -31,14 +31,13 @@ class FocusToggle extends StatelessWidget {
@override
Widget build(BuildContext context) {
final roomCtx = context.read();
- var trackCtx = Provider.of(context);
+ final trackCtx = Provider.of(context);
final String? sid = trackCtx?.sid;
Debug.log('===> FocusButton for $sid');
if (trackCtx == null) {
return const SizedBox();
}
- var shouldShowBackToGridView =
- roomCtx.pinnedTracks.contains(sid) && sid == roomCtx.pinnedTracks.first;
+ final shouldShowBackToGridView = roomCtx.pinnedTracks.contains(sid) && sid == roomCtx.pinnedTracks.first;
if (shouldShowBackToGridView && !showBackToGridView) {
return const SizedBox();
@@ -47,8 +46,7 @@ class FocusToggle extends StatelessWidget {
return Padding(
padding: const EdgeInsets.all(2),
child: IconButton(
- icon: Icon(
- shouldShowBackToGridView ? Icons.grid_view : Icons.open_in_full),
+ icon: Icon(shouldShowBackToGridView ? Icons.grid_view : Icons.open_in_full),
color: Colors.white70,
onPressed: () {
if (sid == null) {
diff --git a/lib/src/ui/widgets/track/no_track_widget.dart b/lib/src/ui/widgets/track/no_track_widget.dart
index 79ff023..4ae83ee 100644
--- a/lib/src/ui/widgets/track/no_track_widget.dart
+++ b/lib/src/ui/widgets/track/no_track_widget.dart
@@ -34,7 +34,7 @@ class NoTrackWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var trackCtx = Provider.of(context);
+ final trackCtx = Provider.of(context);
final String? sid = trackCtx?.sid;
Debug.log('===> NoTrackWidget for $sid');
diff --git a/lib/src/ui/widgets/track/track_stats_widget.dart b/lib/src/ui/widgets/track/track_stats_widget.dart
index 815f46c..3d6732a 100644
--- a/lib/src/ui/widgets/track/track_stats_widget.dart
+++ b/lib/src/ui/widgets/track/track_stats_widget.dart
@@ -9,18 +9,16 @@ class TrackStatsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var trackCtx = Provider.of(context);
+ final trackCtx = Provider.of(context);
if (trackCtx == null) {
return const SizedBox();
}
return Consumer(
- builder: (context, trackCtx, child) =>
- Selector>(
+ builder: (context, trackCtx, child) => Selector>(
selector: (context, trackCtx) => trackCtx.stats,
- builder:
- (BuildContext context, Map stats, Widget? child) {
+ builder: (BuildContext context, Map stats, Widget? child) {
return Center(
child: Stack(
children: [
@@ -33,18 +31,15 @@ class TrackStatsWidget extends StatelessWidget {
),
child: Column(children: [
Text('${trackCtx.isVideo ? 'video' : 'audio'} stats',
- style: const TextStyle(
- fontWeight: FontWeight.bold, fontSize: 16)),
- ...stats.entries
- .map((e) => Text('${e.key}: ${e.value}')),
+ style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
+ ...stats.entries.map((e) => Text('${e.key}: ${e.value}')),
]),
)
: const SizedBox(),
Container(
padding: const EdgeInsets.all(2),
child: IconButton(
- icon: Icon(
- trackCtx.showStatistics ? Icons.close : Icons.info),
+ icon: Icon(trackCtx.showStatistics ? Icons.close : Icons.info),
color: Colors.white70,
onPressed: () {
// show stats
diff --git a/lib/src/ui/widgets/track/video_track_widget.dart b/lib/src/ui/widgets/track/video_track_widget.dart
index 8b9203e..00469d2 100644
--- a/lib/src/ui/widgets/track/video_track_widget.dart
+++ b/lib/src/ui/widgets/track/video_track_widget.dart
@@ -13,6 +13,7 @@
// limitations under the License.
import 'package:flutter/material.dart';
+
import 'package:livekit_client/livekit_client.dart' as sdk;
import 'package:provider/provider.dart';
@@ -37,7 +38,7 @@ class VideoTrackWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- var trackCtx = Provider.of(context);
+ final trackCtx = Provider.of(context);
final String? sid = trackCtx?.sid;
Debug.log('===> VideoTrackWidget for $sid');
diff --git a/maintenance.sh b/maintenance.sh
new file mode 100755
index 0000000..3d31215
--- /dev/null
+++ b/maintenance.sh
@@ -0,0 +1,3 @@
+dart pub run import_sorter:main --no-comments
+dart format . -l 120
+dart pub global run dependency_validator
diff --git a/pubspec.yaml b/pubspec.yaml
index d72c2ce..3e36d96 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -4,27 +4,26 @@ version: 1.2.2+hotfix.1
homepage: https://github.com/livekit/components-flutter
environment:
- sdk: ^3.5.1
+ sdk: ">=3.6.0 <4.0.0"
flutter: ">=1.17.0"
dependencies:
- chat_bubbles: ^1.6.0
- collection: ^1.19.0
flutter:
sdk: flutter
+ flutter_webrtc: 1.2.0
+ livekit_client: ^2.4.9
+ chat_bubbles: ^1.6.0
+ collection: ^1.19.0
flutter_background: ^1.3.0+1
- flutter_webrtc: ^1.0.0
google_fonts: ^6.2.1
- http: ^1.2.2
intl: ^0.20.2
- livekit_client: ^2.4.9
provider: ^6.1.2
responsive_builder: ^0.7.1
dev_dependencies:
flutter_test:
sdk: flutter
- flutter_lints: ^4.0.0
+ flutter_lints: ^6.0.0
import_sorter: ^4.6.0
topics:
@@ -33,39 +32,3 @@ topics:
- livestream
- conference
- agent
-# For information on the generic Dart part of this file, see the
-# following page: https://dart.dev/tools/pub/pubspec
-
-# The following section is specific to Flutter packages.
-# flutter:
-
-# To add assets to your package, add an assets section, like this:
-# assets:
-# - images/a_dot_burr.jpeg
-# - images/a_dot_ham.jpeg
-#
-# For details regarding assets in packages, see
-# https://flutter.dev/to/asset-from-package
-#
-# An image asset can refer to one or more resolution-specific "variants", see
-# https://flutter.dev/to/resolution-aware-images
-
-# To add custom fonts to your package, add a fonts section here,
-# in this "flutter" section. Each entry in this list should have a
-# "family" key with the font family name, and a "fonts" key with a
-# list giving the asset and other descriptors for the font. For
-# example:
-# fonts:
-# - family: Schyler
-# fonts:
-# - asset: fonts/Schyler-Regular.ttf
-# - asset: fonts/Schyler-Italic.ttf
-# style: italic
-# - family: Trajan Pro
-# fonts:
-# - asset: fonts/TrajanPro.ttf
-# - asset: fonts/TrajanPro_Bold.ttf
-# weight: 700
-#
-# For details regarding fonts in packages, see
-# https://flutter.dev/to/font-from-package