Skip to content

Commit

Permalink
feat(suite-native): offline header shows that app is offline
Browse files Browse the repository at this point in the history
  • Loading branch information
vytick committed Aug 6, 2024
1 parent becfe2b commit 1c6c918
Show file tree
Hide file tree
Showing 30 changed files with 178 additions and 19 deletions.
3 changes: 3 additions & 0 deletions suite-common/icons/assets/icons/wifiSlash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions suite-common/icons/src/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const icons = {
warningOctagon: require('../assets/icons/warningOctagon.svg'),
warningTriangle: require('../assets/icons/warningTriangle.svg'),
warningTriangleLight: require('../assets/icons/warningTriangleLight.svg'),
wifiSlash: require('../assets/icons/wifiSlash.svg'),
} as const;
export type IconName = keyof typeof icons;

Expand Down
2 changes: 1 addition & 1 deletion suite-native/app/e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { expect as detoxExpect } from 'detox';
const APP_LAUNCH_ARGS = {
// Do not synchronize communication with the trezor bridge and metro server running on localhost. Since the trezor
// bridge is exchanging messages with the app all the time, the test runner would wait forever otherwise.
detoxURLBlacklistRegex: '\\("^.*127.0.0.1.*",".*localhost.*"\\)',
detoxURLBlacklistRegex: '\\("^.*127.0.0.1.*",".*localhost.*","^*clients3\\.google\\.com*"\\)',
};

const platform = device.getPlatform();
Expand Down
2 changes: 2 additions & 0 deletions suite-native/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"reverse-ports": "adb reverse tcp:8081 tcp:8081 && adb reverse tcp:21325 tcp:21325 && adb reverse tcp:19121 tcp:19121"
},
"dependencies": {
"@react-native-community/netinfo": "11.3.2",
"@react-native/metro-config": "0.74.83",
"@react-navigation/bottom-tabs": "6.5.20",
"@react-navigation/native": "6.1.17",
Expand All @@ -44,6 +45,7 @@
"@suite-native/biometrics": "workspace:*",
"@suite-native/coin-enabling": "workspace:*",
"@suite-native/config": "workspace:*",
"@suite-native/connection-status": "workspace:*",
"@suite-native/device": "workspace:*",
"@suite-native/device-authorization": "workspace:*",
"@suite-native/feature-flags": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions suite-native/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { selectIsAppReady, selectIsConnectInitialized, StoreProvider } from '@su
import { FormatterProvider } from '@suite-common/formatters';
import { NavigationContainerWithAnalytics } from '@suite-native/navigation';
import { FeatureMessageScreen, MessageSystemBannerRenderer } from '@suite-native/message-system';
import { OfflineBanner } from '@suite-native/connection-status';
import { IntlProvider } from '@suite-native/intl';
import { isDebugEnv } from '@suite-native/config';

Expand Down Expand Up @@ -57,6 +58,7 @@ const AppComponent = () => {

return (
<FormatterProvider config={formattersConfig}>
<OfflineBanner />
<MessageSystemBannerRenderer />
<RootStackNavigator />
<ModalsRenderer />
Expand Down
1 change: 1 addition & 0 deletions suite-native/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
{ "path": "../biometrics" },
{ "path": "../coin-enabling" },
{ "path": "../config" },
{ "path": "../connection-status" },
{ "path": "../device" },
{ "path": "../device-authorization" },
{ "path": "../feature-flags" },
Expand Down
25 changes: 25 additions & 0 deletions suite-native/connection-status/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@suite-native/connection-status",
"version": "1.0.0",
"private": true,
"license": "See LICENSE.md in repo root",
"sideEffects": false,
"main": "src/index",
"scripts": {
"lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'",
"depcheck": "yarn g:depcheck",
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@react-native-community/netinfo": "11.3.2",
"@suite-common/icons": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/intl": "workspace:*",
"@suite-native/settings": "workspace:*",
"@trezor/styles": "workspace:*",
"react": "18.2.0",
"react-native": "0.74.1",
"react-native-safe-area-context": "4.10.3",
"react-redux": "8.0.7"
}
}
45 changes: 45 additions & 0 deletions suite-native/connection-status/src/OfflineBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { View } from 'react-native';

import { Icon } from '@suite-common/icons';
import { Text, HStack } from '@suite-native/atoms';
import { Translation } from '@suite-native/intl';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

import { useIsOfflineBannerVisible } from './useIsOfflineBannerVisible';

const containerStyle = prepareNativeStyle(utils => ({
backgroundColor: utils.colors.backgroundAlertYellowBold,
alignItems: 'center',
}));

const contentStyle = prepareNativeStyle<{ topSafeAreaInset: number }>(
(utils, { topSafeAreaInset }) => ({
marginTop: topSafeAreaInset,
paddingTop: utils.spacings.small,
paddingBottom: 12,
alignItems: 'center',
}),
);

export const OfflineBanner = () => {
const { applyStyle } = useNativeStyles();
const { top: topSafeAreaInset } = useSafeAreaInsets();

const isOfflineBannerVisible = useIsOfflineBannerVisible();

if (!isOfflineBannerVisible) {
return null;
}

return (
<View style={applyStyle(containerStyle)}>
<HStack style={applyStyle(contentStyle, { topSafeAreaInset })}>
<Icon name="wifiSlash" size="mediumLarge" />
<Text>
<Translation id="generic.offline" />
</Text>
</HStack>
</View>
);
};
3 changes: 3 additions & 0 deletions suite-native/connection-status/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './OfflineBanner';
export * from './useOfflineBannerAwareSafeAreaInsets';
export * from './useIsOfflineBannerVisible';
12 changes: 12 additions & 0 deletions suite-native/connection-status/src/useIsOfflineBannerVisible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useSelector } from 'react-redux';

import { useNetInfo } from '@react-native-community/netinfo';

import { selectIsOnboardingFinished } from '@suite-native/settings';

export const useIsOfflineBannerVisible = () => {
const isOnboardingFinished = useSelector(selectIsOnboardingFinished);
const { isConnected } = useNetInfo();

return !isConnected && isOnboardingFinished;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { EdgeInsets, useSafeAreaInsets } from 'react-native-safe-area-context';

import { useIsOfflineBannerVisible } from './useIsOfflineBannerVisible';

// If offline banner is visible, return 0 for top inset, otherwise return the top inset from safe area insets
// this is because the offline banner is displayed on top of the screen and we don't want to add any top padding
export const useOfflineBannerAwareSafeAreaInsets = () => {
const { top, ...rest } = useSafeAreaInsets();
const isOfflineBannerVisible = useIsOfflineBannerVisible();

return { top: isOfflineBannerVisible ? 0 : top, ...rest } as EdgeInsets;
};
12 changes: 12 additions & 0 deletions suite-native/connection-status/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "libDev" },
"references": [
{ "path": "../../suite-common/icons" },
{ "path": "../atoms" },
{ "path": "../intl" },
{ "path": "../settings" },
{ "path": "../../packages/styles" }
],
"include": [".", "**/*.json"]
}
1 change: 1 addition & 0 deletions suite-native/intl/src/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const en = {
unknownError: 'Something went wrong',
default: 'Default',
orSeparator: 'OR',
offline: "You're offline.",
},
messageSystem: {
killswitch: {
Expand Down
2 changes: 1 addition & 1 deletion suite-native/message-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
"@suite-common/suite-types": "workspace:*",
"@suite-common/wallet-core": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/connection-status": "workspace:*",
"@suite-native/intl": "workspace:*",
"@suite-native/link": "workspace:*",
"@trezor/styles": "workspace:*",
"@trezor/theme": "workspace:*",
"react": "18.2.0",
"react-native": "0.74.1",
"react-native-reanimated": "3.11.0",
"react-native-safe-area-context": "4.10.3",
"react-redux": "8.0.7"
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';

import { A } from '@mobily/ts-belt';

import { VStack } from '@suite-native/atoms';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import { selectActiveBannerMessages } from '@suite-common/message-system';
import { useOfflineBannerAwareSafeAreaInsets } from '@suite-native/connection-status';

import { MessageBanner } from './MessageBanner';

Expand All @@ -17,7 +17,7 @@ const messageBannerContainerStyle = prepareNativeStyle<{ topSafeAreaInset: numbe

export const MessageSystemBannerRenderer = () => {
const { applyStyle } = useNativeStyles();
const { top: topSafeAreaInset } = useSafeAreaInsets();
const { top: topSafeAreaInset } = useOfflineBannerAwareSafeAreaInsets();

const activeBannerMessages = useSelector(selectActiveBannerMessages);
const topInset = A.isNotEmpty(activeBannerMessages) ? topSafeAreaInset : 0;
Expand Down
1 change: 1 addition & 0 deletions suite-native/message-system/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"path": "../../suite-common/wallet-core"
},
{ "path": "../atoms" },
{ "path": "../connection-status" },
{ "path": "../intl" },
{ "path": "../link" },
{ "path": "../../packages/styles" },
Expand Down
1 change: 1 addition & 0 deletions suite-native/module-add-accounts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@suite-native/accounts": "workspace:*",
"@suite-native/alerts": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/connection-status": "workspace:*",
"@suite-native/discovery": "workspace:*",
"@suite-native/intl": "workspace:*",
"@suite-native/link": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useState } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { View } from 'react-native';

import { LinearGradient } from 'expo-linear-gradient';
Expand All @@ -24,6 +23,7 @@ import {
} from '@suite-native/atoms';
import { useTranslate, Translation, TxKeyPath } from '@suite-native/intl';
import { useOpenLink } from '@suite-native/link';
import { useOfflineBannerAwareSafeAreaInsets } from '@suite-native/connection-status';

import { useAddCoinAccount, accountTypeTranslationKeys } from '../hooks/useAddCoinAccount';

Expand Down Expand Up @@ -89,7 +89,7 @@ export const SelectAccountTypeScreen = ({
const { accountType: defaultType, networkSymbol, flowType } = route.params;
const { translate } = useTranslate();
const openLink = useOpenLink();
const insets = useSafeAreaInsets();
const insets = useOfflineBannerAwareSafeAreaInsets();
const { applyStyle, utils } = useNativeStyles();

const { getAvailableAccountTypesForNetworkSymbol, addCoinAccount } = useAddCoinAccount();
Expand Down
1 change: 1 addition & 0 deletions suite-native/module-add-accounts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
{ "path": "../accounts" },
{ "path": "../alerts" },
{ "path": "../atoms" },
{ "path": "../connection-status" },
{ "path": "../discovery" },
{ "path": "../intl" },
{ "path": "../link" },
Expand Down
1 change: 1 addition & 0 deletions suite-native/navigation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@suite-common/wallet-types": "workspace:*",
"@suite-native/analytics": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/connection-status": "workspace:*",
"@trezor/connect": "workspace:*",
"@trezor/styles": "workspace:*",
"@trezor/theme": "workspace:*",
Expand Down
5 changes: 3 additions & 2 deletions suite-native/navigation/src/components/Screen.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useEffect, useContext, ReactNode } from 'react';
import { Platform, ScrollViewProps, StatusBar, View } from 'react-native';
import { useSafeAreaInsets, EdgeInsets } from 'react-native-safe-area-context';
import { EdgeInsets } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';

import * as SystemUI from 'expo-system-ui';
import * as NavigationBar from 'expo-navigation-bar';
import { BottomTabBarHeightContext } from '@react-navigation/bottom-tabs';
import { useRoute } from '@react-navigation/native';

import { useOfflineBannerAwareSafeAreaInsets } from '@suite-native/connection-status';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import { Color, nativeSpacings } from '@trezor/theme';
import { selectIsAnyBannerMessageActive } from '@suite-common/message-system';
Expand Down Expand Up @@ -114,7 +115,7 @@ export const Screen = ({
} = useNativeStyles();

const hasPaddingBottom = !useContext(BottomTabBarHeightContext) && hasBottomInset;
const insets = useSafeAreaInsets();
const insets = useOfflineBannerAwareSafeAreaInsets();
const backgroundCSSColor = colors[backgroundColor];
const barStyle = isDarkColor(backgroundCSSColor) ? 'light-content' : 'dark-content';

Expand Down
1 change: 1 addition & 0 deletions suite-native/navigation/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
{ "path": "../analytics" },
{ "path": "../atoms" },
{ "path": "../connection-status" },
{ "path": "../../packages/connect" },
{ "path": "../../packages/styles" },
{ "path": "../../packages/theme" }
Expand Down
2 changes: 1 addition & 1 deletion suite-native/notifications/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@suite-common/wallet-core": "workspace:*",
"@suite-common/wallet-types": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/connection-status": "workspace:*",
"@suite-native/formatters": "workspace:*",
"@suite-native/navigation": "workspace:*",
"@suite-native/theme": "workspace:*",
Expand All @@ -27,7 +28,6 @@
"react-native": "0.74.1",
"react-native-gesture-handler": "2.16.2",
"react-native-reanimated": "3.11.0",
"react-native-safe-area-context": "4.10.3",
"react-redux": "8.0.7"
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';

import { Box, VStack } from '@suite-native/atoms';
import { selectOpenedTransactionNotifications } from '@suite-common/toast-notifications';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import { useOfflineBannerAwareSafeAreaInsets } from '@suite-native/connection-status';

import { TransactionNotification } from './TransactionNotification';

Expand All @@ -19,7 +19,7 @@ const notificationContainerStyle = prepareNativeStyle<{ topSafeAreaInset: number

export const NotificationRenderer = () => {
const { applyStyle } = useNativeStyles();
const { top: topSafeAreaInset } = useSafeAreaInsets();
const { top: topSafeAreaInset } = useOfflineBannerAwareSafeAreaInsets();
const transactionNotifications = useSelector(selectOpenedTransactionNotifications);

return (
Expand Down
1 change: 1 addition & 0 deletions suite-native/notifications/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"path": "../../suite-common/wallet-types"
},
{ "path": "../atoms" },
{ "path": "../connection-status" },
{ "path": "../formatters" },
{ "path": "../navigation" },
{ "path": "../theme" },
Expand Down
4 changes: 2 additions & 2 deletions suite-native/toasts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
"@mobily/ts-belt": "^3.13.1",
"@suite-common/icons": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/connection-status": "workspace:*",
"@trezor/styles": "workspace:*",
"@trezor/theme": "workspace:*",
"jotai": "1.9.1",
"react": "18.2.0",
"react-native-reanimated": "3.11.0",
"react-native-safe-area-context": "4.10.3"
"react-native-reanimated": "3.11.0"
}
}
5 changes: 2 additions & 3 deletions suite-native/toasts/src/components/ToastRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { useAtomValue } from 'jotai';

import { useOfflineBannerAwareSafeAreaInsets } from '@suite-native/connection-status';
import { Box, VStack } from '@suite-native/atoms';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

Expand All @@ -20,7 +19,7 @@ const toastsContainerStyle = prepareNativeStyle<{ topSafeAreaInset: number }>(

export const ToastRenderer = () => {
const { applyStyle } = useNativeStyles();
const { top: topSafeAreaInset } = useSafeAreaInsets();
const { top: topSafeAreaInset } = useOfflineBannerAwareSafeAreaInsets();
const toasts = useAtomValue(toastsAtom);

return (
Expand Down
1 change: 1 addition & 0 deletions suite-native/toasts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"references": [
{ "path": "../../suite-common/icons" },
{ "path": "../atoms" },
{ "path": "../connection-status" },
{ "path": "../../packages/styles" },
{ "path": "../../packages/theme" }
]
Expand Down
Loading

0 comments on commit 1c6c918

Please sign in to comment.