Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-sanderson committed Feb 19, 2025
1 parent 8bf10a7 commit 3049fae
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 33 deletions.
16 changes: 11 additions & 5 deletions packages/suite/src/actions/bluetooth/initBluetoothThunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
BLUETOOTH_PREFIX,
bluetoothAdapterEventAction,
bluetoothConnectDeviceEventAction,
bluetoothKnownDevicesUpdateAction,
bluetoothNearbyDevicesUpdateAction,
selectKnownDevices,
} from '@suite-common/bluetooth';
Expand Down Expand Up @@ -33,19 +34,24 @@ export const initBluetoothThunk = createThunk<void, void, void>(
dispatch(bluetoothAdapterEventAction({ isPowered }));
});

bluetoothIpc.on('device-list-update', devices => {
console.warn('device-list-update', devices);
bluetoothIpc.on('device-list-update', nearbyDevices => {
console.warn('device-list-update', nearbyDevices);

const knownDevices = selectKnownDevices<BluetoothDevice>(getState());

// update pairedDevices, id is changed after pairing (linux)
const linuxFixedDevices = devices.reduce((prev, curr) => {
const remappedKnownDevices = nearbyDevices.reduce((prev, curr) => {
// find devices with the same address but different id
const changed = devices.find(d => d.address === curr.address && d.id !== curr.id);
const changed = knownDevices.find(
d => d.address === curr.address && d.id !== curr.id,
);
prev.push(changed ? { ...curr, id: changed.id } : curr);

return prev;
}, [] as BluetoothDevice[]);

dispatch(bluetoothNearbyDevicesUpdateAction({ nearbyDevices: linuxFixedDevices }));
dispatch(bluetoothKnownDevicesUpdateAction({ knownDevices: remappedKnownDevices }));
dispatch(bluetoothNearbyDevicesUpdateAction({ nearbyDevices }));
});

bluetoothIpc.on('device-connection-status', connectionStatus => {
Expand Down
31 changes: 10 additions & 21 deletions packages/suite/src/components/suite/bluetooth/BluetoothConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import { useCallback, useEffect, useState } from 'react';
import {
bluetoothConnectDeviceEventAction,
bluetoothScanStatusAction,
prepareSelectAllDevices,
selectAdapterStatus,
selectNearbyDevices,
selectScanStatus,
} from '@suite-common/bluetooth';
import { notificationsActions } from '@suite-common/toast-notifications';
import { Card, Column, ElevationUp } from '@trezor/components';
import TrezorConnect from '@trezor/connect';
import { spacings } from '@trezor/theme';
import { BluetoothDevice } from '@trezor/transport-bluetooth';
import { TimerId } from '@trezor/type-utils';
Expand All @@ -34,18 +33,20 @@ type BluetoothConnectProps = {
uiMode: 'spatial' | 'card';
};

const selectAllDevices = prepareSelectAllDevices<BluetoothDevice>();

export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) => {
const dispatch = useDispatch();
const [selectedDeviceId, setSelectedDeviceId] = useState<string | null>(null);
const [scannerTimerId, setScannerTimerId] = useState<TimerId | null>(null);

const bluetoothAdapterStatus = useSelector(selectAdapterStatus);
const scanStatus = useSelector(selectScanStatus);
const nearbyDevices = useSelector(selectNearbyDevices<BluetoothDevice>);
const devices = useSelector(selectAllDevices);

const selectedDevice =
selectedDeviceId !== null
? nearbyDevices.find(device => device.device.id === selectedDeviceId)
? devices.find(device => device.device.id === selectedDeviceId)
: undefined;

useEffect(() => {
Expand Down Expand Up @@ -84,7 +85,6 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>

const onSelect = async (id: string) => {
setSelectedDeviceId(id);

const result = await dispatch(bluetoothConnectDeviceThunk({ id })).unwrap();

if (!result.success) {
Expand All @@ -101,23 +101,12 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>
}),
);
} else {
// Todo: What to do with error in this flow? UI-Wise

dispatch(
bluetoothConnectDeviceEventAction({
id,
connectionStatus: { type: 'connected' },
}),
);

// WAIT for connect event, TODO: figure out better way
const closePopupAfterConnection = () => {
TrezorConnect.off('device-connect', closePopupAfterConnection);
TrezorConnect.off('device-connect_unacquired', closePopupAfterConnection);
// setSelectedDeviceStatus({ type: 'error', id }); // Todo: what here?
};
TrezorConnect.on('device-connect', closePopupAfterConnection);
TrezorConnect.on('device-connect_unacquired', closePopupAfterConnection);
}
};

Expand All @@ -135,7 +124,7 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>

// This is fake, we scan for devices all the time
const isScanning = scanStatus === 'running';
const scanFailed = nearbyDevices.length === 0 && scanStatus === 'idle';
const scanFailed = devices.length === 0 && scanStatus === 'idle';

const handlePairingCancel = () => {
setSelectedDeviceId(null);
Expand Down Expand Up @@ -167,7 +156,7 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>
<BluetoothDeviceList
isDisabled={false}
onSelect={onSelect}
deviceList={nearbyDevices}
deviceList={devices}
isScanning={isScanning}
/>
);
Expand All @@ -183,7 +172,7 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>
<BluetoothScanHeader
isScanning={isScanning}
onClose={onClose}
numberOfDevices={nearbyDevices.length}
numberOfDevices={devices.length}
/>

{/* Here we need to do +1 in elevation because of custom design on the welcome screen */}
Expand All @@ -192,7 +181,7 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>
{uiMode === 'card' && (
<BluetoothScanFooter
onReScanClick={onReScanClick}
numberOfDevices={nearbyDevices.length}
numberOfDevices={devices.length}
scanStatus={scanStatus}
/>
)}
Expand All @@ -205,7 +194,7 @@ export const BluetoothConnect = ({ onClose, uiMode }: BluetoothConnectProps) =>
<ElevationUp>
<BluetoothScanFooter
onReScanClick={onReScanClick}
numberOfDevices={nearbyDevices.length}
numberOfDevices={devices.length}
scanStatus={scanStatus}
/>
</ElevationUp>
Expand Down
6 changes: 5 additions & 1 deletion packages/suite/src/middlewares/wallet/storageMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { isAnyOf } from '@reduxjs/toolkit';
import { MiddlewareAPI } from 'redux';

import { analyticsActions } from '@suite-common/analytics';
import { bluetoothKnownDevicesUpdateAction } from '@suite-common/bluetooth';
import { messageSystemActions } from '@suite-common/message-system';
import { isDeviceRemembered } from '@suite-common/suite-utils';
import { TokenManagementAction } from '@suite-common/token-definitions';
Expand Down Expand Up @@ -202,7 +203,10 @@ const storageMiddleware = (api: MiddlewareAPI<Dispatch, AppState>) => {
}
}

if (deviceActions.connectDevice.match(action)) {
if (
deviceActions.connectDevice.match(action) ||
bluetoothKnownDevicesUpdateAction.match(action)
) {
api.dispatch(storageActions.saveKnownDevices());
}

Expand Down
12 changes: 12 additions & 0 deletions suite-common/bluetooth/src/bluetoothActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ export const bluetoothNearbyDevicesUpdateAction = createAction(
}),
);

type BluetoothKnownDevicesUpdateActionPayload = {
knownDevices: BluetoothDeviceCommon[];
};

export const bluetoothKnownDevicesUpdateAction = createAction(
`${BLUETOOTH_PREFIX}/known-devices-update`,
({ knownDevices }: BluetoothKnownDevicesUpdateActionPayload) => ({
payload: { knownDevices },
}),
);

export const bluetoothConnectDeviceEventAction = createAction(
`${BLUETOOTH_PREFIX}/connect-device-event`,
({ connectionStatus, id }: { id: string; connectionStatus: DeviceBluetoothStatus }) => ({
Expand All @@ -41,4 +52,5 @@ export const allBluetoothActions = {
bluetoothNearbyDevicesUpdateAction,
bluetoothConnectDeviceEventAction,
bluetoothScanStatusAction,
bluetoothKnownDevicesUpdateAction,
};
8 changes: 6 additions & 2 deletions suite-common/bluetooth/src/bluetoothReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { deviceActions } from '@suite-common/wallet-core';
import {
bluetoothAdapterEventAction,
bluetoothConnectDeviceEventAction,
bluetoothKnownDevicesUpdateAction,
bluetoothNearbyDevicesUpdateAction,
bluetoothScanStatusAction,
} from './bluetoothActions';
Expand Down Expand Up @@ -88,11 +89,14 @@ export const prepareBluetoothReducerCreator = <T extends BluetoothDeviceCommon>(
}
},
)
.addCase(bluetoothKnownDevicesUpdateAction, (state, { payload: { knownDevices } }) => {
state.knownDevices = knownDevices as Draft<T>[];
})
.addCase(bluetoothScanStatusAction, (state, { payload: { status } }) => {
state.scanStatus = status;
})
.addCase(deviceActions.deviceDisconnect, (state, { payload: { bluetoothProps } }) => {
if (bluetoothProps) {
if (bluetoothProps !== undefined) {
state.nearbyDevices = state.nearbyDevices.filter(
it => it.device.id !== bluetoothProps.id,
);
Expand All @@ -108,7 +112,7 @@ export const prepareBluetoothReducerCreator = <T extends BluetoothDeviceCommon>(
},
},
) => {
if (bluetoothProps === undefined || !bluetoothProps.id) {
if (bluetoothProps === undefined) {
return;
}

Expand Down
24 changes: 21 additions & 3 deletions suite-common/bluetooth/src/bluetoothSelectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { BluetoothDeviceCommon, BluetoothState } from './bluetoothReducer';
import { createWeakMapSelector } from '@suite-common/redux-utils';

import { BluetoothDeviceCommon, BluetoothDeviceState, BluetoothState } from './bluetoothReducer';

type State<T extends BluetoothDeviceCommon> = {
bluetooth: BluetoothState<T>;
Expand All @@ -10,8 +12,24 @@ export const selectAdapterStatus = <T extends BluetoothDeviceCommon>(state: Stat
export const selectKnownDevices = <T extends BluetoothDeviceCommon>(state: State<T>) =>
state.bluetooth.knownDevices;

export const selectNearbyDevices = <T extends BluetoothDeviceCommon>(state: State<T>) =>
state.bluetooth.nearbyDevices;
export const prepareSelectAllDevices = <T extends BluetoothDeviceCommon>() =>
createWeakMapSelector.withTypes<State<T>>()(
[state => state.bluetooth.nearbyDevices, state => state.bluetooth.knownDevices],
(nearbyDevices, knownDevices) => {
const map = new Map<string, BluetoothDeviceState<T>>();
knownDevices.forEach(knownDevice => {
map.set(knownDevice.id, { device: knownDevice, status: null });
});

nearbyDevices.forEach(nearbyDevice => {
if (!map.has(nearbyDevice.device.id)) {
map.set(nearbyDevice.device.id, nearbyDevice);
}
});

return Array.from(map.values());
},
);

export const selectScanStatus = <T extends BluetoothDeviceCommon>(state: State<T>) =>
state.bluetooth.scanStatus;
8 changes: 7 additions & 1 deletion suite-common/bluetooth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export {
allBluetoothActions,
bluetoothConnectDeviceEventAction,
bluetoothNearbyDevicesUpdateAction,
bluetoothKnownDevicesUpdateAction,
bluetoothScanStatusAction,
} from './bluetoothActions';

Expand All @@ -14,4 +15,9 @@ export type {
DeviceBluetoothStatusType,
} from './bluetoothReducer';

export * from './bluetoothSelectors';
export {
prepareSelectAllDevices,
selectKnownDevices,
selectAdapterStatus,
selectScanStatus,
} from './bluetoothSelectors';

0 comments on commit 3049fae

Please sign in to comment.