TP-60588 | Code push loading screen

This commit is contained in:
yashmantri
2024-09-09 14:27:20 +05:30
parent 558d716113
commit 1b2cb25e1c
4 changed files with 188 additions and 9 deletions

61
App.tsx
View File

@@ -10,7 +10,13 @@ import {
StatusBar,
type Permission,
} from 'react-native';
import { default as codePush, default as CodePush } from 'react-native-code-push';
import {
default as codePush,
default as CodePush,
DownloadProgress,
DownloadProgressCallback,
SyncStatusChangedCallback,
} from 'react-native-code-push';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import store, { persistor } from './src/store/store';
@@ -44,6 +50,7 @@ import { setJsErrorHandler } from './src/services/exception-handler.service';
import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service';
import { StorageKeys } from './src/types/storageKeys';
import { setCurrentScreenName } from 'react-native-clarity';
import CodePushLoadingModal, { CodePushLoadingModalRef } from './CodePushModal';
initSentry();
@@ -56,17 +63,28 @@ LogBox.ignoreAllLogs();
export let GlobalDocumentMap: Record<string, TDocumentObj | string> = {};
async function checkCodePushAndSync() {
async function checkCodePushAndSync(
onSyncStatusChange: SyncStatusChangedCallback,
onDownloadProgress: DownloadProgressCallback
) {
try {
await CodePush.sync({
installMode: codePush.InstallMode.IMMEDIATE,
});
await CodePush.sync(
{
installMode: codePush.InstallMode.IMMEDIATE,
},
onSyncStatusChange,
onDownloadProgress
);
} catch (error) {}
}
function handleAppStateChange(nextAppState: any) {
function handleAppStateChange(
nextAppState: any,
onSyncStatusChange: SyncStatusChangedCallback,
onDownloadProgress: DownloadProgressCallback
) {
if (nextAppState == 'active') {
checkCodePushAndSync();
checkCodePushAndSync(onSyncStatusChange, onDownloadProgress);
}
}
@@ -74,6 +92,8 @@ const PERMISSION_CHECK_POLL_INTERVAL = 5 * MILLISECONDS_IN_A_SECOND;
function App() {
const [permissions, setPermissions] = React.useState(true);
const modalRef = React.useRef<CodePushLoadingModalRef>(null);
const askForPermissions = async () => {
const permissionsToRequest = await getPermissionsToRequest();
if (Platform.OS === 'android') {
@@ -94,6 +114,28 @@ function App() {
}
};
const onSyncStatusChange = (syncStatus: codePush.SyncStatus) => {
switch (syncStatus) {
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
modalRef.current?.show();
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
break;
case codePush.SyncStatus.UP_TO_DATE:
modalRef.current?.hide();
break;
default:
modalRef.current?.hide();
break;
}
};
const onDownloadProgress = (downloadProgress: DownloadProgress) => {
if (downloadProgress) {
modalRef.current?.updateProgress(downloadProgress);
}
};
const getActiveRouteName = (state) => {
if (!state || typeof state.index !== 'number') {
return 'Unknown';
@@ -126,7 +168,7 @@ function App() {
fetchUpdatedRemoteConfig();
askForPermissions();
const appStateChange = AppState.addEventListener('change', async (change) => {
handleAppStateChange(change);
handleAppStateChange(change, onSyncStatusChange, onDownloadProgress);
hydrateGlobalImageMap();
});
(async () => {
@@ -136,7 +178,7 @@ function App() {
GlobalDocumentMap = parsedData;
}
})();
checkCodePushAndSync();
checkCodePushAndSync(onSyncStatusChange, onDownloadProgress);
setForegroundTimeStampAndClickstream();
return () => {
@@ -166,6 +208,7 @@ function App() {
<ErrorBoundary>{permissions ? <AuthRouter /> : <Permissions />}</ErrorBoundary>
</NavigationContainer>
<ToastContainer config={toastConfigs} position="top" topOffset={18} />
<CodePushLoadingModal ref={modalRef} />
</PersistGate>
</Provider>
);

92
CodePushModal.tsx Normal file
View File

@@ -0,0 +1,92 @@
import { COLORS } from '@rn-ui-lib/colors';
import ProgressBar from './ProgressBar';
import React, { forwardRef, useImperativeHandle, useState } from 'react';
import { View, StyleSheet } from 'react-native';
import { DownloadProgress } from 'react-native-code-push';
import ModalWrapperForAlfredV2 from '@common/ModalWrapperForAlfredV2';
import LottieView from 'lottie-react-native';
import Text from '@rn-ui-lib/components/Text';
import NaviLogoWithTextIcon from '@rn-ui-lib/icons/NaviLogoWithTextIcon';
export interface CodePushLoadingModalRef {
show: () => void;
hide: () => void;
updateProgress: (progress: DownloadProgress) => void;
}
const CodePushLoadingModal = forwardRef<CodePushLoadingModalRef>((_, ref) => {
const [visible, setVisible] = useState(false);
const [progress, setProgress] = useState<DownloadProgress>();
useImperativeHandle(ref, () => ({
show: () => setVisible(true),
hide: () => setVisible(false),
updateProgress: (downloadProgress: DownloadProgress) => setProgress(downloadProgress),
}));
const getInMb = (progress: number) => {
if (progress) return `${(progress / 1024 / 1024).toFixed(2)} MB`;
return '-';
};
return (
<ModalWrapperForAlfredV2 visible={visible} animationType="fade">
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<View style={{ alignItems: 'center', marginBottom: 24 }}>
<LottieView
style={{ width: 140, height: 140 }}
source={require('./loader.json')}
autoPlay
loop
/>
</View>
{progress ? (
<View>
<Text style={styles.header}>Updating to a newer version...</Text>
<ProgressBar progress={progress?.receivedBytes / progress?.totalBytes} />
<Text style={styles.progressText}>
{getInMb(progress?.receivedBytes)} / {getInMb(progress?.totalBytes)}
</Text>
</View>
) : null}
</View>
<View style={{ alignItems: 'center' }}>
<NaviLogoWithTextIcon />
</View>
</View>
</ModalWrapperForAlfredV2>
);
});
const styles = StyleSheet.create({
modalContainer: {
flex: 1,
padding: 20,
},
modalContent: {
flex: 1,
justifyContent: 'center',
},
header: {
fontSize: 14,
color: COLORS.TEXT.BLACK_24,
paddingTop: 24,
paddingBottom: 6,
},
progressText: {
color: COLORS.TEXT.BLACK_24,
fontSize: 14,
fontWeight: '700',
marginTop: 6,
},
progressBar: {
width: '100%',
height: 2,
marginTop: 10,
},
});
export default CodePushLoadingModal;

43
ProgressBar.tsx Normal file
View File

@@ -0,0 +1,43 @@
import { COLORS } from '@rn-ui-lib/colors';
import React, { useState, useEffect } from 'react';
import { View, Text, Animated, StyleSheet } from 'react-native';
const ProgressBar = ({ progress, height = 10, color = '#18bf5f'}) => {
const [animatedWidth] = useState(new Animated.Value(0));
console.log({progress})
useEffect(() => {
Animated.timing(animatedWidth, {
toValue: progress * 100,
duration: 500,
useNativeDriver: false,
}).start();
}, [progress]);
return (
<View style={[styles.container, { height }]}>
<Animated.View
style={[
styles.fill,
{ width: animatedWidth.interpolate({
inputRange: [0, 100],
outputRange: ['0%', '100%'],
}), backgroundColor: color },
]}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#e0e0e0',
borderRadius: 8,
overflow: 'hidden',
},
fill: {
height: '100%',
},
});
export default ProgressBar;

1
loader.json Normal file

File diff suppressed because one or more lines are too long