fix: Lock thumbnails and timeline when UX is locked for calls (#2487)

This commit is contained in:
Dermot Duffy
2026-06-30 17:45:13 -07:00
committed by dermotduffy
parent abcba884e5
commit 9b750953ae
8 changed files with 50 additions and 13 deletions
+16
View File
@@ -36,6 +36,9 @@ export class AdvancedCameraCardDrawer extends LitElement {
@property({ type: Boolean, reflect: true, attribute: true }) @property({ type: Boolean, reflect: true, attribute: true })
public open = false; public open = false;
@property({ type: Boolean, reflect: true, attribute: true })
public locked?: boolean;
@property({ attribute: false, hasChanged: contentsChanged }) @property({ attribute: false, hasChanged: contentsChanged })
public icons?: DrawerIcons; public icons?: DrawerIcons;
@@ -68,6 +71,12 @@ export class AdvancedCameraCardDrawer extends LitElement {
this._refDrawer.value?.shadowRoot?.appendChild(style); this._refDrawer.value?.shadowRoot?.appendChild(style);
} }
protected willUpdate(): void {
if (this.locked && this.open) {
this.open = false;
}
}
private _slotChanged(): void { private _slotChanged(): void {
const children = this._refSlot.value const children = this._refSlot.value
? getChildrenFromElement(this._refSlot.value) ? getChildrenFromElement(this._refSlot.value)
@@ -113,6 +122,13 @@ export class AdvancedCameraCardDrawer extends LitElement {
<div <div
class="control-surround" class="control-surround"
@click=${(ev: Event) => { @click=${(ev: Event) => {
// While locked the drawer must not open. Return before
// `stopEventFromActivatingCardWideActions` so a click on the
// padded control wrapper is not swallowed and can still fall
// through to card-wide actions.
if (this.locked) {
return;
}
stopEventFromActivatingCardWideActions(ev); stopEventFromActivatingCardWideActions(ev);
this.open = !this.open; this.open = !this.open;
}} }}
+5
View File
@@ -18,6 +18,9 @@ export class AdvancedCameraCardSurroundBasic extends LitElement {
right?: DrawerIcons; right?: DrawerIcons;
}; };
@property({ attribute: false })
public locked?: boolean;
private _refDrawerLeft: Ref<AdvancedCameraCardDrawer> = createRef(); private _refDrawerLeft: Ref<AdvancedCameraCardDrawer> = createRef();
private _refDrawerRight: Ref<AdvancedCameraCardDrawer> = createRef(); private _refDrawerRight: Ref<AdvancedCameraCardDrawer> = createRef();
private _boundDrawerHandler = this._drawerHandler.bind(this); private _boundDrawerHandler = this._drawerHandler.bind(this);
@@ -57,6 +60,7 @@ export class AdvancedCameraCardSurroundBasic extends LitElement {
${ref(this._refDrawerLeft)} ${ref(this._refDrawerLeft)}
location="left" location="left"
.icons=${this.drawerIcons?.left} .icons=${this.drawerIcons?.left}
.locked=${this.locked}
> >
<slot name="left"></slot> <slot name="left"></slot>
</advanced-camera-card-drawer> </advanced-camera-card-drawer>
@@ -64,6 +68,7 @@ export class AdvancedCameraCardSurroundBasic extends LitElement {
${ref(this._refDrawerRight)} ${ref(this._refDrawerRight)}
location="right" location="right"
.icons=${this.drawerIcons?.right} .icons=${this.drawerIcons?.right}
.locked=${this.locked}
> >
<slot name="right"></slot> <slot name="right"></slot>
</advanced-camera-card-drawer> </advanced-camera-card-drawer>
+1
View File
@@ -90,6 +90,7 @@ export class AdvancedCameraCardSurround extends LitElement {
}; };
return html` <advanced-camera-card-surround-basic return html` <advanced-camera-card-surround-basic
.locked=${this.locked}
@advanced-camera-card:thumbnails-carousel:media-select=${(ev: CustomEvent) => @advanced-camera-card:thumbnails-carousel:media-select=${(ev: CustomEvent) =>
changeDrawer(ev, 'close')} changeDrawer(ev, 'close')}
> >
+8
View File
@@ -1,3 +1,5 @@
@use 'locked.scss';
$drawer-icon-size: 20px; $drawer-icon-size: 20px;
$drawer-padding-extend: 20px; $drawer-padding-extend: 20px;
@@ -47,6 +49,12 @@ advanced-camera-card-icon.control {
transition: opacity 0.5s ease; transition: opacity 0.5s ease;
} }
// While locked, the control is dimmed and non-interactive. Applied to the
// control rather than `:host` so the drawer's slotted content is unaffected.
:host([locked]) advanced-camera-card-icon.control {
@include locked.style;
}
:host([location='left']) advanced-camera-card-icon.control { :host([location='left']) advanced-camera-card-icon.control {
border-top-right-radius: $drawer-icon-size; border-top-right-radius: $drawer-icon-size;
border-bottom-right-radius: $drawer-icon-size; border-bottom-right-radius: $drawer-icon-size;
+4 -5
View File
@@ -1,8 +1,7 @@
// Shared styling for components that reflect a `locked` host attribute (set by // The shared definition of the "locked" appearance: dimmed and
// Lit when the consumer-facing `locked` property is true). Dims the host and // non-interactive, without removing the element from layout (so it holds its
// disables pointer interaction without removing it from layout, so the element // place during lock/unlock transitions).
// stays in place during mic mute/unmute transitions. @mixin style {
:host([locked]) {
opacity: 0.4; opacity: 0.4;
pointer-events: none; pointer-events: none;
} }
+8 -8
View File
@@ -1,4 +1,5 @@
@use './button.scss'; @use './button.scss';
@use './locked.scss';
:host { :host {
--advanced-camera-card-next-prev-size: 48px; --advanced-camera-card-next-prev-size: 48px;
@@ -23,15 +24,14 @@
right: var(--advanced-camera-card-right-position); right: var(--advanced-camera-card-right-position);
} }
// Dim while locked. Deliberately applied to `.controls` rather than `:host` // Dim while locked. Deliberately applied to `.controls` rather than `:host`:
// (as the shared `locked.scss` does): `opacity` on the host would create a // `opacity` on the host would create a stacking context that traps
// stacking context that traps `.controls`'s `z-index`, dropping the control // `.controls`'s `z-index`, dropping the control behind the media whenever it
// behind the media whenever it is DOM-ordered before it (the left control). // is DOM-ordered before it (the left control). `.controls` is already
// `.controls` is already positioned and z-indexed, so dimming it here leaves // positioned and z-indexed, so dimming it here leaves its stacking context
// its stacking context intact. // intact.
:host([locked]) .controls { :host([locked]) .controls {
opacity: 0.4; @include locked.style;
pointer-events: none;
} }
.controls.icons { .controls.icons {
+4
View File
@@ -1,6 +1,10 @@
@use 'const.scss'; @use 'const.scss';
@use 'locked.scss'; @use 'locked.scss';
:host([locked]) {
@include locked.style;
}
:host { :host {
display: block; display: block;
width: 100%; width: 100%;
+4
View File
@@ -3,6 +3,10 @@
@use 'const.scss'; @use 'const.scss';
@use 'locked.scss'; @use 'locked.scss';
:host([locked]) {
@include locked.style;
}
:host { :host {
width: 100%; width: 100%;
// Share the screen space with thumbnails that may be above/below. // Share the screen space with thumbnails that may be above/below.