Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Handle multiple live beacons in room share warning, test
Browse files Browse the repository at this point in the history
Signed-off-by: Kerry Archibald <[email protected]>
  • Loading branch information
Kerry Archibald committed Mar 21, 2022
1 parent ce06c27 commit 542b385
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 80 deletions.
1 change: 1 addition & 0 deletions res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@import "./_spacing.scss";
@import "./components/views/beacon/_LeftPanelLiveShareWarning.scss";
@import "./components/views/beacon/_RoomLiveShareWarning.scss";
@import "./components/views/beacon/_StyledLiveBeaconIcon.scss";
@import "./components/views/location/_LiveDurationDropdown.scss";
@import "./components/views/location/_LocationShareMenu.scss";
@import "./components/views/location/_MapError.scss";
Expand Down
14 changes: 11 additions & 3 deletions res/css/components/views/beacon/_RoomLiveShareWarning.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

.mx_RoomLiveShareWarning {
width: 100%;

Expand All @@ -13,14 +12,23 @@
background-color: $system;
}

.mx_RoomLiveShareWarning_icon {
height: 32px;
width: 32px;
margin-right: $spacing-8;
}

.mx_RoomLiveShareWarning_label {
flex: 1;
font-size: $font-15px;
}


.mx_RoomLiveShareWarning_expiry {
color: $secondary-content;
font-size: $font-12px;
margin-right: $spacing-16;
}
}

.mx_RoomLiveShareWarning_spinner {
margin-right: $spacing-16;
}
10 changes: 5 additions & 5 deletions res/css/components/views/beacon/_StyledLiveBeaconIcon.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ limitations under the License.
border-radius: 50%;

background-color: $location-live-color;
// 20% brightness $location-live-color
border-color: #deddfd;
padding: 2px;
// colors icon
color: white;
// 20% brightness $location-live-color
border-color: #deddfd;
padding: 2px;
// colors icon
color: white;
}
11 changes: 2 additions & 9 deletions res/css/components/views/location/_ShareType.scss
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,12 @@ limitations under the License.
border-style: solid;
border-radius: 50%;

// Live is styled by StyledLiveBeaconIcon

&.Own {
border-color: $accent;
}

&.Live {
background-color: $location-live-color;
// 20% brightness $location-live-color
border-color: #deddfd;
padding: 2px;
// colors icon
color: white;
}

&.Pin {
border-color: $accent;
background-color: $accent;
Expand Down
92 changes: 70 additions & 22 deletions src/components/views/beacon/RoomLiveShareWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,61 +14,109 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { useEffect, useState } from 'react';
import classNames from 'classnames';
import React from 'react';
import { Room } from 'matrix-js-sdk/src/matrix';

import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { _t } from '../../../languageHandler';
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
import { Icon as LiveLocationIcon } from '../../../../res/img/location/live-location.svg';
import AccessibleButton from '../elements/AccessibleButton';
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
import { formatDuration } from '../../../DateUtils';
import { getBeaconMsUntilExpiry, sortBeaconsByLatestExpiry } from '../../../utils/beacon';
import Spinner from '../elements/Spinner';

interface Props {
roomId: Room['roomId'];
}

const RoomLiveShareWarning: React.FC<Props> = ({ roomId }) => {
/**
* It's technically possible to have multiple live beacons in one room
* Select the latest expiry to display,
* and kill all beacons on stop sharing
*/
type LiveBeaconsState = {
liveBeaconIds: string[];
msRemaining?: number;
onStopSharing?: () => void;
stoppingInProgress?: boolean;
};
const useLiveBeacons = (roomId: Room['roomId']): LiveBeaconsState => {
const [stoppingInProgress, setStoppingInProgress] = useState(false);
const liveBeaconIds = useEventEmitterState(
OwnBeaconStore.instance,
OwnBeaconStoreEvent.LivenessChange,
() => OwnBeaconStore.instance.getLiveBeaconIds(roomId),
);

// reset stopping in progress on change in live ids
useEffect(() => {
setStoppingInProgress(false);
}, [liveBeaconIds, setStoppingInProgress]);

if (!liveBeaconIds?.length) {
return null;
return { liveBeaconIds };
}

if (liveBeaconIds.length > 1) {
throw new Error('not handled yet');
}
// select the beacon with latest expiry to display expiry time
const beacon = liveBeaconIds.map(beaconId => OwnBeaconStore.instance.getBeaconById(beaconId))
.sort(sortBeaconsByLatestExpiry)
.shift();

const beaconId = liveBeaconIds[0];
const onStopSharing = async () => {
setStoppingInProgress(true);
try {
await Promise.all(liveBeaconIds.map(beaconId => OwnBeaconStore.instance.stopBeacon(beaconId)));
} catch (error) {
// only clear loading in case of error
// to avoid flash of not-loading state
// after beacons have been stopped but we wait for sync
setStoppingInProgress(false);
}
};

const beacon = OwnBeaconStore.instance.getBeaconById(liveBeaconIds[0]);
const liveTimeRemaining = `${beacon.beaconInfo.timeout}`;
const msRemaining = getBeaconMsUntilExpiry(beacon);

const onStopSharing = () => {
OwnBeaconStore.instance.stopBeacon(beaconId);
};
return { liveBeaconIds, onStopSharing, msRemaining, stoppingInProgress };
};

const RoomLiveShareWarning: React.FC<Props> = ({ roomId }) => {
const {
liveBeaconIds,
onStopSharing,
msRemaining,
stoppingInProgress,
} = useLiveBeacons(roomId);

if (!liveBeaconIds?.length) {
return null;
}

const timeRemaining = formatDuration(msRemaining);
const liveTimeRemaining = _t(`%(timeRemaining)s left`, { timeRemaining });

return <div
className={classNames('mx_RoomLiveShareWarning')}
>
<LiveLocationIcon />
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" />
<span className="mx_RoomLiveShareWarning_label">

{ _t('You are sharing your live location') }
{ _t('You are sharing %(count)s live locations', { count: liveBeaconIds.length }) }
</span>
<span
data-test-id='room-live-share-expiry'
className="mx_RoomLiveShareWarning_expiry"
>{ liveTimeRemaining }</span>

{ stoppingInProgress ?
<span className='mx_RoomLiveShareWarning_spinner'><Spinner h={16} w={16} /></span> :
<span
data-test-id='room-live-share-expiry'
className="mx_RoomLiveShareWarning_expiry"
>{ liveTimeRemaining }</span>
}
<AccessibleButton
data-test-id='room-live-share-stop-sharing'
onClick={ onStopSharing }
onClick={onStopSharing}
kind='danger'
element='button'
disabled={stoppingInProgress}
>
{ _t('Stop sharing') }
</AccessibleButton>
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2967,6 +2967,9 @@
"Leave the beta": "Leave the beta",
"Join the beta": "Join the beta",
"You are sharing your live location": "You are sharing your live location",
"%(timeRemaining)s left": "%(timeRemaining)s left",
"You are sharing %(count)s live locations|one": "You are sharing your live location",
"You are sharing %(count)s live locations|other": "You are sharing %(count)s live locations",
"Stop sharing": "Stop sharing",
"Avatar": "Avatar",
"This room is public": "This room is public",
Expand Down
Loading

0 comments on commit 542b385

Please sign in to comment.