Skip to content

Commit 75b1407

Browse files
Brazolxsahil03x
andauthored
feat(ui): livestream player improvements (#1118)
* livestream player improvements * tweaks * option to hide list of recordings * Update packages/stream_video_flutter/lib/src/livestream/livestream_player.dart --------- Co-authored-by: Sahil Kumar <[email protected]>
1 parent ad461d0 commit 75b1407

File tree

6 files changed

+640
-383
lines changed

6 files changed

+640
-383
lines changed

packages/stream_video_flutter/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## Unreleased
2+
3+
#### LivestreamPlayer Improvements
4+
* Added support for Picture in Picture (PiP) mode, configurable via the `pictureInPictureConfiguration` parameter. For platform-specific setup, refer to the [documentation](https://getstream.io/video/docs/flutter/advanced/picture_in_picture/).
5+
* Introduced the `joinBehaviour` parameter, allowing control over whether and when the `LivestreamPlayer` automatically connects the user to a call.
6+
* Added the `showRecordingsWhenEnded` parameter to `LivestreamPlayer`, which enables you to show or hide the recordings list in the default livestream ended UI.
7+
* Refactored `LivestreamPlayer` to leverage `call.partialState` for more efficient state management. New builder methods have been introduced to accommodate this change, and some previous builder methods are now deprecated.
8+
19
## 1.0.0
210

311
### 🚧 Breaking changes

packages/stream_video_flutter/lib/src/livestream/livestream_backstage_content.dart

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import '../l10n/localization_extension.dart';
77
class LivestreamBackstageContent extends StatefulWidget {
88
const LivestreamBackstageContent({
99
super.key,
10-
required this.callState,
10+
required this.call,
1111
});
1212

13-
final CallState callState;
13+
final Call call;
1414

1515
@override
1616
State<LivestreamBackstageContent> createState() =>
@@ -20,39 +20,42 @@ class LivestreamBackstageContent extends StatefulWidget {
2020
class _LivestreamBackstageContentState
2121
extends State<LivestreamBackstageContent> {
2222
Timer? _timer;
23+
StreamSubscription<DateTime?>? _startsAtSubscription;
2324
Duration _timeLeft = Duration.zero;
2425

2526
@override
2627
void initState() {
2728
super.initState();
2829

29-
_updateTimeLeft();
3030
_startTimer();
31+
32+
_startsAtSubscription = widget.call
33+
.partialState(
34+
(state) => state.startsAt,
35+
)
36+
.listen(_updateTimeLeft);
3137
}
3238

3339
@override
3440
void dispose() {
3541
_timer?.cancel();
42+
_startsAtSubscription?.cancel();
3643
super.dispose();
3744
}
3845

39-
@override
40-
void didUpdateWidget(LivestreamBackstageContent oldWidget) {
41-
super.didUpdateWidget(oldWidget);
42-
if (oldWidget.callState.startsAt != widget.callState.startsAt) {
43-
_updateTimeLeft();
44-
}
45-
}
46-
4746
void _startTimer() {
4847
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
49-
_updateTimeLeft();
48+
setState(() {
49+
_timeLeft -= const Duration(seconds: 1);
50+
if (_timeLeft <= Duration.zero) {
51+
_timeLeft = Duration.zero;
52+
_timer?.cancel();
53+
}
54+
});
5055
});
5156
}
5257

53-
void _updateTimeLeft() {
54-
final startsAt = widget.callState.startsAt;
55-
58+
void _updateTimeLeft(DateTime? startsAt) {
5659
if (startsAt != null) {
5760
final now = DateTime.now();
5861
if (startsAt.isAfter(now)) {
@@ -92,40 +95,47 @@ class _LivestreamBackstageContentState
9295
final liveTheme = theme.livestreamTheme;
9396
final translations = context.translations;
9497

95-
final participants = widget.callState.callParticipants;
96-
final startsAt = widget.callState.startsAt;
97-
98-
return Scaffold(
99-
backgroundColor: theme.colorTheme.livestreamBackground,
100-
body: Center(
101-
child: Column(
102-
mainAxisAlignment: MainAxisAlignment.center,
103-
children: [
104-
Text(
105-
startsAt == null || _timeLeft <= Duration.zero
106-
? translations.livestreamBackstageStartingSoon
107-
: translations.livestreamBackstageStartingIn,
108-
style: liveTheme.backstageTextStyle,
109-
),
110-
if (startsAt != null && _timeLeft > Duration.zero) ...[
111-
const SizedBox(height: 12),
112-
Text(
113-
_formatDuration(_timeLeft),
114-
style: liveTheme.backstageCounterTextStyle,
115-
),
116-
],
117-
if (participants.isNotEmpty) ...[
118-
const SizedBox(height: 12),
119-
Text(
120-
translations.livestreamBackstageParticipants(
121-
participants.length,
98+
return PartialCallStateBuilder(
99+
call: widget.call,
100+
selector: (state) =>
101+
(callParticipants: state.callParticipants, startsAt: state.startsAt),
102+
builder: (context, callData) {
103+
final participants = callData.callParticipants;
104+
final startsAt = callData.startsAt;
105+
106+
return Scaffold(
107+
backgroundColor: theme.colorTheme.livestreamBackground,
108+
body: Center(
109+
child: Column(
110+
mainAxisAlignment: MainAxisAlignment.center,
111+
children: [
112+
Text(
113+
startsAt == null || _timeLeft <= Duration.zero
114+
? translations.livestreamBackstageStartingSoon
115+
: translations.livestreamBackstageStartingIn,
116+
style: liveTheme.backstageTextStyle,
122117
),
123-
style: liveTheme.backstageParticipantsTextStyle,
124-
),
125-
],
126-
],
127-
),
128-
),
118+
if (startsAt != null && _timeLeft > Duration.zero) ...[
119+
const SizedBox(height: 12),
120+
Text(
121+
_formatDuration(_timeLeft),
122+
style: liveTheme.backstageCounterTextStyle,
123+
),
124+
],
125+
if (participants.isNotEmpty) ...[
126+
const SizedBox(height: 12),
127+
Text(
128+
translations.livestreamBackstageParticipants(
129+
participants.length,
130+
),
131+
style: liveTheme.backstageParticipantsTextStyle,
132+
),
133+
],
134+
],
135+
),
136+
),
137+
);
138+
},
129139
);
130140
}
131141
}

0 commit comments

Comments
 (0)