TP-34788 | Merge branch 'master' of github.com:navi-medici/address-verification-app into feat/TP-34788

This commit is contained in:
Aman Chaturvedi
2023-09-05 00:12:41 +05:30
20 changed files with 231 additions and 108 deletions

56
App.tsx
View File

@@ -1,7 +1,6 @@
import React from 'react';
import {
AppState,
KeyboardAvoidingView,
LogBox,
Permission,
PermissionsAndroid,
@@ -19,11 +18,11 @@ import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
import * as Sentry from '@sentry/react-native';
import { APM_APP_NAME, APM_BASE_URL, ENV, SENTRY_DSN } from './src/constants/config';
import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config';
import { COLORS } from './RN-UI-LIB/src/styles/colors';
import codePush from 'react-native-code-push';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { LocalStorageKeys, PermissionsToCheck } from './src/common/Constants';
import { LocalStorageKeys } from './src/common/Constants';
import Permissions from './src/screens/permissions/Permissions';
import { setJsErrorHandler } from './src/services/exception-handler.service';
import SuspenseLoader from './RN-UI-LIB/src/components/suspense_loader/SuspenseLoader';
@@ -32,6 +31,12 @@ import CodePush from 'react-native-code-push';
import { TDocumentObj } from './src/screens/caseDetails/interface';
import AuthRouter from './src/screens/auth/AuthRouter';
import { initSentry } from './src/components/utlis/sentry';
import {
getPermissionsToRequest,
getPermissionsToValidate,
} from './src/components/utlis/PermissionUtils';
import usePolling from './src/hooks/usePolling';
import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common';
initSentry();
@@ -58,29 +63,34 @@ function handleAppStateChange(nextAppState: any) {
}
}
const askForPermissions = async (setPermissions: React.Dispatch<React.SetStateAction<boolean>>) => {
if (Platform.OS === 'android') {
PermissionsAndroid.requestMultiple(PermissionsToCheck)
.then(async (result) => {
let isAllPermissionsGranted = true;
for (const permission in result) {
if (!(result?.[permission as Permission] === PermissionsAndroid.RESULTS.GRANTED)) {
isAllPermissionsGranted = false;
break;
}
}
setPermissions(isAllPermissionsGranted);
})
.catch((err) => {
setPermissions(false);
});
}
};
const PERMISSION_CHECK_POLL_INTERVAL = 5 * MILLISECONDS_IN_A_SECOND;
const App = () => {
const [permissions, setPermissions] = React.useState(true);
const [isGlobalDocumentMapLoaded, setIsGlobalDocumentMapLoaded] = React.useState(false);
const askForPermissions = async () => {
const permissionsToRequest = await getPermissionsToRequest();
if (Platform.OS === 'android') {
PermissionsAndroid.requestMultiple(permissionsToRequest)
.then(async (result) => {
let isAllPermissionsGranted = true;
for (const permission in result) {
if (result?.[permission as Permission] !== PermissionsAndroid.RESULTS.GRANTED) {
isAllPermissionsGranted = false;
break;
}
}
setPermissions(isAllPermissionsGranted);
})
.catch((err) => {
setPermissions(false);
});
}
};
usePolling(askForPermissions, PERMISSION_CHECK_POLL_INTERVAL);
initApm({
serviceName: APM_APP_NAME,
serverUrl: APM_BASE_URL,
@@ -90,9 +100,9 @@ const App = () => {
});
React.useEffect(() => {
const appStateChange = AppState.addEventListener('change', (change) => {
askForPermissions();
const appStateChange = AppState.addEventListener('change', async (change) => {
handleAppStateChange(change);
askForPermissions(setPermissions);
});
(async () => {
const data = await AsyncStorage.getItem(LocalStorageKeys.GLOBAL_DOCUMENT_MAP);

View File

@@ -131,8 +131,8 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
def VERSION_CODE = 79
def VERSION_NAME = "2.3.6"
def VERSION_CODE = 81
def VERSION_NAME = "2.3.8"
android {
ndkVersion rootProject.ext.ndkVersion

View File

@@ -24,6 +24,10 @@
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> -> 10+
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
<uses-permission android:name="android.permission.POST_NOTIFICATION" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> ->
<uses-permission android:name="android.permission.WAKE_LOCK" />
21 -> lollipop 28 ->

View File

@@ -5,8 +5,8 @@ buildscript {
kotlinVersion = '1.6.21'
buildToolsVersion = "31.0.0"
minSdkVersion = 21
compileSdkVersion = 31
targetSdkVersion = 31
compileSdkVersion = 33
targetSdkVersion = 33
googlePlayServicesAuthVersion = "19.2.0"
if (System.properties['os.arch'] == "aarch64") {

View File

@@ -1,6 +1,6 @@
{
"name": "AV_APP",
"version": "2.3.6",
"version": "2.3.8",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",
@@ -49,7 +49,7 @@
"appcenter-analytics": "^4.4.5",
"appcenter-crashes": "^4.4.5",
"axios": "1.2.1",
"dayjs": "^1.11.9",
"dayjs": "1.11.9",
"fuzzysort": "2.0.4",
"lottie-react-native": "5.1.4",
"react": "18.1.0",

View File

@@ -27,6 +27,7 @@ import { GenericFunctionArgs, GenericType } from '../common/GenericTypes';
import { GoogleSignin } from '@react-native-google-signin/google-signin';
import { resetConfig } from '../reducer/configSlice';
import { resetProfileData } from '../reducer/profileSlice';
import CosmosForegroundService from '../services/foregroundServices/foreground.service';
export interface GenerateOTPPayload {
phoneNumber: string;
@@ -214,6 +215,7 @@ export const handleImpersonatedUserLogin =
.then(async (response: AxiosResponse<IUser>) => {
//clear current user data
await clearAllAsyncStorage();
CosmosForegroundService.clearTasks();
await foregroundService.stopAll();
dispatch(resetCasesData());
await loggedOutCurrentUser();

View File

@@ -575,8 +575,6 @@ export const PermissionsToCheck: Permission[] = [
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.READ_SMS,
PermissionsAndroid.PERMISSIONS.READ_CALL_LOG,
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
@@ -586,6 +584,7 @@ export const PermissionsToCheck: Permission[] = [
PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE,
PermissionsAndroid.PERMISSIONS.SEND_SMS,
PermissionsAndroid.PERMISSIONS.RECEIVE_WAP_PUSH,
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATION,
];
export const BLOCKER_SCREEN_DATA = {

View File

@@ -1,8 +1,8 @@
import { type ReactNode, useEffect, useRef } from 'react';
import { type ReactNode, useEffect, useRef, useCallback } from 'react';
import { type NativeEventSubscription, AppState, type AppStateStatus } from 'react-native';
import dayJs from 'dayjs';
import { setItem, getItem } from '../components/utlis/storageHelper';
import UnstoppableService, {
import CosmosForegroundService, {
type IForegroundTask,
} from '../services/foregroundServices/foreground.service';
import useIsOnline from '../hooks/useIsOnline';
@@ -55,7 +55,6 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
const isOnline = useIsOnline();
const dispatch = useAppDispatch();
const appState = useRef(AppState.currentState);
const user = useAppSelector((state) => state.user);
const {
referenceId,
@@ -98,7 +97,7 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
timestamp: Date.now(),
isActiveOnApp: Boolean(isActiveOnApp),
};
dispatch(setDeviceGeolocationsBuffer(geolocation));
dispatch(sendLocationAndActivenessToServer([geolocation]));
} catch (e: any) {
logError(e, 'Error during background location sending.');
}
@@ -109,7 +108,7 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
return;
}
if (geolocations.length) {
dispatch(sendLocationAndActivenessToServer(geolocations));
dispatch(sendLocationAndActivenessToServer(geolocations, true));
}
}, [geolocations, isOnline]);
@@ -231,7 +230,7 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
await setItem(StorageKeys.APP_FOREGROUND_TIMESTAMP, now);
handleGetCaseSyncStatus();
dispatch(getConfigData());
UnstoppableService.start(tasks);
CosmosForegroundService.start(tasks);
}
if (nextAppState === AppStates.BACKGROUND) {
await setItem(StorageKeys.APP_BACKGROUND_TIMESTAMP, now);
@@ -258,10 +257,12 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
useEffect(() => {
let appStateSubscription: NativeEventSubscription;
if (!UnstoppableService.isRunning()) {
appStateSubscription = AppState.addEventListener('change', handleAppStateChange);
UnstoppableService.start(tasks);
}
CosmosForegroundService.isRunning().then((isFGSRunning) => {
if (!isFGSRunning) {
appStateSubscription = AppState.addEventListener('change', handleAppStateChange);
CosmosForegroundService.start(tasks);
}
});
return () => {
appStateSubscription?.remove();
};

View File

@@ -5,27 +5,6 @@ import { logError } from '../../utlis/errorUtils';
import { addClickstreamEvent } from '../../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../../common/Constants';
const FIVE_MIN = 5 * 60 * 1000;
export const requestLocationPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Geolocation Permission',
message: 'Can we access your location?',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
return granted === 'granted';
} catch (err) {
toast({
type: 'error',
text1: 'requestLocationPermission failed',
});
return false;
}
};
export class CaptureGeolocation {
private static capturedLocation: {
@@ -61,7 +40,9 @@ export class CaptureGeolocation {
resolve(undefined);
}
CaptureGeolocation.setCapturing(resourceId, true);
const isLocationOn = await requestLocationPermission();
const isLocationOn = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
);
if (!isLocationOn && appState === 'active') {
CaptureGeolocation.setCapturing(resourceId, false);
toast({

View File

@@ -0,0 +1,55 @@
import { Permission, PermissionsAndroid, Platform } from 'react-native';
import { PermissionsToCheck } from '../../common/Constants';
import { checkNotifications } from 'react-native-permissions';
import CosmosForegroundService from '../../services/foregroundServices/foreground.service';
let isNotificationPermissionEnabled = true;
export const getPermissionsToValidate = () => {
const permissionsToValidate = [...PermissionsToCheck];
if (Number(Platform.Version) >= 33) {
const sdk33Permissions = [
PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO,
PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES,
PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO,
];
permissionsToValidate.push(...sdk33Permissions);
} else {
const lessThanSdk33Permissions = [
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
];
permissionsToValidate.push(...lessThanSdk33Permissions);
}
return permissionsToValidate;
};
export const getPermissionsToRequest = async () => {
const permissionsToRequest: Permission[] = [];
const permissionsToValidate = getPermissionsToValidate();
for (let i = 0; i < permissionsToValidate.length; i++) {
const permission = permissionsToValidate[i];
if (permission === PermissionsAndroid.PERMISSIONS.POST_NOTIFICATION) {
const notificationPermission = await checkNotifications();
const notificationStatus = notificationPermission.status === 'granted';
if (!notificationStatus) {
permissionsToRequest.push(permission);
} else {
const isFGSRunning = await CosmosForegroundService.isRunning();
if (!isFGSRunning) {
CosmosForegroundService.start();
}
if (!isNotificationPermissionEnabled) {
CosmosForegroundService.update();
}
}
isNotificationPermissionEnabled = notificationStatus;
continue;
}
const granted = await PermissionsAndroid.check(permission);
if (!granted) {
permissionsToRequest.push(permission);
}
}
return permissionsToRequest;
};

View File

@@ -7,11 +7,16 @@ import Microphone from '../assets/icons/MicrophoneIcon';
import SmsIcon from '../assets/icons/SmsIcon';
import Calendar from '../assets/icons/Calendar';
import PhoneIcon from '../assets/icons/PhoneIcon';
import NotificationIconSmall from '../../RN-UI-LIB/src/Icons/NotificationIconSmall';
export const permissionsScreenMessage =
'NAVI Cosmos needs your permission to access certain features';
'NAVI Cosmos needs your permission to give you access to certain features';
export const androidPermissions = [
{
Icon: NotificationIconSmall,
header: 'Notifications',
},
{
Icon: CameraPermissionIcon,
header: 'Camera',

View File

@@ -1,7 +1,11 @@
import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
import { AppDispatch } from '../store/store';
import { clearDeviceGeolocationsBuffer } from '../reducer/foregroundServiceSlice';
import {
clearDeviceGeolocationsBuffer,
setDeviceGeolocationsBuffer,
} from '../reducer/foregroundServiceSlice';
import { logError } from '../components/utlis/errorUtils';
import { toast } from '../../RN-UI-LIB/src/components/toast';
export interface IGeolocationPayload {
latitude: number;
@@ -12,7 +16,7 @@ export interface IGeolocationPayload {
}
export const sendLocationAndActivenessToServer =
(geolocationBuffer: IGeolocationPayload[]) => (dispatch: AppDispatch) => {
(geolocationBuffer: IGeolocationPayload[], clearBuffer?: boolean) => (dispatch: AppDispatch) => {
axiosInstance
.post(getApiUrl(ApiKeys.SEND_LOCATION), geolocationBuffer, {
headers: {
@@ -20,9 +24,10 @@ export const sendLocationAndActivenessToServer =
},
})
.then(() => {
dispatch(clearDeviceGeolocationsBuffer());
clearBuffer && dispatch(clearDeviceGeolocationsBuffer());
})
.catch((error) => {
!clearBuffer && dispatch(setDeviceGeolocationsBuffer(geolocationBuffer[0]));
logError(error, 'Error while sending location to server');
});
};

View File

@@ -14,6 +14,7 @@ interface ICaseItemProps extends ViewProps {
isCompleted?: boolean;
isTodoItem?: boolean;
shouldBatchAvatar?: boolean;
allCasesView?: boolean;
}
const CaseItem: React.FC<ICaseItemProps> = ({
@@ -22,6 +23,7 @@ const CaseItem: React.FC<ICaseItemProps> = ({
isCompleted = false,
isTodoItem = false,
shouldBatchAvatar = false,
allCasesView = false,
...restProps
}) => {
const { ADD_VISIT_PLAN, ATTEMPTED_CASES } = CaseTypes;
@@ -85,6 +87,7 @@ const CaseItem: React.FC<ICaseItemProps> = ({
shouldBatchAvatar={shouldBatchAvatar}
isCompleted={isCompleted}
isTodoItem={isTodoItem}
allCasesView={allCasesView}
/>
</View>
);

View File

@@ -58,9 +58,10 @@ export const ESTIMATED_LIST_SIZE = { height: SCREEN_HEIGHT - 192, width: SCREEN_
interface ICasesList {
casesList: ICaseItem[];
isVisitPlan?: boolean;
allCasesView?: boolean;
}
const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan }) => {
const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan, allCasesView }) => {
const {
caseDetails,
visitPlansUpdating,
@@ -247,6 +248,7 @@ const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan }) => {
caseDetailObj={caseItemDetailObj}
shouldBatchAvatar={true}
testID={`case-${type === CaseTypes.TODO ? 'todo' : ''}-${row.index}`}
allCasesView={allCasesView}
/>
);
};

View File

@@ -58,7 +58,7 @@ const Filters: React.FC<IFilters> = ({
style={styles.textInput}
LeftComponent={<SearchIcon />}
onChangeText={handleSearchChange}
placeholder="Search by name, address, number"
placeholder={`Search in ${isVisitPlan ? 'visit plan' : 'my cases'}`}
defaultValue={searchQuery}
testID="test_search"
/>

View File

@@ -30,7 +30,7 @@ import OnboardingIcon from '../../../RN-UI-LIB/src/Icons/OnboardingIcon';
import RoundCheckIcon from '../../../RN-UI-LIB/src/Icons/RoundCheckIcon';
import { getDocumentList } from '../../components/utlis/commonFunctions';
import { toast } from '../../../RN-UI-LIB/src/components/toast';
import { ToastMessages } from './constants';
import { COMPLETED_STATUSES, ToastMessages } from './constants';
import { VisitPlanStatus } from '../../reducer/userSlice';
import { PaymentStatus } from '../caseDetails/interface';
@@ -39,6 +39,7 @@ interface IListItem {
isTodoItem?: boolean;
isCompleted?: boolean;
shouldBatchAvatar?: boolean;
allCasesView?: boolean;
}
const paymentStatusMapping: Record<
@@ -55,7 +56,7 @@ const paymentStatusMapping: Record<
};
const ListItem: React.FC<IListItem> = (props) => {
const { caseListItemDetailObj, isCompleted, isTodoItem, shouldBatchAvatar } = props;
const { caseListItemDetailObj, isCompleted, isTodoItem, shouldBatchAvatar, allCasesView } = props;
const {
id: caseId,
isIntermediateOrSelectedTodoCaseItem,
@@ -79,10 +80,6 @@ const ListItem: React.FC<IListItem> = (props) => {
const dispatch = useAppDispatch();
if (!isCompleted && caseStatus === CaseStatuses.CLOSED) {
return null;
}
useEffect(() => {
if (isNewlyAdded) {
setTimeout(() => dispatch(toggleNewlyAddedCase(caseId)), 1000);
@@ -169,6 +166,16 @@ const ListItem: React.FC<IListItem> = (props) => {
]
);
if (!isCompleted && caseStatus === CaseStatuses.CLOSED) {
return null;
}
const isCaseItemPinnedMainView = getCaseItemAvatarCaseDetailObj.isPinned && allCasesView;
const caseCompleted = COMPLETED_STATUSES.includes(caseStatus);
const showVisitPlanBtn =
!(caseCompleted || isCaseItemPinnedMainView) && !isTodoItem && !isCompleted;
return (
<Pressable onPress={handleCaseClick}>
<View
@@ -189,21 +196,22 @@ const ListItem: React.FC<IListItem> = (props) => {
caseDetailObj={getCaseItemAvatarCaseDetailObj}
shouldBatchAvatar={shouldBatchAvatar}
/>
{!isTodoItem && !isCompleted ? (
{showVisitPlanBtn ? (
<Pressable onPress={handleAvatarClick} style={styles.selectBtn}>
<RoundCheckIcon focused={isCaseSelected} />
</Pressable>
) : null}
{isCaseItemPinnedMainView && !caseCompleted && (
<View style={[GenericStyles.absolute, styles.visitPlanContainer]}>
<Text style={[GenericStyles.fontSize12, styles.visitPlanText]}>In visit plan</Text>
</View>
)}
<View style={[styles.caseItemInfo]}>
<View style={styles.tag}>
{isCollectionCaseType ? (
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
<Tag
variant={TagVariant.violet}
text={CaseTypeMap[CaseAllocationType.COLLECTION_CASE]}
/>
{paymentStatus ? (
<View style={[GenericStyles.ml8]}>
<View>
<Tag
variant={paymentStatusMapping[paymentStatus]?.variant || TagVariant.alert}
text={(paymentStatusMapping[paymentStatus]?.label || paymentStatus) as string}
@@ -211,7 +219,7 @@ const ListItem: React.FC<IListItem> = (props) => {
</View>
) : null}
{collectionTag ? (
<View style={[GenericStyles.ml8]}>
<View style={paymentStatus && GenericStyles.ml8}>
<Tag variant={TagVariant.gray} text={collectionTag} />
</View>
) : null}
@@ -310,6 +318,17 @@ const styles = StyleSheet.create({
fill: 1,
zIndex: 100,
},
visitPlanContainer: {
right: 0,
top: 0,
padding: 8,
backgroundColor: COLORS.BACKGROUND.BLUE,
borderBottomLeftRadius: 4,
borderTopRightRadius: 4,
},
visitPlanText: {
color: COLORS.TEXT.BLUE,
},
});
export default memo(ListItem);

View File

@@ -24,7 +24,9 @@ import { BOTTOM_TAB_ROUTES } from './constants';
import { getSelfieDocument } from '../../action/profileActions';
const AllCasesMain = () => {
const { pendingList, pinnedList, loading } = useAppSelector((state) => state.allCases);
const { pendingList, pinnedList, completedList, loading } = useAppSelector(
(state) => state.allCases
);
const userState = useAppSelector((state: RootState) => state.user);
const dispatch = useAppDispatch();
const isAgentTLOrAM = true;
@@ -33,7 +35,9 @@ const AllCasesMain = () => {
const bottomSheetScreens = [
{
name: BOTTOM_TAB_ROUTES.Cases,
component: () => <CasesList casesList={pendingList} />,
component: () => (
<CasesList casesList={[...pendingList, ...pinnedList, ...completedList]} allCasesView />
),
icon: CasesIcon,
},
];

View File

@@ -14,7 +14,7 @@ import TrackingComponent from '../../common/TrackingComponent';
import useFCM from '../../hooks/useFCM';
import { NetworkStatusService } from '../../services/network-monitoring.service';
import BlockerScreen from '../../common/BlockerScreen';
import UnstoppableService from '../../services/foregroundServices/foreground.service';
import CosmosForegroundService from '../../services/foregroundServices/foreground.service';
const AuthRouter = () => {
const dispatch = useAppDispatch();
@@ -49,9 +49,12 @@ const AuthRouter = () => {
useEffect(() => {
if (!isLoggedIn) {
if (UnstoppableService.isRunning()) {
UnstoppableService.stopAll();
}
CosmosForegroundService.isRunning().then((isRunning) => {
if (isRunning) {
CosmosForegroundService.clearTasks();
CosmosForegroundService.stopAll();
}
});
}
}, [isLoggedIn]);

View File

@@ -13,31 +13,42 @@ export interface IForegroundTask {
const FOREGROUND_SERVICE_ID = 1244;
const FOREGROUND_SERVICE_CONFIG = {
id: FOREGROUND_SERVICE_ID,
title: 'Tap to open Cosmos',
message: '',
icon: 'ic_launcher',
color: '#000000',
// @ts-ignore
setOnlyAlertOnce: false,
priority: 'low',
visibility: 'hidden',
importance: 'low',
sound: null,
vibrate: null,
};
class CosmosForegroundService {
private static fgsTasks: IForegroundTask[] = [];
private constructor() {}
static async start(tasks: IForegroundTask[]) {
static async start(tasks?: IForegroundTask[]) {
if (GLOBAL.IS_IMPERSONATED) {
return;
}
if (!tasks && !this.fgsTasks.length) {
return;
}
if (tasks?.length) {
this.fgsTasks = tasks;
}
try {
for (const currentTask of tasks) {
for (const currentTask of this.fgsTasks) {
if (!ForegroundService.is_running() || !ForegroundService.get_task(currentTask.taskId)) {
if (!ForegroundService.is_running()) {
await ForegroundService.start({
id: FOREGROUND_SERVICE_ID,
title: 'Tap to open Cosmos',
message: '',
icon: 'ic_launcher',
color: '#000000',
// @ts-ignore
setOnlyAlertOnce: false,
priority: 'low',
visibility: 'hidden',
importance: 'low',
sound: null,
vibrate: null,
});
//@ts-expect-error
await ForegroundService.start(FOREGROUND_SERVICE_CONFIG);
}
const { task, ...rest } = currentTask;
ForegroundService.add_task(task, { ...rest });
@@ -48,13 +59,32 @@ class CosmosForegroundService {
}
}
public static isRunning() {
return ForegroundService.is_running();
static async update() {
if (GLOBAL.IS_IMPERSONATED) {
return;
}
if (!this.fgsTasks.length) {
return;
}
//@ts-expect-error
ForegroundService.update(FOREGROUND_SERVICE_CONFIG);
}
public static async isRunning() {
try {
return await ForegroundService.is_running();
} catch (e: any) {
logError(e, 'Error checking Foreground service');
return false;
}
}
public static clearTasks() {
CosmosForegroundService.fgsTasks = [];
}
public static async stopAll() {
try {
await ForegroundService.remove_all_tasks();
await ForegroundService.stop();
await ForegroundService.stopAll();
} catch (e: any) {