Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 11 additions & 16 deletions dogfooding/lib/screens/call_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import '../core/repos/app_preferences.dart';
import '../core/repos/user_chat_repository.dart';
import '../di/injector.dart';
import '../utils/feedback_dialog.dart';
import '../widgets/badged_call_option.dart';
import '../widgets/call_connection_banner.dart';
import '../widgets/closed_captions_widget.dart';
import '../widgets/e2ee_key_notification.dart';
Expand Down Expand Up @@ -422,14 +421,12 @@ class _CallScreenState extends State<CallScreen>
Widget _participantsControl(Call call) => PartialCallStateBuilder(
call: call,
selector: (state) => state.callParticipants.length,
builder: (context, count) => BadgedCallOption(
badgeCount: count == 0 ? null : count,
callControlOption: CallFeatureButton(
icon: Icon(context.streamIcons.usersFill),
tooltip: 'Participants',
selected: _openPanel == CallSidePanel.participants,
onPressed: () => _togglePanel(CallSidePanel.participants),
),
builder: (context, count) => CallFeatureButton(
icon: Icon(context.streamIcons.usersFill),
tooltip: 'Participants',
selected: _openPanel == CallSidePanel.participants,
badge: CallControlNotificationBadge(count: count, type: .neutral),
onPressed: () => _togglePanel(CallSidePanel.participants),
),
);

Expand Down Expand Up @@ -774,13 +771,11 @@ class __ShowChatButtonState extends State<_ShowChatButton> {

@override
Widget build(BuildContext context) {
return BadgedCallOption(
callControlOption: CallFeatureButton(
icon: Icon(context.streamIcons.messageBubblesFill),
selected: widget.selected,
onPressed: widget.channel != null ? widget.onPressed : null,
),
badgeCount: _unreadCount == 0 ? null : _unreadCount,
return CallFeatureButton(
icon: Icon(context.streamIcons.messageBubblesFill),
selected: widget.selected,
badge: CallControlNotificationBadge(count: _unreadCount),
onPressed: widget.channel != null ? widget.onPressed : null,
);
}
}
31 changes: 0 additions & 31 deletions dogfooding/lib/widgets/badged_call_option.dart

This file was deleted.

6 changes: 4 additions & 2 deletions packages/stream_video_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- Added `ViewportVisibilityReporter`, which measures how much of its child is on screen and reports it to `Call.viewportVisibility`.
- Redesigned the incoming and outgoing ringing screens. Both are an avatar over a name and a status line, with the call controls below. The incoming screen sits on the app surface; the outgoing one is drawn on top of the caller's own camera, blurred behind a scrim, and falls back to the flat scrim when the camera is off.
- Added `CallRingingButton`, the 64px round button answering, declining and cancelling are drawn with. It is `CallControlButton` at the size the ringing designs give it, optionally with a label under it.
- Added `CallControlNotificationBadge`, a `CallControlBadge` that draws a count as a `StreamBadgeNotification`, optionally in a `StreamBadgeNotificationType`.
- `CallControlButton` takes a `themeStyle`, handed to the button as `props.themeStyle`. It resolves after the ambient `StreamButtonTheme`, so it reaches that one button — where a nested `StreamButtonTheme` would be dropped for the `positive` tone, which brings one of its own.
- Added `StreamRingingCameraController`, which opens the camera the outgoing screen previews and hands it to the call as `TrackOption.provided`, so the call carries on with the camera the caller was already previewing rather than opening a second one. `StreamOutgoingCallContent` makes one unless it is given one.
- Added `StreamIncomingCallThemeData` and `StreamOutgoingCallThemeData` on `StreamVideoTheme`, with `StreamIncomingCallTheme` and `StreamOutgoingCallTheme` to restyle either over a subtree. Both carry a `StreamRingingCallStyle`, which `StreamIncomingCallContent.style` and `StreamOutgoingCallContent.style` override per call site.
Expand Down Expand Up @@ -72,7 +73,7 @@
onPressed: toggleScreenShare,
)
```
- Both buttons take a `showErrorBadge` flag, which draws a `StreamErrorBadge` on the top-end corner. It is independent of the tone and of whether the button can be pressed, so a control can be red, badged and still tappable — a microphone whose permission was refused, say. A button that simply cannot be used takes a null `onPressed`.
- Both buttons take a `badge`, a `CallControlBadge`. A `CallControlErrorBadge` draws a `StreamErrorBadge` on the top-end corner. It is independent of the tone and of whether the button can be pressed, so a control can be red, badged and still tappable — a microphone whose permission was refused, say. A button that simply cannot be used takes a null `onPressed`.
- The lobby theme follows the `@themeGen` pattern the other component themes use: `StreamLobbyViewThemeData` carries one nullable `StreamLobbyViewStyle`, every property of which means "no override", and `StreamLobbyViewTheme` is an `InheritedTheme` that merges with the ambient theme instead of replacing it. The style is deliberately small — the preview's appearance belongs to `StreamParticipantTileTheme`, the gaps between rows to `StreamSpacing` and the headings to `StreamTextTheme`, so an app restyles them by restyling those. What is left is the lobby's own geometry: `previewTileStyle`, `compactPreviewAspectRatio`, `expandedPreviewSize`, `maxOverlaidControls` and `joinButtonWidth`.

- The lobby's preview is a `StreamParticipantTile` — the same component the call draws — so its surface, corner radius, name pill and placeholder avatar cannot drift from the tiles it leads to, and an app that themes its participant tiles themes the lobby too. The tile is handed its renderer directly, because the lobby's camera track is warmed up locally and never registered with the call, so the tile's usual lookup by session id would find nothing. The overflow menu, sound indicator, connection quality and reactions are switched off — nobody has joined, so there is nothing to pin or mute, no connection to rate, no reactions to receive, and no local audio level for an indicator to animate. The overflow button is suppressed through the tile's style rather than its props, so it stays suppressed even under an app-wide `participantTile` builder that adds actions to every tile. The speaking outline is left on but never triggers yet: the in-call speaking state comes from the SFU, and a local microphone level pre-join is still to come. `StreamLobbyController.localParticipant` exposes the `CallParticipantState` this is built from.
Expand Down Expand Up @@ -186,6 +187,7 @@
### 🔄 Changed

- The badge on the call control buttons is amber with no border, where it used to be red with one.
- The count on `StreamParticipantsButton` uses the design system's neutral badge instead of `accentSuccess`.
- `accentWarning` is a lighter amber, which also repaints the fair bars on `StreamConnectionQualityIndicator`.
- `CallAppBar` is laid out by `StreamToolbar` at the design system's 72 with `spacing.sm` edge padding, matching `CallControlBar`'s horizontal inset.
- `CallAppBar.backgroundColor` colours a floating bar as well as a docked one.
Expand Down Expand Up @@ -250,7 +252,7 @@

Each old name survives as a deprecated typedef, so an unmigrated call site keeps compiling. `dart fix --apply` renames them all.

- `CallControlOption` is deprecated in favour of `CallControlButton` and `CallFeatureButton`, and has been restored to the shape it has in the last release: it takes `iconColor`, `disabledIconColor`, `elevation`, `backgroundColor`, `disabledBackgroundColor`, `shape` and `padding`, and draws an `ElevatedButton` styled from `StreamCallControlsTheme`. Code written against the released SDK keeps compiling and keeps looking the way it did. Migrating is manual rather than a `dart fix`: neither replacement takes per-instance colours, so a rename would drop whatever the call site passed. Map `state`-free call sites and the old `on` state onto `CallControlButton(tone: .neutral)`, `off` onto `.negative`, `positive` onto `.positive` for a control or `CallFeatureButton(selected: true)` for a feature, `negative` onto `.negative`, and `disabled` onto `CallControlButton(tone: .negative, showErrorBadge: true)`.
- `CallControlOption` is deprecated in favour of `CallControlButton` and `CallFeatureButton`, and has been restored to the shape it has in the last release: it takes `iconColor`, `disabledIconColor`, `elevation`, `backgroundColor`, `disabledBackgroundColor`, `shape` and `padding`, and draws an `ElevatedButton` styled from `StreamCallControlsTheme`. Code written against the released SDK keeps compiling and keeps looking the way it did. Migrating is manual rather than a `dart fix`: neither replacement takes per-instance colours, so a rename would drop whatever the call site passed. Map `state`-free call sites and the old `on` state onto `CallControlButton(tone: .neutral)`, `off` onto `.negative`, `positive` onto `.positive` for a control or `CallFeatureButton(selected: true)` for a feature, `negative` onto `.negative`, and `disabled` onto `CallControlButton(tone: .negative, badge: CallControlErrorBadge())`.
- `StreamCallParticipantThemeData` and `StreamCallParticipantTheme` are deprecated. Their properties now live in `StreamParticipantTileThemeData`, `StreamParticipantLabelThemeData`, `StreamConnectionQualityIndicatorThemeData` and `StreamCallParticipantsGridThemeData`. A theme passed to `StreamVideoTheme(callParticipantTheme: ...)` is still applied — in full, so a tile styled the old way keeps looking the way it did. Stop passing it to pick up the redesign, and pass a theme in the new shape to replace it outright. The translation runs in that factory only: setting `callParticipantTheme` through `copyWith`, or wrapping a subtree in the `StreamCallParticipantTheme` widget, changes the field without restyling anything.
- `StreamCallParticipant` is deprecated in favour of `StreamParticipantTile`, matching the component name in the design system. It keeps its own full parameter list and now only wraps `DefaultStreamParticipantTile`. Swapping the name is a manual migration rather than a `dart fix`: `StreamParticipantTile` replaces the visual parameters with a single `style:` (see the Breaking entry below), so a rename would drop whatever a call site passed. `dart fix --apply` does still strip the parameters that no longer have any effect.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class CallControlButton extends StatelessWidget {
super.key,
required this.icon,
this.tone = .neutral,
this.showErrorBadge = false,
this.badge,
this.onPressed,
this.tooltip,
this.themeStyle,
Expand All @@ -55,13 +55,15 @@ class CallControlButton extends StatelessWidget {
/// What pressing this button means.
final CallControlTone tone;

/// Whether to draw an error badge on the button's top-end corner.
/// The badge on the button's top-end corner.
///
/// This marks a control the user should look at — a microphone permission
/// that was refused, a camera that failed to start — and is independent of
/// [tone] and of whether the button can be pressed. A button that simply
/// cannot be used right now takes a null [onPressed] instead.
final bool showErrorBadge;
/// A [CallControlErrorBadge] marks a control the user should look at — a
/// microphone permission that was refused, a camera that failed to start —
/// and is independent of [tone] and of whether the button can be pressed. A
/// [CallControlNotificationBadge] shows a count, such as the people in a
/// call. A button that simply cannot be used right now takes a null
/// [onPressed] instead.
final CallControlBadge? badge;

/// The callback to invoke when the user taps on the button.
///
Expand All @@ -82,7 +84,7 @@ class CallControlButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final button = StreamCallButtonBadge(
showErrorBadge: showErrorBadge,
badge: badge,
child: StreamButton.icon(
icon: icon,
onPressed: onPressed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class CallFeatureButton extends StatelessWidget {
required this.icon,
this.selected = false,
this.tone = .accent,
this.showErrorBadge = false,
this.badge,
this.onPressed,
this.tooltip,
});
Expand All @@ -58,12 +58,13 @@ class CallFeatureButton extends StatelessWidget {
/// The colour to paint while [selected]. Ignored while it is false.
final CallFeatureTone tone;

/// Whether to draw an error badge on the button's top-end corner.
/// The badge on the button's top-end corner.
///
/// Marks a feature that needs attention — a screen share the platform
/// refused, say. A feature that merely cannot be used right now takes a null
/// [onPressed] instead.
final bool showErrorBadge;
/// A [CallControlErrorBadge] marks a feature that needs attention — a screen
/// share the platform refused, say. A [CallControlNotificationBadge] shows a
/// count, such as unread messages. A feature that merely cannot be used right
/// now takes a null [onPressed] instead.
final CallControlBadge? badge;

/// The callback to invoke when the user taps on the button.
///
Expand All @@ -76,7 +77,7 @@ class CallFeatureButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamCallButtonBadge(
showErrorBadge: showErrorBadge,
badge: badge,
child: StreamButton.icon(
icon: icon,
onPressed: onPressed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class StreamCameraButton extends StatelessWidget {
// An absent device is not a user choice, so it is badged rather than
// drawn as a deliberate mute.
tone: enabled || unavailable ? .neutral : .negative,
showErrorBadge: unavailable,
badge: unavailable ? const CallControlErrorBadge() : null,
onPressed: unavailable
? null
: () => applyDeviceChange(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class StreamMicrophoneButton extends StatelessWidget {
// An absent device is not a user choice, so it is badged rather than
// drawn as a deliberate mute.
tone: enabled || unavailable ? .neutral : .negative,
showErrorBadge: unavailable,
badge: unavailable ? const CallControlErrorBadge() : null,
onPressed: unavailable
? null
: () => applyDeviceChange(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ class _DeviceSplitButton extends StatelessWidget {
// open is worth retrying — while the caret follows what it has to
// offer, which is nothing when the platform named no device.
builder: (context, handle) => StreamCallButtonBadge(
showErrorBadge: unavailable,
badge: unavailable ? const CallControlErrorBadge() : null,
child: StreamSplitButton.icon(
leadingIcon: Icon(icon),
trailingIcon: Icon(caret(isOpen: handle.isOpen)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,30 +70,17 @@ class StreamParticipantsButton extends StatelessWidget {
}

Widget _build(BuildContext context, List<UserInfo> participants) {
final colorScheme = context.streamColorScheme;
final translations = context.translations;
final spacing = context.streamSpacing;

Widget badged(Widget button) {
if (participants.isEmpty) return button;

return StreamBadgeNotificationTheme(
data: StreamBadgeNotificationThemeData(
primaryBackgroundColor: colorScheme.accentSuccess,
),
child: StreamBadgeNotification(
label: '${participants.length}',
child: button,
),
);
}

Widget button(VoidCallback? onPressed) => badged(
CallControlButton(
icon: Icon(context.streamIcons.usersFill),
tooltip: translations.lobbyParticipants,
onPressed: onPressed,
Widget button(VoidCallback? onPressed) => CallControlButton(
icon: Icon(context.streamIcons.usersFill),
tooltip: translations.lobbyParticipants,
badge: CallControlNotificationBadge(
count: participants.length,
type: .neutral,
),
onPressed: onPressed,
);

// Nothing to anchor a menu to when the press is the caller's to handle.
Expand Down
Loading
Loading