Apply prettier formatting
This commit is contained in:
parent
1cac306093
commit
526645c791
1576 changed files with 65385 additions and 62478 deletions
|
@ -14,20 +14,20 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { HTMLProps, useContext } from 'react';
|
||||
import { Beacon, BeaconEvent } from 'matrix-js-sdk/src/matrix';
|
||||
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import React, { HTMLProps, useContext } from "react";
|
||||
import { Beacon, BeaconEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import { humanizeTime } from '../../../utils/humanize';
|
||||
import { preventDefaultWrapper } from '../../../utils/NativeEventUtils';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import MemberAvatar from '../avatars/MemberAvatar';
|
||||
import BeaconStatus from './BeaconStatus';
|
||||
import { BeaconDisplayStatus } from './displayStatus';
|
||||
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
|
||||
import ShareLatestLocation from './ShareLatestLocation';
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import { humanizeTime } from "../../../utils/humanize";
|
||||
import { preventDefaultWrapper } from "../../../utils/NativeEventUtils";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import MemberAvatar from "../avatars/MemberAvatar";
|
||||
import BeaconStatus from "./BeaconStatus";
|
||||
import { BeaconDisplayStatus } from "./displayStatus";
|
||||
import StyledLiveBeaconIcon from "./StyledLiveBeaconIcon";
|
||||
import ShareLatestLocation from "./ShareLatestLocation";
|
||||
|
||||
interface Props {
|
||||
beacon: Beacon;
|
||||
|
@ -47,38 +47,36 @@ const BeaconListItem: React.FC<Props & HTMLProps<HTMLLIElement>> = ({ beacon, ..
|
|||
}
|
||||
|
||||
const isSelfLocation = beacon.beaconInfo.assetType === LocationAssetType.Self;
|
||||
const beaconMember = isSelfLocation ?
|
||||
room.getMember(beacon.beaconInfoOwner) :
|
||||
undefined;
|
||||
const beaconMember = isSelfLocation ? room.getMember(beacon.beaconInfoOwner) : undefined;
|
||||
|
||||
const humanizedUpdateTime = humanizeTime(latestLocationState.timestamp);
|
||||
|
||||
return <li className='mx_BeaconListItem' {...rest}>
|
||||
{ isSelfLocation ?
|
||||
<MemberAvatar
|
||||
className='mx_BeaconListItem_avatar'
|
||||
member={beaconMember}
|
||||
height={32}
|
||||
width={32}
|
||||
/> :
|
||||
<StyledLiveBeaconIcon className='mx_BeaconListItem_avatarIcon' />
|
||||
}
|
||||
<div className='mx_BeaconListItem_info'>
|
||||
<BeaconStatus
|
||||
className='mx_BeaconListItem_status'
|
||||
beacon={beacon}
|
||||
label={beaconMember?.name || beacon.beaconInfo.description || beacon.beaconInfoOwner}
|
||||
displayStatus={BeaconDisplayStatus.Active}
|
||||
>
|
||||
{ /* eat events from interactive share buttons
|
||||
so parent click handlers are not triggered */ }
|
||||
<div className='mx_BeaconListItem_interactions' onClick={preventDefaultWrapper(() => {})}>
|
||||
<ShareLatestLocation latestLocationState={latestLocationState} />
|
||||
</div>
|
||||
</BeaconStatus>
|
||||
<span className='mx_BeaconListItem_lastUpdated'>{ _t("Updated %(humanizedUpdateTime)s", { humanizedUpdateTime }) }</span>
|
||||
</div>
|
||||
</li>;
|
||||
return (
|
||||
<li className="mx_BeaconListItem" {...rest}>
|
||||
{isSelfLocation ? (
|
||||
<MemberAvatar className="mx_BeaconListItem_avatar" member={beaconMember} height={32} width={32} />
|
||||
) : (
|
||||
<StyledLiveBeaconIcon className="mx_BeaconListItem_avatarIcon" />
|
||||
)}
|
||||
<div className="mx_BeaconListItem_info">
|
||||
<BeaconStatus
|
||||
className="mx_BeaconListItem_status"
|
||||
beacon={beacon}
|
||||
label={beaconMember?.name || beacon.beaconInfo.description || beacon.beaconInfoOwner}
|
||||
displayStatus={BeaconDisplayStatus.Active}
|
||||
>
|
||||
{/* eat events from interactive share buttons
|
||||
so parent click handlers are not triggered */}
|
||||
<div className="mx_BeaconListItem_interactions" onClick={preventDefaultWrapper(() => {})}>
|
||||
<ShareLatestLocation latestLocationState={latestLocationState} />
|
||||
</div>
|
||||
</BeaconStatus>
|
||||
<span className="mx_BeaconListItem_lastUpdated">
|
||||
{_t("Updated %(humanizedUpdateTime)s", { humanizedUpdateTime })}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export default BeaconListItem;
|
||||
|
|
|
@ -14,17 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ReactNode, useContext } from 'react';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import {
|
||||
Beacon,
|
||||
BeaconEvent,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import React, { ReactNode, useContext } from "react";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { Beacon, BeaconEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import SmartMarker from '../location/SmartMarker';
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import SmartMarker from "../location/SmartMarker";
|
||||
|
||||
interface Props {
|
||||
map: maplibregl.Map;
|
||||
|
@ -50,18 +47,19 @@ const BeaconMarker: React.FC<Props> = ({ map, beacon, tooltip }) => {
|
|||
|
||||
const geoUri = latestLocationState?.uri;
|
||||
|
||||
const markerRoomMember = beacon.beaconInfo.assetType === LocationAssetType.Self ?
|
||||
room.getMember(beacon.beaconInfoOwner) :
|
||||
undefined;
|
||||
const markerRoomMember =
|
||||
beacon.beaconInfo.assetType === LocationAssetType.Self ? room.getMember(beacon.beaconInfoOwner) : undefined;
|
||||
|
||||
return <SmartMarker
|
||||
map={map}
|
||||
id={beacon.identifier}
|
||||
geoUri={geoUri}
|
||||
roomMember={markerRoomMember}
|
||||
tooltip={tooltip}
|
||||
useMemberColor
|
||||
/>;
|
||||
return (
|
||||
<SmartMarker
|
||||
map={map}
|
||||
id={beacon.identifier}
|
||||
geoUri={geoUri}
|
||||
roomMember={markerRoomMember}
|
||||
tooltip={tooltip}
|
||||
useMemberColor
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BeaconMarker;
|
||||
|
|
|
@ -14,16 +14,16 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { HTMLProps } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import React, { HTMLProps } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import LiveTimeRemaining from './LiveTimeRemaining';
|
||||
import { BeaconDisplayStatus } from './displayStatus';
|
||||
import { getBeaconExpiryTimestamp } from '../../../utils/beacon';
|
||||
import { formatTime } from '../../../DateUtils';
|
||||
import StyledLiveBeaconIcon from "./StyledLiveBeaconIcon";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import LiveTimeRemaining from "./LiveTimeRemaining";
|
||||
import { BeaconDisplayStatus } from "./displayStatus";
|
||||
import { getBeaconExpiryTimestamp } from "../../../utils/beacon";
|
||||
import { formatTime } from "../../../DateUtils";
|
||||
|
||||
interface Props {
|
||||
displayStatus: BeaconDisplayStatus;
|
||||
|
@ -35,56 +35,56 @@ interface Props {
|
|||
|
||||
const BeaconExpiryTime: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
|
||||
const expiryTime = formatTime(new Date(getBeaconExpiryTimestamp(beacon)));
|
||||
return <span className='mx_BeaconStatus_expiryTime'>{ _t('Live until %(expiryTime)s', { expiryTime }) }</span>;
|
||||
return <span className="mx_BeaconStatus_expiryTime">{_t("Live until %(expiryTime)s", { expiryTime })}</span>;
|
||||
};
|
||||
|
||||
const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> =
|
||||
({
|
||||
beacon,
|
||||
displayStatus,
|
||||
displayLiveTimeRemaining,
|
||||
label,
|
||||
className,
|
||||
children,
|
||||
withIcon,
|
||||
...rest
|
||||
}) => {
|
||||
const isIdle = displayStatus === BeaconDisplayStatus.Loading ||
|
||||
displayStatus === BeaconDisplayStatus.Stopped;
|
||||
const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
|
||||
beacon,
|
||||
displayStatus,
|
||||
displayLiveTimeRemaining,
|
||||
label,
|
||||
className,
|
||||
children,
|
||||
withIcon,
|
||||
...rest
|
||||
}) => {
|
||||
const isIdle = displayStatus === BeaconDisplayStatus.Loading || displayStatus === BeaconDisplayStatus.Stopped;
|
||||
|
||||
return <div
|
||||
{...rest}
|
||||
className={classNames('mx_BeaconStatus', `mx_BeaconStatus_${displayStatus}`, className)}
|
||||
>
|
||||
{ withIcon && <StyledLiveBeaconIcon
|
||||
className='mx_BeaconStatus_icon'
|
||||
withError={displayStatus === BeaconDisplayStatus.Error}
|
||||
isIdle={isIdle}
|
||||
/> }
|
||||
<div className='mx_BeaconStatus_description'>
|
||||
|
||||
{ displayStatus === BeaconDisplayStatus.Loading &&
|
||||
<span className="mx_BeaconStatus_description_status">{ _t('Loading live location...') }</span>
|
||||
}
|
||||
{ displayStatus === BeaconDisplayStatus.Stopped &&
|
||||
<span className="mx_BeaconStatus_description_status">{ _t('Live location ended') }</span>
|
||||
}
|
||||
{ displayStatus === BeaconDisplayStatus.Error &&
|
||||
<span className="mx_BeaconStatus_description_status">{ _t('Live location error') }</span>
|
||||
}
|
||||
{ displayStatus === BeaconDisplayStatus.Active && beacon && <>
|
||||
return (
|
||||
<div {...rest} className={classNames("mx_BeaconStatus", `mx_BeaconStatus_${displayStatus}`, className)}>
|
||||
{withIcon && (
|
||||
<StyledLiveBeaconIcon
|
||||
className="mx_BeaconStatus_icon"
|
||||
withError={displayStatus === BeaconDisplayStatus.Error}
|
||||
isIdle={isIdle}
|
||||
/>
|
||||
)}
|
||||
<div className="mx_BeaconStatus_description">
|
||||
{displayStatus === BeaconDisplayStatus.Loading && (
|
||||
<span className="mx_BeaconStatus_description_status">{_t("Loading live location...")}</span>
|
||||
)}
|
||||
{displayStatus === BeaconDisplayStatus.Stopped && (
|
||||
<span className="mx_BeaconStatus_description_status">{_t("Live location ended")}</span>
|
||||
)}
|
||||
{displayStatus === BeaconDisplayStatus.Error && (
|
||||
<span className="mx_BeaconStatus_description_status">{_t("Live location error")}</span>
|
||||
)}
|
||||
{displayStatus === BeaconDisplayStatus.Active && beacon && (
|
||||
<>
|
||||
<span className='mx_BeaconStatus_label'>{ label }</span>
|
||||
{ displayLiveTimeRemaining ?
|
||||
<LiveTimeRemaining beacon={beacon} /> :
|
||||
<BeaconExpiryTime beacon={beacon} />
|
||||
}
|
||||
<>
|
||||
<span className="mx_BeaconStatus_label">{label}</span>
|
||||
{displayLiveTimeRemaining ? (
|
||||
<LiveTimeRemaining beacon={beacon} />
|
||||
) : (
|
||||
<BeaconExpiryTime beacon={beacon} />
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
</>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
{ children }
|
||||
</div>;
|
||||
};
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BeaconStatus;
|
||||
|
|
|
@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import { Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import React, { useContext } from "react";
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import BeaconStatus from './BeaconStatus';
|
||||
import { BeaconDisplayStatus } from './displayStatus';
|
||||
import ShareLatestLocation from './ShareLatestLocation';
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import BeaconStatus from "./BeaconStatus";
|
||||
import { BeaconDisplayStatus } from "./displayStatus";
|
||||
import ShareLatestLocation from "./ShareLatestLocation";
|
||||
|
||||
interface Props {
|
||||
beacon: Beacon;
|
||||
|
@ -42,17 +42,19 @@ const useBeaconName = (beacon: Beacon): string => {
|
|||
const BeaconStatusTooltip: React.FC<Props> = ({ beacon }) => {
|
||||
const label = useBeaconName(beacon);
|
||||
|
||||
return <div className='mx_BeaconStatusTooltip'>
|
||||
<BeaconStatus
|
||||
beacon={beacon}
|
||||
label={label}
|
||||
displayStatus={BeaconDisplayStatus.Active}
|
||||
displayLiveTimeRemaining
|
||||
className='mx_BeaconStatusTooltip_inner'
|
||||
>
|
||||
<ShareLatestLocation latestLocationState={beacon.latestLocationState} />
|
||||
</BeaconStatus>
|
||||
</div>;
|
||||
return (
|
||||
<div className="mx_BeaconStatusTooltip">
|
||||
<BeaconStatus
|
||||
beacon={beacon}
|
||||
label={label}
|
||||
displayStatus={BeaconDisplayStatus.Active}
|
||||
displayLiveTimeRemaining
|
||||
className="mx_BeaconStatusTooltip_inner"
|
||||
>
|
||||
<ShareLatestLocation latestLocationState={beacon.latestLocationState} />
|
||||
</BeaconStatus>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BeaconStatusTooltip;
|
||||
|
|
|
@ -14,35 +14,32 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import {
|
||||
Beacon,
|
||||
Room,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { Beacon, Room } from "matrix-js-sdk/src/matrix";
|
||||
import maplibregl from "maplibre-gl";
|
||||
|
||||
import { Icon as LiveLocationIcon } from '../../../../res/img/location/live-location.svg';
|
||||
import { useLiveBeacons } from '../../../utils/beacon/useLiveBeacons';
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import { Icon as LiveLocationIcon } from "../../../../res/img/location/live-location.svg";
|
||||
import { useLiveBeacons } from "../../../utils/beacon/useLiveBeacons";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import BaseDialog from "../dialogs/BaseDialog";
|
||||
import { IDialogProps } from "../dialogs/IDialogProps";
|
||||
import Map from '../location/Map';
|
||||
import ZoomButtons from '../location/ZoomButtons';
|
||||
import BeaconMarker from './BeaconMarker';
|
||||
import { Bounds, getBeaconBounds } from '../../../utils/beacon/bounds';
|
||||
import { getGeoUri } from '../../../utils/beacon';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import DialogSidebar from './DialogSidebar';
|
||||
import DialogOwnBeaconStatus from './DialogOwnBeaconStatus';
|
||||
import BeaconStatusTooltip from './BeaconStatusTooltip';
|
||||
import MapFallback from '../location/MapFallback';
|
||||
import { MapError } from '../location/MapError';
|
||||
import { LocationShareError } from '../../../utils/location';
|
||||
import Map from "../location/Map";
|
||||
import ZoomButtons from "../location/ZoomButtons";
|
||||
import BeaconMarker from "./BeaconMarker";
|
||||
import { Bounds, getBeaconBounds } from "../../../utils/beacon/bounds";
|
||||
import { getGeoUri } from "../../../utils/beacon";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import DialogSidebar from "./DialogSidebar";
|
||||
import DialogOwnBeaconStatus from "./DialogOwnBeaconStatus";
|
||||
import BeaconStatusTooltip from "./BeaconStatusTooltip";
|
||||
import MapFallback from "../location/MapFallback";
|
||||
import { MapError } from "../location/MapError";
|
||||
import { LocationShareError } from "../../../utils/location";
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
roomId: Room['roomId'];
|
||||
roomId: Room["roomId"];
|
||||
matrixClient: MatrixClient;
|
||||
// open the map centered on this beacon's location
|
||||
initialFocusedBeacon?: Beacon;
|
||||
|
@ -68,13 +65,16 @@ const getBoundsCenter = (bounds: Bounds): string | undefined => {
|
|||
});
|
||||
};
|
||||
|
||||
const useMapPosition = (liveBeacons: Beacon[], { beacon, ts }: FocusedBeaconState): {
|
||||
bounds?: Bounds; centerGeoUri: string;
|
||||
const useMapPosition = (
|
||||
liveBeacons: Beacon[],
|
||||
{ beacon, ts }: FocusedBeaconState,
|
||||
): {
|
||||
bounds?: Bounds;
|
||||
centerGeoUri: string;
|
||||
} => {
|
||||
const [bounds, setBounds] = useState<Bounds | undefined>(getBeaconBounds(liveBeacons));
|
||||
const [centerGeoUri, setCenterGeoUri] = useState<string>(
|
||||
beacon?.latestLocationState?.uri ||
|
||||
getBoundsCenter(bounds),
|
||||
beacon?.latestLocationState?.uri || getBoundsCenter(bounds),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -101,15 +101,12 @@ const useMapPosition = (liveBeacons: Beacon[], { beacon, ts }: FocusedBeaconStat
|
|||
/**
|
||||
* Dialog to view live beacons maximised
|
||||
*/
|
||||
const BeaconViewDialog: React.FC<IProps> = ({
|
||||
initialFocusedBeacon,
|
||||
roomId,
|
||||
matrixClient,
|
||||
onFinished,
|
||||
}) => {
|
||||
const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matrixClient, onFinished }) => {
|
||||
const liveBeacons = useLiveBeacons(roomId, matrixClient);
|
||||
const [focusedBeaconState, setFocusedBeaconState] =
|
||||
useState<FocusedBeaconState>({ beacon: initialFocusedBeacon, ts: 0 });
|
||||
const [focusedBeaconState, setFocusedBeaconState] = useState<FocusedBeaconState>({
|
||||
beacon: initialFocusedBeacon,
|
||||
ts: 0,
|
||||
});
|
||||
|
||||
const [isSidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
|
@ -129,66 +126,63 @@ const BeaconViewDialog: React.FC<IProps> = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
className='mx_BeaconViewDialog'
|
||||
onFinished={onFinished}
|
||||
fixedWidth={false}
|
||||
>
|
||||
<BaseDialog className="mx_BeaconViewDialog" onFinished={onFinished} fixedWidth={false}>
|
||||
<MatrixClientContext.Provider value={matrixClient}>
|
||||
{ (centerGeoUri && !mapDisplayError) && <Map
|
||||
id='mx_BeaconViewDialog'
|
||||
bounds={bounds}
|
||||
centerGeoUri={centerGeoUri}
|
||||
interactive
|
||||
onError={setMapDisplayError}
|
||||
className="mx_BeaconViewDialog_map"
|
||||
>
|
||||
{
|
||||
({ map }: { map: maplibregl.Map}) =>
|
||||
{centerGeoUri && !mapDisplayError && (
|
||||
<Map
|
||||
id="mx_BeaconViewDialog"
|
||||
bounds={bounds}
|
||||
centerGeoUri={centerGeoUri}
|
||||
interactive
|
||||
onError={setMapDisplayError}
|
||||
className="mx_BeaconViewDialog_map"
|
||||
>
|
||||
{({ map }: { map: maplibregl.Map }) => (
|
||||
<>
|
||||
{ liveBeacons.map(beacon => <BeaconMarker
|
||||
key={beacon.identifier}
|
||||
map={map}
|
||||
beacon={beacon}
|
||||
tooltip={<BeaconStatusTooltip beacon={beacon} />}
|
||||
/>) }
|
||||
{liveBeacons.map((beacon) => (
|
||||
<BeaconMarker
|
||||
key={beacon.identifier}
|
||||
map={map}
|
||||
beacon={beacon}
|
||||
tooltip={<BeaconStatusTooltip beacon={beacon} />}
|
||||
/>
|
||||
))}
|
||||
<ZoomButtons map={map} />
|
||||
</>
|
||||
}
|
||||
</Map> }
|
||||
{ mapDisplayError &&
|
||||
<MapError
|
||||
error={mapDisplayError.message as LocationShareError}
|
||||
isMinimised
|
||||
/>
|
||||
}
|
||||
{ !centerGeoUri && !mapDisplayError &&
|
||||
<MapFallback
|
||||
data-test-id='beacon-view-dialog-map-fallback'
|
||||
className='mx_BeaconViewDialog_map'
|
||||
>
|
||||
<span className='mx_BeaconViewDialog_mapFallbackMessage'>{ _t('No live locations') }</span>
|
||||
)}
|
||||
</Map>
|
||||
)}
|
||||
{mapDisplayError && <MapError error={mapDisplayError.message as LocationShareError} isMinimised />}
|
||||
{!centerGeoUri && !mapDisplayError && (
|
||||
<MapFallback data-test-id="beacon-view-dialog-map-fallback" className="mx_BeaconViewDialog_map">
|
||||
<span className="mx_BeaconViewDialog_mapFallbackMessage">{_t("No live locations")}</span>
|
||||
<AccessibleButton
|
||||
kind='primary'
|
||||
kind="primary"
|
||||
onClick={onFinished}
|
||||
data-test-id='beacon-view-dialog-fallback-close'
|
||||
data-test-id="beacon-view-dialog-fallback-close"
|
||||
>
|
||||
{ _t('Close') }
|
||||
{_t("Close")}
|
||||
</AccessibleButton>
|
||||
</MapFallback>
|
||||
}
|
||||
{ isSidebarOpen ?
|
||||
<DialogSidebar beacons={liveBeacons} onBeaconClick={onBeaconListItemClick} requestClose={() => setSidebarOpen(false)} /> :
|
||||
)}
|
||||
{isSidebarOpen ? (
|
||||
<DialogSidebar
|
||||
beacons={liveBeacons}
|
||||
onBeaconClick={onBeaconListItemClick}
|
||||
requestClose={() => setSidebarOpen(false)}
|
||||
/>
|
||||
) : (
|
||||
<AccessibleButton
|
||||
kind='primary'
|
||||
kind="primary"
|
||||
onClick={() => setSidebarOpen(true)}
|
||||
data-test-id='beacon-view-dialog-open-sidebar'
|
||||
className='mx_BeaconViewDialog_viewListButton'
|
||||
data-test-id="beacon-view-dialog-open-sidebar"
|
||||
className="mx_BeaconViewDialog_viewListButton"
|
||||
>
|
||||
<LiveLocationIcon height={12} />
|
||||
{ _t('View list') }
|
||||
<LiveLocationIcon height={12} />
|
||||
|
||||
{_t("View list")}
|
||||
</AccessibleButton>
|
||||
}
|
||||
)}
|
||||
<DialogOwnBeaconStatus roomId={roomId} />
|
||||
</MatrixClientContext.Provider>
|
||||
</BaseDialog>
|
||||
|
|
|
@ -14,31 +14,27 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import { Room, Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import React, { useContext } from "react";
|
||||
import { Room, Beacon } from "matrix-js-sdk/src/matrix";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import OwnBeaconStatus from './OwnBeaconStatus';
|
||||
import { BeaconDisplayStatus } from './displayStatus';
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import MemberAvatar from '../avatars/MemberAvatar';
|
||||
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../stores/OwnBeaconStore";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import OwnBeaconStatus from "./OwnBeaconStatus";
|
||||
import { BeaconDisplayStatus } from "./displayStatus";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import MemberAvatar from "../avatars/MemberAvatar";
|
||||
import StyledLiveBeaconIcon from "./StyledLiveBeaconIcon";
|
||||
|
||||
interface Props {
|
||||
roomId: Room['roomId'];
|
||||
roomId: Room["roomId"];
|
||||
}
|
||||
|
||||
const useOwnBeacon = (roomId: Room['roomId']): Beacon | undefined => {
|
||||
const ownBeacon = useEventEmitterState(
|
||||
OwnBeaconStore.instance,
|
||||
OwnBeaconStoreEvent.LivenessChange,
|
||||
() => {
|
||||
const [ownBeaconId] = OwnBeaconStore.instance.getLiveBeaconIds(roomId);
|
||||
return OwnBeaconStore.instance.getBeaconById(ownBeaconId);
|
||||
},
|
||||
);
|
||||
const useOwnBeacon = (roomId: Room["roomId"]): Beacon | undefined => {
|
||||
const ownBeacon = useEventEmitterState(OwnBeaconStore.instance, OwnBeaconStoreEvent.LivenessChange, () => {
|
||||
const [ownBeaconId] = OwnBeaconStore.instance.getLiveBeaconIds(roomId);
|
||||
return OwnBeaconStore.instance.getBeaconById(ownBeaconId);
|
||||
});
|
||||
|
||||
return ownBeacon;
|
||||
};
|
||||
|
@ -54,26 +50,27 @@ const DialogOwnBeaconStatus: React.FC<Props> = ({ roomId }) => {
|
|||
}
|
||||
|
||||
const isSelfLocation = beacon.beaconInfo.assetType === LocationAssetType.Self;
|
||||
const beaconMember = isSelfLocation ?
|
||||
room.getMember(beacon.beaconInfoOwner) :
|
||||
undefined;
|
||||
const beaconMember = isSelfLocation ? room.getMember(beacon.beaconInfoOwner) : undefined;
|
||||
|
||||
return <div className='mx_DialogOwnBeaconStatus'>
|
||||
{ isSelfLocation ?
|
||||
<MemberAvatar
|
||||
className='mx_DialogOwnBeaconStatus_avatar'
|
||||
member={beaconMember}
|
||||
height={32}
|
||||
width={32}
|
||||
/> :
|
||||
<StyledLiveBeaconIcon className='mx_DialogOwnBeaconStatus_avatarIcon' />
|
||||
}
|
||||
<OwnBeaconStatus
|
||||
className='mx_DialogOwnBeaconStatus_status'
|
||||
beacon={beacon}
|
||||
displayStatus={BeaconDisplayStatus.Active}
|
||||
/>
|
||||
</div>;
|
||||
return (
|
||||
<div className="mx_DialogOwnBeaconStatus">
|
||||
{isSelfLocation ? (
|
||||
<MemberAvatar
|
||||
className="mx_DialogOwnBeaconStatus_avatar"
|
||||
member={beaconMember}
|
||||
height={32}
|
||||
width={32}
|
||||
/>
|
||||
) : (
|
||||
<StyledLiveBeaconIcon className="mx_DialogOwnBeaconStatus_avatarIcon" />
|
||||
)}
|
||||
<OwnBeaconStatus
|
||||
className="mx_DialogOwnBeaconStatus_status"
|
||||
beacon={beacon}
|
||||
displayStatus={BeaconDisplayStatus.Active}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogOwnBeaconStatus;
|
||||
|
|
|
@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import React from "react";
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { Icon as CloseIcon } from '../../../../res/img/image-view/close.svg';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import Heading from '../typography/Heading';
|
||||
import BeaconListItem from './BeaconListItem';
|
||||
import { Icon as CloseIcon } from "../../../../res/img/image-view/close.svg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import Heading from "../typography/Heading";
|
||||
import BeaconListItem from "./BeaconListItem";
|
||||
|
||||
interface Props {
|
||||
beacons: Beacon[];
|
||||
|
@ -29,36 +29,31 @@ interface Props {
|
|||
onBeaconClick: (beacon: Beacon) => void;
|
||||
}
|
||||
|
||||
const DialogSidebar: React.FC<Props> = ({
|
||||
beacons,
|
||||
onBeaconClick,
|
||||
requestClose,
|
||||
}) => {
|
||||
return <div className='mx_DialogSidebar'>
|
||||
<div className='mx_DialogSidebar_header'>
|
||||
<Heading size='h4'>{ _t('View List') }</Heading>
|
||||
<AccessibleButton
|
||||
className='mx_DialogSidebar_closeButton'
|
||||
onClick={requestClose}
|
||||
title={_t('Close sidebar')}
|
||||
data-testid='dialog-sidebar-close'
|
||||
>
|
||||
<CloseIcon className='mx_DialogSidebar_closeButtonIcon' />
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
{ beacons?.length
|
||||
? <ol className='mx_DialogSidebar_list'>
|
||||
{ beacons.map((beacon) => <BeaconListItem
|
||||
key={beacon.identifier}
|
||||
beacon={beacon}
|
||||
onClick={() => onBeaconClick(beacon)}
|
||||
/>) }
|
||||
</ol>
|
||||
: <div className='mx_DialogSidebar_noResults'>
|
||||
{ _t('No live locations') }
|
||||
const DialogSidebar: React.FC<Props> = ({ beacons, onBeaconClick, requestClose }) => {
|
||||
return (
|
||||
<div className="mx_DialogSidebar">
|
||||
<div className="mx_DialogSidebar_header">
|
||||
<Heading size="h4">{_t("View List")}</Heading>
|
||||
<AccessibleButton
|
||||
className="mx_DialogSidebar_closeButton"
|
||||
onClick={requestClose}
|
||||
title={_t("Close sidebar")}
|
||||
data-testid="dialog-sidebar-close"
|
||||
>
|
||||
<CloseIcon className="mx_DialogSidebar_closeButtonIcon" />
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
}
|
||||
</div>;
|
||||
{beacons?.length ? (
|
||||
<ol className="mx_DialogSidebar_list">
|
||||
{beacons.map((beacon) => (
|
||||
<BeaconListItem key={beacon.identifier} beacon={beacon} onClick={() => onBeaconClick(beacon)} />
|
||||
))}
|
||||
</ol>
|
||||
) : (
|
||||
<div className="mx_DialogSidebar_noResults">{_t("No live locations")}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogSidebar;
|
||||
|
|
|
@ -14,18 +14,18 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Beacon, BeaconIdentifier } from 'matrix-js-sdk/src/matrix';
|
||||
import classNames from "classnames";
|
||||
import React, { useEffect } from "react";
|
||||
import { Beacon, BeaconIdentifier } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
|
||||
import { Icon as LiveLocationIcon } from '../../../../res/img/location/live-location.svg';
|
||||
import { ViewRoomPayload } from '../../../dispatcher/payloads/ViewRoomPayload';
|
||||
import { Action } from '../../../dispatcher/actions';
|
||||
import dispatcher from '../../../dispatcher/dispatcher';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../stores/OwnBeaconStore";
|
||||
import { Icon as LiveLocationIcon } from "../../../../res/img/location/live-location.svg";
|
||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import dispatcher from "../../../dispatcher/dispatcher";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
||||
interface Props {
|
||||
isMinimized?: boolean;
|
||||
|
@ -52,12 +52,12 @@ const chooseBestBeacon = (
|
|||
|
||||
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
|
||||
if (hasStoppingErrors) {
|
||||
return _t('An error occurred while stopping your live location');
|
||||
return _t("An error occurred while stopping your live location");
|
||||
}
|
||||
if (hasLocationErrors) {
|
||||
return _t('An error occurred whilst sharing your live location');
|
||||
return _t("An error occurred whilst sharing your live location");
|
||||
}
|
||||
return _t('You are sharing your live location');
|
||||
return _t("You are sharing your live location");
|
||||
};
|
||||
|
||||
const useLivenessMonitor = (liveBeaconIds: BeaconIdentifier[], beacons: Map<BeaconIdentifier, Beacon>): void => {
|
||||
|
@ -66,8 +66,8 @@ const useLivenessMonitor = (liveBeaconIds: BeaconIdentifier[], beacons: Map<Beac
|
|||
// for inactive tabs
|
||||
// refresh beacon monitors when the tab becomes active again
|
||||
const onPageVisibilityChanged = () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
liveBeaconIds.forEach(identifier => beacons.get(identifier)?.monitorLiveness());
|
||||
if (document.visibilityState === "visible") {
|
||||
liveBeaconIds.forEach((identifier) => beacons.get(identifier)?.monitorLiveness());
|
||||
}
|
||||
};
|
||||
if (liveBeaconIds.length) {
|
||||
|
@ -95,15 +95,14 @@ const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
|
|||
const beaconIdsWithStoppingError = useEventEmitterState(
|
||||
OwnBeaconStore.instance,
|
||||
OwnBeaconStoreEvent.BeaconUpdateError,
|
||||
() => OwnBeaconStore.instance.getLiveBeaconIds().filter(
|
||||
beaconId => OwnBeaconStore.instance.beaconUpdateErrors.has(beaconId),
|
||||
),
|
||||
() =>
|
||||
OwnBeaconStore.instance
|
||||
.getLiveBeaconIds()
|
||||
.filter((beaconId) => OwnBeaconStore.instance.beaconUpdateErrors.has(beaconId)),
|
||||
);
|
||||
|
||||
const liveBeaconIds = useEventEmitterState(
|
||||
OwnBeaconStore.instance,
|
||||
OwnBeaconStoreEvent.LivenessChange,
|
||||
() => OwnBeaconStore.instance.getLiveBeaconIds(),
|
||||
const liveBeaconIds = useEventEmitterState(OwnBeaconStore.instance, OwnBeaconStoreEvent.LivenessChange, () =>
|
||||
OwnBeaconStore.instance.getLiveBeaconIds(),
|
||||
);
|
||||
|
||||
const hasLocationPublishErrors = !!beaconIdsWithLocationPublishError.length;
|
||||
|
@ -116,32 +115,38 @@ const LeftPanelLiveShareWarning: React.FC<Props> = ({ isMinimized }) => {
|
|||
}
|
||||
|
||||
const relevantBeacon = chooseBestBeacon(
|
||||
liveBeaconIds, beaconIdsWithStoppingError, beaconIdsWithLocationPublishError,
|
||||
liveBeaconIds,
|
||||
beaconIdsWithStoppingError,
|
||||
beaconIdsWithLocationPublishError,
|
||||
);
|
||||
|
||||
const onWarningClick = relevantBeacon ? () => {
|
||||
dispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: relevantBeacon.roomId,
|
||||
metricsTrigger: undefined,
|
||||
event_id: relevantBeacon.beaconInfoId,
|
||||
scroll_into_view: true,
|
||||
highlighted: true,
|
||||
});
|
||||
} : undefined;
|
||||
const onWarningClick = relevantBeacon
|
||||
? () => {
|
||||
dispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: relevantBeacon.roomId,
|
||||
metricsTrigger: undefined,
|
||||
event_id: relevantBeacon.beaconInfoId,
|
||||
scroll_into_view: true,
|
||||
highlighted: true,
|
||||
});
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const label = getLabel(hasStoppingErrors, hasLocationPublishErrors);
|
||||
|
||||
return <AccessibleButton
|
||||
className={classNames('mx_LeftPanelLiveShareWarning', {
|
||||
'mx_LeftPanelLiveShareWarning__minimized': isMinimized,
|
||||
'mx_LeftPanelLiveShareWarning__error': hasLocationPublishErrors || hasStoppingErrors,
|
||||
})}
|
||||
title={isMinimized ? label : undefined}
|
||||
onClick={onWarningClick}
|
||||
>
|
||||
{ isMinimized ? <LiveLocationIcon height={10} /> : label }
|
||||
</AccessibleButton>;
|
||||
return (
|
||||
<AccessibleButton
|
||||
className={classNames("mx_LeftPanelLiveShareWarning", {
|
||||
mx_LeftPanelLiveShareWarning__minimized: isMinimized,
|
||||
mx_LeftPanelLiveShareWarning__error: hasLocationPublishErrors || hasStoppingErrors,
|
||||
})}
|
||||
title={isMinimized ? label : undefined}
|
||||
onClick={onWarningClick}
|
||||
>
|
||||
{isMinimized ? <LiveLocationIcon height={10} /> : label}
|
||||
</AccessibleButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default LeftPanelLiveShareWarning;
|
||||
|
|
|
@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { BeaconEvent, Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { BeaconEvent, Beacon } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { formatDuration } from '../../../DateUtils';
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import { useInterval } from '../../../hooks/useTimeout';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { getBeaconMsUntilExpiry } from '../../../utils/beacon';
|
||||
import { formatDuration } from "../../../DateUtils";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import { useInterval } from "../../../hooks/useTimeout";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { getBeaconMsUntilExpiry } from "../../../utils/beacon";
|
||||
|
||||
const MINUTE_MS = 60000;
|
||||
const HOUR_MS = MINUTE_MS * 60;
|
||||
|
@ -38,11 +38,7 @@ const getUpdateInterval = (ms: number) => {
|
|||
return 1000;
|
||||
};
|
||||
const useMsRemaining = (beacon: Beacon): number => {
|
||||
const beaconInfo = useEventEmitterState(
|
||||
beacon,
|
||||
BeaconEvent.Update,
|
||||
() => beacon.beaconInfo,
|
||||
);
|
||||
const beaconInfo = useEventEmitterState(beacon, BeaconEvent.Update, () => beacon.beaconInfo);
|
||||
|
||||
const [msRemaining, setMsRemaining] = useState(() => getBeaconMsUntilExpiry(beaconInfo));
|
||||
|
||||
|
@ -66,10 +62,11 @@ const LiveTimeRemaining: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
|
|||
const timeRemaining = formatDuration(msRemaining);
|
||||
const liveTimeRemaining = _t(`%(timeRemaining)s left`, { timeRemaining });
|
||||
|
||||
return <span
|
||||
data-test-id='room-live-share-expiry'
|
||||
className="mx_LiveTimeRemaining"
|
||||
>{ liveTimeRemaining }</span>;
|
||||
return (
|
||||
<span data-test-id="room-live-share-expiry" className="mx_LiveTimeRemaining">
|
||||
{liveTimeRemaining}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default LiveTimeRemaining;
|
||||
|
|
|
@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import React, { HTMLProps } from 'react';
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
import React, { HTMLProps } from "react";
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { useOwnLiveBeacons } from '../../../utils/beacon';
|
||||
import { preventDefaultWrapper } from '../../../utils/NativeEventUtils';
|
||||
import BeaconStatus from './BeaconStatus';
|
||||
import { BeaconDisplayStatus } from './displayStatus';
|
||||
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { useOwnLiveBeacons } from "../../../utils/beacon";
|
||||
import { preventDefaultWrapper } from "../../../utils/NativeEventUtils";
|
||||
import BeaconStatus from "./BeaconStatus";
|
||||
import { BeaconDisplayStatus } from "./displayStatus";
|
||||
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||
|
||||
interface Props {
|
||||
displayStatus: BeaconDisplayStatus;
|
||||
|
@ -35,9 +35,7 @@ interface Props {
|
|||
* Wraps BeaconStatus with more capabilities
|
||||
* for errors and actions available for users own live beacons
|
||||
*/
|
||||
const OwnBeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
|
||||
beacon, displayStatus, ...rest
|
||||
}) => {
|
||||
const OwnBeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({ beacon, displayStatus, ...rest }) => {
|
||||
const {
|
||||
hasLocationPublishError,
|
||||
hasStopSharingError,
|
||||
|
@ -47,51 +45,55 @@ const OwnBeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
|
|||
} = useOwnLiveBeacons([beacon?.identifier]);
|
||||
|
||||
// combine display status with errors that only occur for user's own beacons
|
||||
const ownDisplayStatus = hasLocationPublishError || hasStopSharingError ?
|
||||
BeaconDisplayStatus.Error :
|
||||
displayStatus;
|
||||
const ownDisplayStatus = hasLocationPublishError || hasStopSharingError ? BeaconDisplayStatus.Error : displayStatus;
|
||||
|
||||
return <BeaconStatus
|
||||
beacon={beacon}
|
||||
displayStatus={ownDisplayStatus}
|
||||
label={_t('Live location enabled')}
|
||||
displayLiveTimeRemaining
|
||||
{...rest}
|
||||
>
|
||||
{ ownDisplayStatus === BeaconDisplayStatus.Active && <AccessibleButton
|
||||
data-test-id='beacon-status-stop-beacon'
|
||||
kind='link'
|
||||
// eat events here to avoid 1) the map and 2) reply or thread tiles
|
||||
// moving under the beacon status on stop/retry click
|
||||
onClick={preventDefaultWrapper<ButtonEvent>(onStopSharing)}
|
||||
className='mx_OwnBeaconStatus_button mx_OwnBeaconStatus_destructiveButton'
|
||||
disabled={stoppingInProgress}
|
||||
return (
|
||||
<BeaconStatus
|
||||
beacon={beacon}
|
||||
displayStatus={ownDisplayStatus}
|
||||
label={_t("Live location enabled")}
|
||||
displayLiveTimeRemaining
|
||||
{...rest}
|
||||
>
|
||||
{ _t('Stop') }
|
||||
</AccessibleButton>
|
||||
}
|
||||
{ hasLocationPublishError && <AccessibleButton
|
||||
data-test-id='beacon-status-reset-wire-error'
|
||||
kind='link'
|
||||
// eat events here to avoid 1) the map and 2) reply or thread tiles
|
||||
// moving under the beacon status on stop/retry click
|
||||
onClick={preventDefaultWrapper(onResetLocationPublishError)}
|
||||
className='mx_OwnBeaconStatus_button mx_OwnBeaconStatus_destructiveButton'
|
||||
>
|
||||
{ _t('Retry') }
|
||||
</AccessibleButton>
|
||||
}
|
||||
{ hasStopSharingError && <AccessibleButton
|
||||
data-test-id='beacon-status-stop-beacon-retry'
|
||||
kind='link'
|
||||
// eat events here to avoid 1) the map and 2) reply or thread tiles
|
||||
// moving under the beacon status on stop/retry click
|
||||
onClick={preventDefaultWrapper(onStopSharing)}
|
||||
className='mx_OwnBeaconStatus_button mx_OwnBeaconStatus_destructiveButton'
|
||||
>
|
||||
{ _t('Retry') }
|
||||
</AccessibleButton> }
|
||||
</BeaconStatus>;
|
||||
{ownDisplayStatus === BeaconDisplayStatus.Active && (
|
||||
<AccessibleButton
|
||||
data-test-id="beacon-status-stop-beacon"
|
||||
kind="link"
|
||||
// eat events here to avoid 1) the map and 2) reply or thread tiles
|
||||
// moving under the beacon status on stop/retry click
|
||||
onClick={preventDefaultWrapper<ButtonEvent>(onStopSharing)}
|
||||
className="mx_OwnBeaconStatus_button mx_OwnBeaconStatus_destructiveButton"
|
||||
disabled={stoppingInProgress}
|
||||
>
|
||||
{_t("Stop")}
|
||||
</AccessibleButton>
|
||||
)}
|
||||
{hasLocationPublishError && (
|
||||
<AccessibleButton
|
||||
data-test-id="beacon-status-reset-wire-error"
|
||||
kind="link"
|
||||
// eat events here to avoid 1) the map and 2) reply or thread tiles
|
||||
// moving under the beacon status on stop/retry click
|
||||
onClick={preventDefaultWrapper(onResetLocationPublishError)}
|
||||
className="mx_OwnBeaconStatus_button mx_OwnBeaconStatus_destructiveButton"
|
||||
>
|
||||
{_t("Retry")}
|
||||
</AccessibleButton>
|
||||
)}
|
||||
{hasStopSharingError && (
|
||||
<AccessibleButton
|
||||
data-test-id="beacon-status-stop-beacon-retry"
|
||||
kind="link"
|
||||
// eat events here to avoid 1) the map and 2) reply or thread tiles
|
||||
// moving under the beacon status on stop/retry click
|
||||
onClick={preventDefaultWrapper(onStopSharing)}
|
||||
className="mx_OwnBeaconStatus_button mx_OwnBeaconStatus_destructiveButton"
|
||||
>
|
||||
{_t("Retry")}
|
||||
</AccessibleButton>
|
||||
)}
|
||||
</BeaconStatus>
|
||||
);
|
||||
};
|
||||
|
||||
export default OwnBeaconStatus;
|
||||
|
|
|
@ -27,10 +27,7 @@ import { Action } from "../../../dispatcher/actions";
|
|||
import { ConnectionState, ElementCall } from "../../../models/Call";
|
||||
import { useCall } from "../../../hooks/useCall";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import {
|
||||
OwnBeaconStore,
|
||||
OwnBeaconStoreEvent,
|
||||
} from "../../../stores/OwnBeaconStore";
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../stores/OwnBeaconStore";
|
||||
import { GroupCallDuration } from "../voip/CallDuration";
|
||||
import { SdkContextClass } from "../../../contexts/SDKContext";
|
||||
|
||||
|
@ -39,10 +36,7 @@ interface RoomCallBannerProps {
|
|||
call: ElementCall;
|
||||
}
|
||||
|
||||
const RoomCallBannerInner: React.FC<RoomCallBannerProps> = ({
|
||||
roomId,
|
||||
call,
|
||||
}) => {
|
||||
const RoomCallBannerInner: React.FC<RoomCallBannerProps> = ({ roomId, call }) => {
|
||||
const connect = useCallback(
|
||||
(ev: ButtonEvent) => {
|
||||
ev.preventDefault();
|
||||
|
@ -58,7 +52,8 @@ const RoomCallBannerInner: React.FC<RoomCallBannerProps> = ({
|
|||
|
||||
const onClick = useCallback(() => {
|
||||
const event = call.groupCall.room.currentState.getStateEvents(
|
||||
EventType.GroupCallPrefix, call.groupCall.groupCallId,
|
||||
EventType.GroupCallPrefix,
|
||||
call.groupCall.groupCallId,
|
||||
);
|
||||
if (event === null) {
|
||||
logger.error("Couldn't find a group call event to jump to");
|
||||
|
@ -76,22 +71,14 @@ const RoomCallBannerInner: React.FC<RoomCallBannerProps> = ({
|
|||
}, [call, roomId]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="mx_RoomCallBanner"
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="mx_RoomCallBanner" onClick={onClick}>
|
||||
<div className="mx_RoomCallBanner_text">
|
||||
<span className="mx_RoomCallBanner_label">{ _t("Video call") }</span>
|
||||
<span className="mx_RoomCallBanner_label">{_t("Video call")}</span>
|
||||
<GroupCallDuration groupCall={call.groupCall} />
|
||||
</div>
|
||||
|
||||
<AccessibleButton
|
||||
onClick={connect}
|
||||
kind="primary"
|
||||
element="button"
|
||||
disabled={false}
|
||||
>
|
||||
{ _t("Join") }
|
||||
<AccessibleButton onClick={connect} kind="primary" element="button" disabled={false}>
|
||||
{_t("Join")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
);
|
||||
|
@ -111,10 +98,8 @@ const RoomCallBanner: React.FC<Props> = ({ roomId }) => {
|
|||
() => OwnBeaconStore.instance.isMonitoringLiveLocation,
|
||||
);
|
||||
|
||||
const liveBeaconIds = useEventEmitterState(
|
||||
OwnBeaconStore.instance,
|
||||
OwnBeaconStoreEvent.LivenessChange,
|
||||
() => OwnBeaconStore.instance.getLiveBeaconIds(roomId),
|
||||
const liveBeaconIds = useEventEmitterState(OwnBeaconStore.instance, OwnBeaconStoreEvent.LivenessChange, () =>
|
||||
OwnBeaconStore.instance.getLiveBeaconIds(roomId),
|
||||
);
|
||||
|
||||
if (isMonitoringLiveLocation && liveBeaconIds.length) {
|
||||
|
|
|
@ -14,35 +14,35 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Room } from 'matrix-js-sdk/src/matrix';
|
||||
import React from "react";
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { useEventEmitterState } from '../../../hooks/useEventEmitter';
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
|
||||
import { useOwnLiveBeacons } from '../../../utils/beacon';
|
||||
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
|
||||
import Spinner from '../elements/Spinner';
|
||||
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
|
||||
import { Icon as CloseIcon } from '../../../../res/img/image-view/close.svg';
|
||||
import LiveTimeRemaining from './LiveTimeRemaining';
|
||||
import dispatcher from '../../../dispatcher/dispatcher';
|
||||
import { ViewRoomPayload } from '../../../dispatcher/payloads/ViewRoomPayload';
|
||||
import { Action } from '../../../dispatcher/actions';
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../stores/OwnBeaconStore";
|
||||
import { useOwnLiveBeacons } from "../../../utils/beacon";
|
||||
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import StyledLiveBeaconIcon from "./StyledLiveBeaconIcon";
|
||||
import { Icon as CloseIcon } from "../../../../res/img/image-view/close.svg";
|
||||
import LiveTimeRemaining from "./LiveTimeRemaining";
|
||||
import dispatcher from "../../../dispatcher/dispatcher";
|
||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
|
||||
const getLabel = (hasLocationPublishError: boolean, hasStopSharingError: boolean): string => {
|
||||
if (hasLocationPublishError) {
|
||||
return _t('An error occurred whilst sharing your live location, please try again');
|
||||
return _t("An error occurred whilst sharing your live location, please try again");
|
||||
}
|
||||
if (hasStopSharingError) {
|
||||
return _t('An error occurred while stopping your live location, please try again');
|
||||
return _t("An error occurred while stopping your live location, please try again");
|
||||
}
|
||||
return _t('You are sharing your live location');
|
||||
return _t("You are sharing your live location");
|
||||
};
|
||||
|
||||
interface RoomLiveShareWarningInnerProps {
|
||||
liveBeaconIds: string[];
|
||||
roomId: Room['roomId'];
|
||||
roomId: Room["roomId"];
|
||||
}
|
||||
const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ liveBeaconIds, roomId }) => {
|
||||
const {
|
||||
|
@ -86,45 +86,48 @@ const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ l
|
|||
});
|
||||
};
|
||||
|
||||
return <div
|
||||
className='mx_RoomLiveShareWarning'
|
||||
onClick={onClick}
|
||||
>
|
||||
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasError} />
|
||||
return (
|
||||
<div className="mx_RoomLiveShareWarning" onClick={onClick}>
|
||||
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasError} />
|
||||
|
||||
<span className="mx_RoomLiveShareWarning_label">
|
||||
{ getLabel(hasLocationPublishError, hasStopSharingError) }
|
||||
</span>
|
||||
<span className="mx_RoomLiveShareWarning_label">
|
||||
{getLabel(hasLocationPublishError, hasStopSharingError)}
|
||||
</span>
|
||||
|
||||
{ stoppingInProgress &&
|
||||
<span className='mx_RoomLiveShareWarning_spinner'><Spinner h={16} w={16} /></span>
|
||||
}
|
||||
{ !stoppingInProgress && !hasError && <LiveTimeRemaining beacon={beacon} /> }
|
||||
{stoppingInProgress && (
|
||||
<span className="mx_RoomLiveShareWarning_spinner">
|
||||
<Spinner h={16} w={16} />
|
||||
</span>
|
||||
)}
|
||||
{!stoppingInProgress && !hasError && <LiveTimeRemaining beacon={beacon} />}
|
||||
|
||||
<AccessibleButton
|
||||
className='mx_RoomLiveShareWarning_stopButton'
|
||||
data-test-id='room-live-share-primary-button'
|
||||
onClick={stopPropagationWrapper(onButtonClick)}
|
||||
kind='danger'
|
||||
element='button'
|
||||
disabled={stoppingInProgress}
|
||||
>
|
||||
{ hasError ? _t('Retry') : _t('Stop') }
|
||||
</AccessibleButton>
|
||||
{ hasLocationPublishError && <AccessibleButton
|
||||
data-test-id='room-live-share-wire-error-close-button'
|
||||
title={_t('Stop and close')}
|
||||
element='button'
|
||||
className='mx_RoomLiveShareWarning_closeButton'
|
||||
onClick={stopPropagationWrapper(onStopSharing)}
|
||||
>
|
||||
<CloseIcon className='mx_RoomLiveShareWarning_closeButtonIcon' />
|
||||
</AccessibleButton> }
|
||||
</div>;
|
||||
<AccessibleButton
|
||||
className="mx_RoomLiveShareWarning_stopButton"
|
||||
data-test-id="room-live-share-primary-button"
|
||||
onClick={stopPropagationWrapper(onButtonClick)}
|
||||
kind="danger"
|
||||
element="button"
|
||||
disabled={stoppingInProgress}
|
||||
>
|
||||
{hasError ? _t("Retry") : _t("Stop")}
|
||||
</AccessibleButton>
|
||||
{hasLocationPublishError && (
|
||||
<AccessibleButton
|
||||
data-test-id="room-live-share-wire-error-close-button"
|
||||
title={_t("Stop and close")}
|
||||
element="button"
|
||||
className="mx_RoomLiveShareWarning_closeButton"
|
||||
onClick={stopPropagationWrapper(onStopSharing)}
|
||||
>
|
||||
<CloseIcon className="mx_RoomLiveShareWarning_closeButtonIcon" />
|
||||
</AccessibleButton>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
roomId: Room['roomId'];
|
||||
roomId: Room["roomId"];
|
||||
}
|
||||
const RoomLiveShareWarning: React.FC<Props> = ({ roomId }) => {
|
||||
// do we have an active geolocation.watchPosition
|
||||
|
@ -134,10 +137,8 @@ const RoomLiveShareWarning: React.FC<Props> = ({ roomId }) => {
|
|||
() => OwnBeaconStore.instance.isMonitoringLiveLocation,
|
||||
);
|
||||
|
||||
const liveBeaconIds = useEventEmitterState(
|
||||
OwnBeaconStore.instance,
|
||||
OwnBeaconStoreEvent.LivenessChange,
|
||||
() => OwnBeaconStore.instance.getLiveBeaconIds(roomId),
|
||||
const liveBeaconIds = useEventEmitterState(OwnBeaconStore.instance, OwnBeaconStoreEvent.LivenessChange, () =>
|
||||
OwnBeaconStore.instance.getLiveBeaconIds(roomId),
|
||||
);
|
||||
|
||||
if (!isMonitoringLiveLocation || !liveBeaconIds.length) {
|
||||
|
|
|
@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { BeaconLocationState } from 'matrix-js-sdk/src/content-helpers';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BeaconLocationState } from "matrix-js-sdk/src/content-helpers";
|
||||
|
||||
import { Icon as ExternalLinkIcon } from '../../../../res/img/external-link.svg';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { makeMapSiteLink, parseGeoUri } from '../../../utils/location';
|
||||
import CopyableText from '../elements/CopyableText';
|
||||
import TooltipTarget from '../elements/TooltipTarget';
|
||||
import { Icon as ExternalLinkIcon } from "../../../../res/img/external-link.svg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { makeMapSiteLink, parseGeoUri } from "../../../utils/location";
|
||||
import CopyableText from "../elements/CopyableText";
|
||||
import TooltipTarget from "../elements/TooltipTarget";
|
||||
|
||||
interface Props {
|
||||
latestLocationState?: BeaconLocationState;
|
||||
|
@ -44,23 +44,16 @@ const ShareLatestLocation: React.FC<Props> = ({ latestLocationState }) => {
|
|||
const latLonString = `${coords.latitude},${coords.longitude}`;
|
||||
const mapLink = makeMapSiteLink(coords);
|
||||
|
||||
return <>
|
||||
<TooltipTarget label={_t('Open in OpenStreetMap')}>
|
||||
<a
|
||||
data-testid='open-location-in-osm'
|
||||
href={mapLink}
|
||||
target='_blank'
|
||||
rel='noreferrer noopener'
|
||||
>
|
||||
<ExternalLinkIcon className='mx_ShareLatestLocation_icon' />
|
||||
</a>
|
||||
</TooltipTarget>
|
||||
<CopyableText
|
||||
className='mx_ShareLatestLocation_copy'
|
||||
border={false}
|
||||
getTextToCopy={() => latLonString}
|
||||
/>
|
||||
</>;
|
||||
return (
|
||||
<>
|
||||
<TooltipTarget label={_t("Open in OpenStreetMap")}>
|
||||
<a data-testid="open-location-in-osm" href={mapLink} target="_blank" rel="noreferrer noopener">
|
||||
<ExternalLinkIcon className="mx_ShareLatestLocation_icon" />
|
||||
</a>
|
||||
</TooltipTarget>
|
||||
<CopyableText className="mx_ShareLatestLocation_copy" border={false} getTextToCopy={() => latLonString} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShareLatestLocation;
|
||||
|
|
|
@ -14,27 +14,24 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { Icon as LiveLocationIcon } from '../../../../res/img/location/live-location.svg';
|
||||
import { Icon as LiveLocationIcon } from "../../../../res/img/location/live-location.svg";
|
||||
|
||||
interface Props extends React.SVGProps<SVGSVGElement> {
|
||||
// use error styling when true
|
||||
withError?: boolean;
|
||||
isIdle?: boolean;
|
||||
}
|
||||
const StyledLiveBeaconIcon: React.FC<Props> = ({ className, withError, isIdle, ...props }) =>
|
||||
const StyledLiveBeaconIcon: React.FC<Props> = ({ className, withError, isIdle, ...props }) => (
|
||||
<LiveLocationIcon
|
||||
{...props}
|
||||
className={classNames(
|
||||
'mx_StyledLiveBeaconIcon',
|
||||
className,
|
||||
{
|
||||
'mx_StyledLiveBeaconIcon_error': withError,
|
||||
'mx_StyledLiveBeaconIcon_idle': isIdle,
|
||||
|
||||
})}
|
||||
/>;
|
||||
className={classNames("mx_StyledLiveBeaconIcon", className, {
|
||||
mx_StyledLiveBeaconIcon_error: withError,
|
||||
mx_StyledLiveBeaconIcon_idle: isIdle,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
|
||||
export default StyledLiveBeaconIcon;
|
||||
|
|
|
@ -17,10 +17,10 @@ limitations under the License.
|
|||
import { BeaconLocationState } from "matrix-js-sdk/src/content-helpers";
|
||||
|
||||
export enum BeaconDisplayStatus {
|
||||
Loading = 'Loading',
|
||||
Error = 'Error',
|
||||
Stopped = 'Stopped',
|
||||
Active = 'Active',
|
||||
Loading = "Loading",
|
||||
Error = "Error",
|
||||
Stopped = "Stopped",
|
||||
Active = "Active",
|
||||
}
|
||||
export const getBeaconDisplayStatus = (
|
||||
isLive: boolean,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue