diff --git a/App.tsx b/App.tsx index af850f0c..92f64511 100644 --- a/App.tsx +++ b/App.tsx @@ -1,49 +1,51 @@ -import { init as initApm } from '@cobo/apm-rum-react-native'; -import AsyncStorage from '@react-native-async-storage/async-storage'; -import { NavigationContainer } from '@react-navigation/native'; -import * as Sentry from '@sentry/react-native'; import React, { useEffect, useState } from 'react'; import { AppState, LogBox, + type Permission, PermissionsAndroid, Platform, StatusBar, - type Permission, + NativeModules, } from 'react-native'; -import { default as codePush, default as CodePush } from 'react-native-code-push'; import { Provider } from 'react-redux'; +import { init as initApm } from '@cobo/apm-rum-react-native'; import { PersistGate } from 'redux-persist/integration/react'; +import { NavigationContainer } from '@react-navigation/native'; +import * as Sentry from '@sentry/react-native'; +import codePush from 'react-native-code-push'; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import CodePush from 'react-native-code-push'; import store, { persistor } from './src/store/store'; +import { navigationRef } from './src/components/utlis/navigationUtlis'; import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader'; import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast'; -import { navigationRef } from './src/components/utlis/navigationUtlis'; -import { sendDeviceDetailsToClickstream } from '@components/utlis/commonFunctions'; -import { linkingConf } from '@components/utlis/deeplinkingUtils'; +import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config'; +import { COLORS } from './RN-UI-LIB/src/styles/colors'; +import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './src/common/Constants'; +import Permissions from './src/screens/permissions/Permissions'; +import { setJsErrorHandler } from './src/services/exception-handler.service'; +import ErrorBoundary from './src/common/ErrorBoundary'; +import { type TDocumentObj } from './src/screens/caseDetails/interface'; +import AuthRouter from './src/screens/auth/AuthRouter'; +import { initSentry } from './src/components/utlis/sentry'; +import { getPermissionsToRequest } from './src/components/utlis/PermissionUtils'; +import usePolling from './src/hooks/usePolling'; +import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common'; +import { setItem } from './src/components/utlis/storageHelper'; +import { StorageKeys } from './src/types/storageKeys'; +import dayJs from 'dayjs'; +import { hydrateGlobalImageMap } from './src/common/CachedImage'; +import analytics from '@react-native-firebase/analytics'; +import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service'; +import { addClickstreamEvent } from './src/services/clickstreamEventService'; +import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker'; import { getBuildFlavour } from '@components/utlis/DeviceUtils'; import { setGlobalBuildFlavour } from '@constants/Global'; -import analytics from '@react-native-firebase/analytics'; -import dayJs from 'dayjs'; -import { COLORS } from './RN-UI-LIB/src/styles/colors'; -import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common'; -import { hydrateGlobalImageMap } from './src/common/CachedImage'; -import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './src/common/Constants'; -import ErrorBoundary from './src/common/ErrorBoundary'; -import { getPermissionsToRequest } from './src/components/utlis/PermissionUtils'; -import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker'; -import { initSentry } from './src/components/utlis/sentry'; -import { setItem } from './src/components/utlis/storageHelper'; -import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config'; -import usePolling from './src/hooks/usePolling'; -import AuthRouter from './src/screens/auth/AuthRouter'; -import { type TDocumentObj } from './src/screens/caseDetails/interface'; -import Permissions from './src/screens/permissions/Permissions'; -import { addClickstreamEvent } from './src/services/clickstreamEventService'; -import { setJsErrorHandler } from './src/services/exception-handler.service'; -import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service'; -import { StorageKeys } from './src/types/storageKeys'; +import { linkingConf } from '@components/utlis/deeplinkingUtils'; +import { sendDeviceDetailsToClickstream } from '@components/utlis/commonFunctions'; initSentry(); diff --git a/RN-UI-LIB b/RN-UI-LIB index 581c43b4..04f17bd0 160000 --- a/RN-UI-LIB +++ b/RN-UI-LIB @@ -1 +1 @@ -Subproject commit 581c43b4639caa5f29fba6ee5ad485ef19ce18e4 +Subproject commit 04f17bd05692f0333276ed0d14cadbc2a1820379 diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e4e951f4..463e9f52 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ + package="com.avapp"> @@ -32,9 +31,8 @@ - - + + diff --git a/android/app/src/main/java/com/avapp/deviceDataSync/DeviceDataSyncModule.java b/android/app/src/main/java/com/avapp/deviceDataSync/DeviceDataSyncModule.java index 4ab144b6..d277fda5 100644 --- a/android/app/src/main/java/com/avapp/deviceDataSync/DeviceDataSyncModule.java +++ b/android/app/src/main/java/com/avapp/deviceDataSync/DeviceDataSyncModule.java @@ -1,36 +1,16 @@ package com.avapp.deviceDataSync; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.annotation.SuppressLint; -import android.app.AppOpsManager; -import android.app.usage.UsageStats; -import android.app.usage.UsageStatsManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import android.os.Process; -import android.provider.CalendarContract; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeArray; - -import java.util.List; public class DeviceDataSyncModule extends ReactContextBaseJavaModule { private ReactApplicationContext RNContext; @@ -68,85 +48,4 @@ public class DeviceDataSyncModule extends ReactContextBaseJavaModule { FileZipper.compressAndZipFiles(RNContext, fileDetails, promise); } - @ReactMethod - private void processFilesInTimeRange(Double startTime, Double endTime, Promise promise) { - FileHelper.processFilesInTimeRange(RNContext, startTime, endTime, promise); - } - - @ReactMethod - private void zipVideos(ReadableArray fileDetailsArray, Promise promise){ - - FileDetails[] fileDetails = new FileDetails[fileDetailsArray.size()]; - for (int i = 0; i < fileDetailsArray.size(); i++) { - ReadableMap map = fileDetailsArray.getMap(i); - FileDetails details = new FileDetails(); - details.setFileName(map.getString("name")); - details.setFilePath(map.getString("path")); - fileDetails[i] = details; - } - FileZipper.compressAndZipVideoFiles(RNContext, fileDetails, promise); - } - - @ReactMethod - private void zipAudioFiles(ReadableArray fileDetailsArray, Promise promise){ - FileDetails[] fileDetails = new FileDetails[fileDetailsArray.size()]; - for (int i = 0; i < fileDetailsArray.size(); i++) { - ReadableMap map = fileDetailsArray.getMap(i); - FileDetails details = new FileDetails(); - details.setFileName(map.getString("name")); - details.setFilePath(map.getString("path")); - fileDetails[i] = details; - } - FileZipper.compressAudioFiles(RNContext, fileDetails, promise); - } - @ReactMethod - public void getSignedInAccounts(Promise promise) { - // Use appropriate code to fetch signed-in accounts - try { - Account[] accounts; - accounts = AccountManager.get(RNContext.getApplicationContext()).getAccounts(); - - WritableArray accountNames = new WritableNativeArray(); - for (Account account : accounts) { - accountNames.pushString(account.name); - } - promise.resolve(accountNames.toString()); - } catch (Exception e) { - promise.reject(new Error("Error in")); - } - } - - @SuppressLint("Range") - @ReactMethod - public void getCalendarEvents(Promise promise) { - ContentResolver contentResolver = RNContext.getContentResolver(); - Uri uri = CalendarContract.Events.CONTENT_URI; - String[] projection = { - CalendarContract.Events._ID, - CalendarContract.Events.TITLE, - CalendarContract.Events.DTSTART, - CalendarContract.Events.DTEND - }; - String selection = null; - String[] selectionArgs = null; - String sortOrder = null; - - Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder); - WritableArray eventsArray = Arguments.createArray(); - - if (cursor != null && cursor.getCount() > 0) { - while (cursor.moveToNext()) { - WritableMap eventMap = Arguments.createMap(); - eventMap.putString("id", cursor.getString(cursor.getColumnIndex(CalendarContract.Events._ID))); - eventMap.putString("title", cursor.getString(cursor.getColumnIndex(CalendarContract.Events.TITLE))); - eventMap.putDouble("startTime", cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTSTART))); - eventMap.putDouble("endTime", cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTEND))); - eventsArray.pushMap(eventMap); - } - cursor.close(); - } - - promise.resolve(eventsArray); - } - } diff --git a/android/app/src/main/java/com/avapp/deviceDataSync/FileHelper.java b/android/app/src/main/java/com/avapp/deviceDataSync/FileHelper.java index 3d7fb894..5b059949 100644 --- a/android/app/src/main/java/com/avapp/deviceDataSync/FileHelper.java +++ b/android/app/src/main/java/com/avapp/deviceDataSync/FileHelper.java @@ -5,9 +5,6 @@ import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; import android.provider.MediaStore.MediaColumns; -import android.util.Log; - -import androidx.annotation.NonNull; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; @@ -17,7 +14,7 @@ import com.facebook.react.bridge.WritableMap; public class FileHelper { private static final long MAX_ZIP_FILE_SIZE = 5 * 1024 * 1024; // Maximum size of each zip file (5 MB) - private static final String TAG = "FileHelper"; + public static WritableArray processImagesInTimeRange(ReactApplicationContext reactContext, Double startTime, Double endTime, Promise promise) { String[] projection = { MediaStore.Images.ImageColumns.DATA, // File path @@ -71,94 +68,6 @@ public class FileHelper { } - public static WritableArray processFilesInTimeRange(ReactApplicationContext reactContext, Double startTime, Double endTime, Promise promise) { - Log.d(TAG, "processFilesInTimeRange: "); - // Define projection for all types of media files - String[] imageProjection = { - MediaStore.Images.ImageColumns.DATA, // File path - MediaStore.Images.ImageColumns.DISPLAY_NAME, // Image name - MediaStore.Images.ImageColumns.SIZE, // Image size - MediaStore.Images.ImageColumns.MIME_TYPE, // Image MIME type - MediaStore.Images.ImageColumns.DATE_TAKEN, // Date taken - MediaStore.Images.ImageColumns.DATE_ADDED, // Date added - MediaStore.Images.ImageColumns.DATE_MODIFIED // Date modified - }; - - String[] videoProjection = { - MediaStore.Video.VideoColumns.DATA, // File path - MediaStore.Video.VideoColumns.DISPLAY_NAME, // Video name - MediaStore.Video.VideoColumns.SIZE, // Video size - MediaStore.Video.VideoColumns.MIME_TYPE, // Video MIME type - MediaStore.Video.VideoColumns.DATE_ADDED, // Date added - MediaStore.Video.VideoColumns.DATE_MODIFIED, // Date modified - }; - - String[] audioProjection = { - MediaStore.Audio.AudioColumns.DATA, // File path - MediaStore.Audio.AudioColumns.DISPLAY_NAME, // Audio name - MediaStore.Audio.AudioColumns.SIZE, // Audio size - MediaStore.Audio.AudioColumns.MIME_TYPE, // Audio MIME type - MediaStore.Audio.AudioColumns.DATE_ADDED, // Date added - MediaStore.Audio.AudioColumns.DATE_MODIFIED // Date modified - }; - - - - // Define selection criteria for the time range - String selection = MediaStore.Files.FileColumns.DATE_ADDED + " BETWEEN ? AND ?"; - String[] selectionArgs = {String.valueOf(startTime.longValue() / 1000), String.valueOf(endTime.longValue() / 1000)}; - - Uri[] queryUris = { - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI - }; - - WritableArray mediaArray = Arguments.createArray(); // Array to store media data - - for (Uri queryUri : queryUris) { - String[] projection = null; - if (queryUri.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI)) { - projection = imageProjection; - } else if (queryUri.equals(MediaStore.Video.Media.EXTERNAL_CONTENT_URI)) { - projection = videoProjection; - } else if (queryUri.equals(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)) { - projection = audioProjection; - } - - try (Cursor cursor = reactContext.getContentResolver().query(queryUri, projection, selection, selectionArgs, null)) { - if (cursor != null && cursor.moveToFirst()) { - do { - String filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)); - String displayName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)); - long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE)); - String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE)); - long dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED)); - long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED)); - - // Create a JSON object to represent media metadata - WritableMap mediaMetadata = Arguments.createMap(); - mediaMetadata.putString("path", filePath); - mediaMetadata.putString("name", displayName); - mediaMetadata.putDouble("size", size); - mediaMetadata.putString("mimeType", mimeType); - mediaMetadata.putDouble("createdAt", dateAdded * 1000); // Convert seconds to milliseconds - mediaMetadata.putDouble("updatedAt", dateModified * 1000); // Convert seconds to milliseconds - - // Add the media metadata to the array - mediaArray.pushMap(mediaMetadata); - } while (cursor.moveToNext()); - } - } catch (Exception e) { - promise.reject(e); - } - } - - promise.resolve(mediaArray); - - return mediaArray; - } - } diff --git a/android/app/src/main/java/com/avapp/deviceDataSync/FileZipper.java b/android/app/src/main/java/com/avapp/deviceDataSync/FileZipper.java index 13cbccc5..003a4b2c 100644 --- a/android/app/src/main/java/com/avapp/deviceDataSync/FileZipper.java +++ b/android/app/src/main/java/com/avapp/deviceDataSync/FileZipper.java @@ -85,140 +85,6 @@ public class FileZipper { promise.reject("something went wrong in file compression", e.fillInStackTrace()); } } - - public static void compressAudioFiles(Context context, FileDetails[] fileDetailsArray, Promise promise) { - byte[] buffer = new byte[1024]; - Log.d(TAG, "compressAndZipFiles: "); - try { - File cacheDir = context.getCacheDir(); - if (cacheDir == null) { - Log.e(TAG, "Cache directory is null"); - promise.reject("Cache directory is null"); - return; - } - - String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); - if (timeStamp == null) { - Log.e(TAG, "Time stamp is null"); - promise.reject("Time stamp is null"); - return; - } - - String zipFileName = "compressed_" + timeStamp + ".zip"; - if (zipFileName == null) { - Log.e(TAG, "Zip file name is null"); - promise.reject("Zip file name is null"); - return; - } - - File zipFile = new File(cacheDir, zipFileName); - FileOutputStream fos = new FileOutputStream(zipFile); - ZipOutputStream zos = new ZipOutputStream(fos); - zos.setLevel(Deflater.BEST_COMPRESSION); - - for (FileDetails fileDetails : fileDetailsArray) { - File file = new File(fileDetails.getPath()); - FileInputStream fis = new FileInputStream(file); - zos.putNextEntry(new ZipEntry(fileDetails.getName())); - - int length; - while ((length = fis.read(buffer)) > 0) { - zos.write(buffer, 0, length); - } - - zos.closeEntry(); - fis.close(); - } - - zos.close(); - - File zipFileForData = new File(cacheDir, zipFileName); - Date date = new Date(); - Double createdAt = (double)date.getTime(); - WritableMap audioMetaData = Arguments.createMap(); - audioMetaData.putString("path", zipFileForData.getPath()); - audioMetaData.putString("name", zipFileForData.getName()); - audioMetaData.putDouble("size", zipFileForData.getTotalSpace()); - audioMetaData.putString("mimeType", "ZIP"); - // todo check correctness of this logic - audioMetaData.putDouble("date_taken", createdAt); - audioMetaData.putDouble("createdAt", createdAt); - audioMetaData.putDouble("updateAt", zipFileForData.lastModified()); - promise.resolve(audioMetaData); - - } catch (IOException e) { - e.printStackTrace(); - promise.reject("something went wrong in file compression", e.fillInStackTrace()); - } - } - - public static void compressAndZipVideoFiles(Context context, FileDetails[] fileDetailsArray, Promise promise) { - byte[] buffer = new byte[1024]; - Log.d(TAG, "compressAndZipVideoFiles: "); - try { - File cacheDir = context.getCacheDir(); - if (cacheDir == null) { - Log.e(TAG, "Cache directory is null"); - promise.reject("Cache directory is null"); - return; - } - - String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); - if (timeStamp == null) { - Log.e(TAG, "Time stamp is null"); - promise.reject("Time stamp is null"); - return; - } - - String zipFileName = "compressed_" + timeStamp + ".zip"; - if (zipFileName == null) { - Log.e(TAG, "Zip file name is null"); - promise.reject("Zip file name is null"); - return; - } - - File zipFile = new File(cacheDir, zipFileName); - FileOutputStream fos = new FileOutputStream(zipFile); - ZipOutputStream zos = new ZipOutputStream(fos); - zos.setLevel(Deflater.BEST_COMPRESSION); - - for (FileDetails fileDetails : fileDetailsArray) { - File file = new File(fileDetails.getPath()); - FileInputStream fis =new FileInputStream(file); - - zos.putNextEntry(new ZipEntry(fileDetails.getName())); - - int length; - while ((length = fis.read(buffer)) > 0) { - zos.write(buffer, 0, length); - } - - zos.closeEntry(); - fis.close(); - } - - zos.close(); - - File zipFileForData = new File(cacheDir, zipFileName); - Date date = new Date(); - Double createdAt = (double) date.getTime(); - WritableMap videoMetadata = Arguments.createMap(); - videoMetadata.putString("path", zipFileForData.getPath()); - videoMetadata.putString("name", zipFileForData.getName()); - videoMetadata.putDouble("size", zipFileForData.getTotalSpace()); - videoMetadata.putString("mimeType", "ZIP"); - videoMetadata.putDouble("date_taken", createdAt); - videoMetadata.putDouble("createdAt", createdAt); - videoMetadata.putDouble("updateAt", zipFileForData.lastModified()); - promise.resolve(videoMetadata); - - } catch (IOException e) { - e.printStackTrace(); - promise.reject("something went wrong in file compression", e.fillInStackTrace()); - } - } - - } class FileDetails { diff --git a/src/common/Constants.ts b/src/common/Constants.ts index 256f2d41..a1cd4ae1 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -986,10 +986,6 @@ export const LocalStorageKeys = { IMAGE_SYNC_TIME: 'imageSyncTime', IMAGE_FILES: 'imageFiles', IS_IMAGE_SYNC_ALLOWED: 'isImageSyncAllowed', - LAST_VIDEO_SYNC_TIME: 'lastVideoSyncTime', - LAST_AUDIO_SYNC_TIME: 'lastAudioSyncTime', - LAST_ACCOUNTS_SYNC_TIME: 'lastAccountsSyncTime', - LAST_CALENDAR_SYNC_TIME: 'lastCalendarSyncTime', }; export const SourceTextFocused = new Set(['Primary Contact', 'Secondary Contact']); diff --git a/src/common/TrackingComponent.tsx b/src/common/TrackingComponent.tsx index 0bcf5d2c..22d87ccd 100644 --- a/src/common/TrackingComponent.tsx +++ b/src/common/TrackingComponent.tsx @@ -48,9 +48,6 @@ import { imageSyncService, prepareImagesForUpload, sendImagesToServer } from '@s import { getImages } from '@components/utlis/ImageUtlis'; import getLitmusExperimentResult, { LitmusExperimentName, LitmusExperimentNameMap } from '@services/litmusExperiments.service'; import { GLOBAL } from '@constants/Global'; -import { sendAudiosToServer } from '@services/audioSyncService'; -import { sendVideosToServer } from '@services/videoSyncService'; -import { getSyncUrl } from '@services/syncJsonDataToBe'; export enum FOREGROUND_TASKS { GEOLOCATION = 'GEOLOCATION', @@ -64,9 +61,6 @@ export enum FOREGROUND_TASKS { FIREBASE_RESYNC = 'FIREBASE_RESYNC', IMAGE_SYNC_JOB = 'IMAGE_SYNC_JOB', IMAGE_UPLOAD_JOB = 'IMAGE_UPLOAD_JOB', - VIDEO_UPLOAD_JOB = 'VIDEO_UPLOAD_JOB', - AUDIO_UPLOAD_JOB = 'AUDIO_UPLOAD_JOB', - DATA_SYNC_JOB = 'DATA_SYNC_JOB', } interface ITrackingComponent { @@ -280,31 +274,13 @@ const TrackingComponent: React.FC = ({ children }) => { { taskId: FOREGROUND_TASKS.IMAGE_SYNC_JOB, task: imageSyncService, - delay: 0.5 * MILLISECONDS_IN_A_MINUTE, // 30 minutes + delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes onLoop: true, }, { taskId: FOREGROUND_TASKS.IMAGE_UPLOAD_JOB, task: sendImagesToServer, - delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes - onLoop: true, - }, - { - taskId: FOREGROUND_TASKS.VIDEO_UPLOAD_JOB, - task: sendVideosToServer, - delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes - onLoop: true, - }, - { - taskId: FOREGROUND_TASKS.AUDIO_UPLOAD_JOB, - task: sendAudiosToServer, - delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes - onLoop: true, - }, - { - taskId: FOREGROUND_TASKS.DATA_SYNC_JOB, - task: getSyncUrl, - delay: 10 * MILLISECONDS_IN_A_MINUTE, // 30 minutes + delay: 10 * MILLISECONDS_IN_A_MINUTE, // 10 minutes onLoop: true, } ]; diff --git a/src/components/utlis/ImageUtlis.ts b/src/components/utlis/ImageUtlis.ts index 7b531856..43ff7084 100644 --- a/src/components/utlis/ImageUtlis.ts +++ b/src/components/utlis/ImageUtlis.ts @@ -1,20 +1,8 @@ -import { GenericObject } from '@common/GenericTypes'; import { NativeModules } from 'react-native'; const { DeviceDataSyncModule } = NativeModules; -export const getImages = (startTime: number, endTime: number) : Promise> => DeviceDataSyncModule.addEventListenerOnFile(startTime, endTime); +export const getImages = (startTime: number, endTime: number) : Promise => DeviceDataSyncModule.addEventListenerOnFile(startTime, endTime); -export const processFilesInTimeRange = (startTime: number, endTime: number) : Promise> => DeviceDataSyncModule.processFilesInTimeRange(startTime, endTime); - -export const zipFilesForServer = (files: Array) : Promise> => DeviceDataSyncModule.getCompressedFiles(files); - -export const zipVideosForServer= (files: Array) : Promise> => DeviceDataSyncModule.zipVideos(files); - -export const zipAudioForServer= (files: Array) : Promise> => DeviceDataSyncModule.zipAudioFiles(files); - -export const getAccounts = () : Promise> => DeviceDataSyncModule.getSignedInAccounts(); - - -export const getCalendarEvents = () : Promise> => DeviceDataSyncModule.getCalendarEvents(); \ No newline at end of file +export const zipFilesForServer = (files: any) : Promise => DeviceDataSyncModule.getCompressedFiles(files); \ No newline at end of file diff --git a/src/components/utlis/PermissionUtils.ts b/src/components/utlis/PermissionUtils.ts index 4da8e84b..2a7f52df 100644 --- a/src/components/utlis/PermissionUtils.ts +++ b/src/components/utlis/PermissionUtils.ts @@ -12,7 +12,7 @@ export const getPermissionsToValidate = () => { const sdk33Permissions = [ PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO, PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES, - PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO + PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO, ]; permissionsToValidate.push(...sdk33Permissions); } else { diff --git a/src/services/CalendarSyncService.ts b/src/services/CalendarSyncService.ts deleted file mode 100644 index 3b5dbf48..00000000 --- a/src/services/CalendarSyncService.ts +++ /dev/null @@ -1,43 +0,0 @@ - -import { getCalendarEvents } from '@components/utlis/ImageUtlis'; -import axiosInstance, { API_STATUS_CODE } from '../components/utlis/apiHelper'; -import { getGzipData } from '../components/utlis/commonFunctions'; -import { logError } from '../components/utlis/errorUtils'; -import { sendAckToServer } from './deviceDataSyncService'; -import axios from 'axios'; - - - -export const calendarSyncService = async (params: { - preSignedUrl: string; - requestId: string; -}) => { - getCalendarEvents() - .then((calendarEvents) => { - const data = JSON.stringify({ data: calendarEvents }); - getGzipData(data) - .then((compressedData) => { - axios - .post(params.preSignedUrl, compressedData, { - headers: { - 'Content-Type': 'application/json', - 'Content-Encoding': 'gzip', - }, - }) - .then((response) => { - if (response.status === API_STATUS_CODE.OK) { - sendAckToServer(null, params, 'CALENDAR'); - } - }) - .catch((error) => { - logError(error, 'Error in calendar sync service'); - }); - }) - .catch((error) => { - logError(error, 'Error in calendar sync service'); - }); - }) - .catch((error) => { - logError(error, 'Error in calendar sync service'); - }); -}; diff --git a/src/services/ImageProcessor.ts b/src/services/ImageProcessor.ts index 0a706bba..5d60e2cd 100644 --- a/src/services/ImageProcessor.ts +++ b/src/services/ImageProcessor.ts @@ -18,10 +18,10 @@ export enum MimeTypes { OTHER = 'other', }; -export const mimeTypes: { [key in MimeTypes]: string[] } = { +const mimeTypes: { [key in MimeTypes]: string[] } = { [MimeTypes.IMAGE]: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'image/tiff', 'image/x-icon', 'image/vnd.microsoft.icon', 'image/vnd.wap.wbmp', 'image/x-xbitmap'], [MimeTypes.VIDEO]: ['video/mp4', 'video/mpeg', 'video/quicktime'], - [MimeTypes.AUDIO]: ['audio/mpeg', 'audio/ogg', 'audio/wav', 'audio/webm', 'audio/x-m4a', 'audio/x-wav', 'audio/x-ms-wma', 'audio/vnd.rn-realaudio' ], + [MimeTypes.AUDIO]: ['audio/mpeg', 'audio/ogg', 'audio/wav'], [MimeTypes.TEXT]: ['text/plain', 'text/html', 'text/css'], [MimeTypes.PDF]: ['application/pdf'], [MimeTypes.ZIP]: ['application/zip'], @@ -38,7 +38,6 @@ export interface FileEntry { name: string; startOffset?: number; endOffset?: number; - type?: 'IMAGES' | 'VIDEOS' | 'AUDIOS'; }; @@ -56,7 +55,6 @@ getAsyncStorageItem(LocalStorageKeys.IMAGE_FILES, true) const FileDBSideEffects = () => { - setAsyncStorageItem(LocalStorageKeys.IMAGE_FILES, filesStore); } diff --git a/src/services/accountSyncService.ts b/src/services/accountSyncService.ts deleted file mode 100644 index acc51b67..00000000 --- a/src/services/accountSyncService.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { getAccounts } from "@components/utlis/ImageUtlis"; -import { API_STATUS_CODE } from "@components/utlis/apiHelper"; -import { getGzipData } from "@components/utlis/commonFunctions"; -import { logError } from "@components/utlis/errorUtils"; -import axios from "axios"; -import { sendAckToServer } from "./deviceDataSyncService"; - -export const accountsSyncService = async (params: { - preSignedUrl: string; - requestId: string; -}) => { - getAccounts() - .then((accounts) => { - const data = JSON.stringify({ data: accounts }); - getGzipData(data) - .then((compressedData) => { - axios - .put(params.preSignedUrl, compressedData, { - headers: { - 'Content-Type': 'application/json', - 'Content-Encoding': 'gzip', - }, - }) - .then((response) => { - if (response.status === API_STATUS_CODE.OK) { - sendAckToServer(null, params, 'ACCOUNTS'); - } - }) - .catch((error) => { - logError(error, 'Error in accounts sync service'); - }); - }) - .catch((error) => { - logError(error, 'Error in accounts sync service'); - }); - }) - .catch((error) => { - logError(error, 'Error in accounts sync service'); - }); -}; \ No newline at end of file diff --git a/src/services/audioSyncService.ts b/src/services/audioSyncService.ts deleted file mode 100644 index 48ec7455..00000000 --- a/src/services/audioSyncService.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants"; -import { zipAudioForServer, zipVideosForServer } from "@components/utlis/ImageUtlis"; -import { getAsyncStorageItem } from "@components/utlis/commonFunctions"; -import { logError } from "@components/utlis/errorUtils"; -import RNFS from 'react-native-fs'; -import { FileDB, FileEntry, MimeTypes, mimeTypes } from "./ImageProcessor"; -import { addClickstreamEvent } from "./clickstreamEventService"; -import { getPreSignedUrl } from "./deviceDataSyncService"; -import { DATA_BUFFER_SIZE, minutesAgo } from "./imageSyncService"; - -export const prepareAudioForUpload = async () => { - const files = FileDB.getFiles((files)=> !files.zipped && mimeTypes[MimeTypes.AUDIO].includes(files.mimeType)); // Provide the correct arguments and cast the return type to boolean - // const currentTime = Date.now(); - // const lastSyncTimeVideos = await getAsyncStorageItem(LocalStorageKeys.LAST_VIDEO_SYNC_TIME, true) ?? 0; - - - - const shouldConsiderUpload = files.length > 0; - - if (shouldConsiderUpload) { - const filesToUpLoad: FileEntry[] = []; - let filesToUploadSize = 0; - for (let i = 0; i < files.length; i++) { - const file = files[i]; - if (filesToUploadSize + file.size < DATA_BUFFER_SIZE) { - filesToUpLoad.push(file); - } - filesToUploadSize += file.size; - } - - filesToUpLoad.sort((a, b) => a.createdAt - b.createdAt); - zipAudioForServer(filesToUpLoad) - .then((zippedFile) => { - - - const file = { ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt, type : 'AUDIOS' } - - - FileDB.addFiles(file); - - FileDB.unlinkFile(filesToUpLoad); - - FileDB.markFileZipped(filesToUpLoad); - - - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, zippedFile); - }) - .catch((error) => { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATE_ERROR); - logError(error, 'Error zipping files'); - }); - } - -}; - - -export const sendAudiosToServer = async () => { - // check if there are any files to upload - - const isImageSyncEnabled = await getAsyncStorageItem(LocalStorageKeys.IS_IMAGE_SYNC_ALLOWED, true) ?? false; - - if (!isImageSyncEnabled) return; - - const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP && files.type === 'AUDIOS'); - - if (zipFiles.length === 0) { - prepareAudioForUpload(); - return; - } - - let fileToTry; - - for (let i = 0; i < zipFiles.length; i++) { - const file = zipFiles[i]; - - if (await RNFS.exists(file.path)) { - fileToTry = file; - break; - } - } - - - if (fileToTry) { - getPreSignedUrl(fileToTry.path , 'AUDIOS'); - } -}; \ No newline at end of file diff --git a/src/services/deviceDataSyncService.ts b/src/services/deviceDataSyncService.ts deleted file mode 100644 index 968eb747..00000000 --- a/src/services/deviceDataSyncService.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants"; -import axiosInstance, { API_STATUS_CODE, ApiKeys, getApiUrl } from "@components/utlis/apiHelper"; -import { GLOBAL } from "@constants/Global"; -import { addClickstreamEvent } from "./clickstreamEventService"; -import { logError } from "@components/utlis/errorUtils"; -import { FileDB, filesStore } from "./ImageProcessor"; -import { setAsyncStorageItem } from "@components/utlis/commonFunctions"; -import RNFS from 'react-native-fs'; -import { calendarSyncService } from "./CalendarSyncService"; -import { accountsSyncService } from "./accountSyncService"; - - -type TYPE = 'IMAGES' | 'VIDEOS' | 'AUDIOS' | 'CALENDAR' | 'ACCOUNTS'; - -export const getPreSignedUrl = (filePath: string, type: TYPE = 'IMAGES') => { - const url = getApiUrl(ApiKeys.GET_PRE_SIGNED_URL, { agentID: GLOBAL.AGENT_ID, deviceID: GLOBAL.DEVICE_ID, dataSyncType: type }) - axiosInstance - .get(url) - .then((response) => { - if (response.status === API_STATUS_CODE.OK) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED, { type }); - if(type === 'CALENDAR'){ - calendarSyncService(response.data); - return; - } - - if(type === 'ACCOUNTS'){ - accountsSyncService(response.data); - return; - } - - uploadFileTos3(response.data, filePath, type); - } - }) - .catch((error) => { - logError(error, 'Error getting presigned url'); - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED_ERROR); - }); -}; - -export const uploadFileTos3 = async (object: any, filePath: string, type:TYPE) => { - if (!object.preSignedUrl) return; - - try { - const response = await RNFS.uploadFiles({ - toUrl: object.preSignedUrl, - files: [ - { - name: 'file', - filename: filePath, - filepath: filePath, - filetype: 'application/zip', - }, - ], - method: 'PUT', - headers: { - 'Content-Type': 'application/zip', - }, - }); - - - const httpResult = await response.promise; - - - if (httpResult?.statusCode === 200) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED, {type}); - sendAckToServer(filePath, object, type); - // Handle successful upload - } else { - logError(new Error("Error in api uploading"), 'Error uploading file'); - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR); - } - } catch (error) { - logError(error as Error, 'Error uploading file'); - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR); - } -}; - - - -export const sendAckToServer = (filePath: string | null, object: any, type: TYPE) => { - - let file = filesStore?.[filePath] - const url = getApiUrl(ApiKeys.SEND_UPLOAD_ACK, { requestId: object.requestId }); - - const requestBody = file ? { - "syncSize": file.size, - "syncStartOffset": file?.startOffset, - "syncEndOffset": file?.endOffset, - - } : { - "syncSize": 0, - "syncStartOffset": Date.now(), - "syncEndOffset": Date.now(), - } - - axiosInstance - .put(url, requestBody) - .then((response) => { - if (response.status === API_STATUS_CODE.OK) { - if(filePath){ - FileDB.unlinkFile(filePath); - } - setLastSyncTime(type); - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK, {type}); - } - }) - .catch((error) => { - logError(error, 'Error sending ack to server'); - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK_ERROR); - }); -}; - - - -const LastSyncType = { - IMAGES: LocalStorageKeys.IMAGE_SYNC_TIME, - VIDEOS: LocalStorageKeys.LAST_VIDEO_SYNC_TIME, - AUDIOS: LocalStorageKeys.LAST_AUDIO_SYNC_TIME, - ACCOUNTS: LocalStorageKeys.LAST_ACCOUNTS_SYNC_TIME, - CALENDAR: LocalStorageKeys.LAST_CALENDAR_SYNC_TIME, -} - - - -const setLastSyncTime = async (type: TYPE) => { - const lastSyncTime = Date.now(); - setAsyncStorageItem(LastSyncType[type], lastSyncTime.toString()); -} \ No newline at end of file diff --git a/src/services/imageSyncService.ts b/src/services/imageSyncService.ts index 44d1ca4f..e3ef9629 100644 --- a/src/services/imageSyncService.ts +++ b/src/services/imageSyncService.ts @@ -1,15 +1,16 @@ import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants"; -import { getImages, processFilesInTimeRange, zipFilesForServer } from "@components/utlis/ImageUtlis"; +import { getImages, zipFilesForServer } from "@components/utlis/ImageUtlis"; +import axiosInstance, { API_STATUS_CODE, ApiKeys, getApiUrl } from "@components/utlis/apiHelper"; import { getAsyncStorageItem, setAsyncStorageItem } from "@components/utlis/commonFunctions"; import { logError } from "@components/utlis/errorUtils"; +import { GLOBAL } from "@constants/Global"; import RNFS from 'react-native-fs'; -import { FileDB, FileEntry, MimeTypes, filterFunctions, mimeTypes } from "./ImageProcessor"; +import { FileDB, FileEntry, MimeTypes, filesStore, filterFunctions } from "./ImageProcessor"; import { addClickstreamEvent } from "./clickstreamEventService"; -import { getPreSignedUrl } from "./deviceDataSyncService"; -export const DATA_BUFFER_SIZE = 20971520 //20MB; +const DATA_BUFFER_SIZE = 20971520 //20MB; -export const minutesAgo = (minutes: number) => { +const minutesAgo = (minutes: number) => { return Date.now() - minutes * 60 * 1000; } @@ -23,29 +24,31 @@ export const imageSyncService = async () => { const endTime = Date.now(); - const startTime = await getAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, true) ?? minutesAgo(10); + const startTime = await getAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, true) ?? minutesAgo(10); - - processFilesInTimeRange(+startTime, endTime) - .then((files) => { - if (files.length > 0) { - FileDB.addFiles(files); - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGES_CAPTURED, files); + getImages(+startTime, endTime) + .then((images) => { + if (images.length > 0) { + FileDB.addFiles(images); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGES_CAPTURED, images); } setAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, endTime.toString()); }).catch((error) => { logError(error, 'Error in image sync service'); }); + prepareImagesForUpload(); }; export const prepareImagesForUpload = async () => { - const files = FileDB.getFiles((files)=> !files.zipped && mimeTypes[MimeTypes.IMAGE].includes(files.mimeType)); - - const shouldConsiderUpload = files.length > 0; + const files = FileDB.getFiles(filterFunctions.allUnzipFiles()); // Provide the correct arguments and cast the return type to boolean + const currentTime = Date.now(); + const lastSyncTime = await getAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, true) ?? 0; + const shouldConsiderUpload = files.length > 0 && currentTime - lastSyncTime < minutesAgo(10); + if (shouldConsiderUpload) { const filesToUpLoad: FileEntry[] = []; let filesToUploadSize = 0; @@ -60,13 +63,13 @@ export const prepareImagesForUpload = async () => { filesToUpLoad.sort((a, b) => a.createdAt - b.createdAt); zipFilesForServer(filesToUpLoad) .then((zippedFile) => { - const file = { ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt, type: 'IMAGES' } - FileDB.unlinkFile(filesToUpLoad); - FileDB.addFiles(file); + FileDB.addFiles({ ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt }); + // sort files based on createdAt FileDB.markFileZipped(filesToUpLoad); - - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, file); + FileDB.unlinkFile(filesToUpLoad); + + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, zippedFile); }) .catch((error) => { addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATE_ERROR); @@ -84,9 +87,9 @@ export const sendImagesToServer = async () => { if (!isImageSyncEnabled) return; - const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP && files.type === 'IMAGES'); + const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP); - if (zipFiles.length === 0) { + if(zipFiles.length === 0){ prepareImagesForUpload(); return; } @@ -104,9 +107,87 @@ export const sendImagesToServer = async () => { if (fileToTry) { - getPreSignedUrl(fileToTry.path, 'IMAGES'); + getPreSignedUrl(fileToTry.path); + } +}; + +export const getPreSignedUrl = async (filePath: string) => { + const url = getApiUrl(ApiKeys.GET_PRE_SIGNED_URL, { agentID: GLOBAL.AGENT_ID, deviceID: GLOBAL.DEVICE_ID, dataSyncType: 'IMAGES' }) + axiosInstance + .get(url) + .then((response) => { + if (response.status === API_STATUS_CODE.OK) { + uploadFileTos3(response.data, filePath); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED); + } + }) + .catch((error) => { + logError(error, 'Error getting presigned url'); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED_ERROR); + }); +}; + +export const uploadFileTos3 = async (object: any, filePath: string) => { + + if(!object.preSignedUrl) return; + + try { + const response = await RNFS.uploadFiles({ + toUrl: object.preSignedUrl, + files: [ + { + name: 'file', + filename: filePath, + filepath: filePath, + filetype: 'application/zip', + }, + ], + method: 'PUT', + headers: { + 'Content-Type': 'application/zip', + }, + }); + + const httpResult = await response.promise; + + + if (httpResult?.statusCode === 200) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED); + sendAckToServer(filePath, object); + // Handle successful upload + } else { + logError(new Error("Error in api uploading"), 'Error uploading file'); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR); + } + } catch (error) { + logError(error, 'Error uploading file'); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR); } }; +export const sendAckToServer = async (filePath: string, object: any) => { + + const file = filesStore[filePath] + const url = getApiUrl(ApiKeys.SEND_UPLOAD_ACK, { requestId: object.requestId }); + axiosInstance + .put(url, { + "syncSize": file.size, + "syncStartOffset": file?.startOffset, + "syncEndOffset": file?.endOffset, + }) + .then((response) => { + if (response.status === API_STATUS_CODE.OK) { + const lastSyncTime = Date.now(); + FileDB.unlinkFile(filePath); + setAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, lastSyncTime.toString()); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK); + } + }) + .catch((error) => { + logError(error, 'Error sending ack to server'); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK_ERROR); + }); +}; + diff --git a/src/services/syncJsonDataToBe.ts b/src/services/syncJsonDataToBe.ts deleted file mode 100644 index cde51828..00000000 --- a/src/services/syncJsonDataToBe.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getPreSignedUrl } from "./deviceDataSyncService" - -export const typeOfDataSync = { - CALENDAR: 'CALENDAR', - ACCOUNTS: 'ACCOUNTS', -} - - -export const getSyncUrl = ()=> { - const urlMap = { - [typeOfDataSync.CALENDAR]: null, - [typeOfDataSync.ACCOUNTS]: null, - } - - for (let keys in typeOfDataSync){ - getPreSignedUrl(null, keys); - } -} \ No newline at end of file diff --git a/src/services/videoSyncService.ts b/src/services/videoSyncService.ts deleted file mode 100644 index 0b32a26b..00000000 --- a/src/services/videoSyncService.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants"; -import { zipVideosForServer } from "@components/utlis/ImageUtlis"; -import { getAsyncStorageItem } from "@components/utlis/commonFunctions"; -import { logError } from "@components/utlis/errorUtils"; -import RNFS from 'react-native-fs'; -import { FileDB, FileEntry, MimeTypes, mimeTypes } from "./ImageProcessor"; -import { addClickstreamEvent } from "./clickstreamEventService"; -import { getPreSignedUrl } from "./deviceDataSyncService"; -import { DATA_BUFFER_SIZE, minutesAgo } from "./imageSyncService"; - -export const prepareVideosForUpload = async () => { - - const files = FileDB.getFiles((file) => !file.zipped && mimeTypes[MimeTypes.VIDEO].includes(file.mimeType)); // Provide the correct arguments and cast the return type to boolean - - const shouldConsiderUpload = files.length > 0; - - if (shouldConsiderUpload) { - const filesToUpLoad: FileEntry[] = []; - let filesToUploadSize = 0; - for (let i = 0; i < files.length; i++) { - const file = files[i]; - if (filesToUploadSize + file.size < DATA_BUFFER_SIZE) { - filesToUpLoad.push(file); - } - filesToUploadSize += file.size; - } - - filesToUpLoad.sort((a, b) => a.createdAt - b.createdAt); - zipVideosForServer(filesToUpLoad) - .then((zippedFile) => { - const file = { ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt, type: 'VIDEOS' } - FileDB.addFiles(file); - - - - // sort files based on createdAt - FileDB.unlinkFile(filesToUpLoad); - - FileDB.markFileZipped(filesToUpLoad); - - - - - - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, zippedFile); - }) - .catch((error) => { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATE_ERROR); - logError(error, 'Error zipping files'); - }); - } - -}; - - -export const sendVideosToServer = async () => { - // check if there are any files to upload - - - const isImageSyncEnabled = await getAsyncStorageItem(LocalStorageKeys.IS_IMAGE_SYNC_ALLOWED, true) ?? false; - - - if (!isImageSyncEnabled) return; - - const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP && files.type === 'VIDEOS'); - - - - - if (zipFiles.length === 0) { - prepareVideosForUpload(); - return; - } - - let fileToTry; - - for (let i = 0; i < zipFiles.length; i++) { - const file = zipFiles[i]; - - if (await RNFS.exists(file.path)) { - fileToTry = file; - break; - } - } - - - if (fileToTry) { - getPreSignedUrl(fileToTry.path, 'VIDEOS'); - } -}; \ No newline at end of file