diff --git a/app/screens/connect-wallet/create-did-screen.tsx b/app/screens/connect-wallet/create-did-screen.tsx index c03aba55..1c225617 100644 --- a/app/screens/connect-wallet/create-did-screen.tsx +++ b/app/screens/connect-wallet/create-did-screen.tsx @@ -6,7 +6,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' import Toast from 'react-native-toast-message' import { HDKEY } from '@functionland/fula-sec' import { useSetRecoilState } from 'recoil' -import notifee from '@notifee/react-native' +import notifee, { AndroidColor } from '@notifee/react-native' import * as Keychain from '../../utils/keychain' import { Header, HeaderArrowBack } from '../../components/header' @@ -57,6 +57,8 @@ export const CreateDIDScreen: React.FC = ({ navigation, route }) => { pressAction: { id: 'default' }, + colorized: true, + color: AndroidColor.RED, ongoing: true, asForegroundService: true, channelId: 'sticky' diff --git a/app/screens/image-gallery-viewer/index.tsx b/app/screens/image-gallery-viewer/index.tsx index 925eeeaa..5b2eeb68 100644 --- a/app/screens/image-gallery-viewer/index.tsx +++ b/app/screens/image-gallery-viewer/index.tsx @@ -46,6 +46,7 @@ import { GalleryImage } from './gallery-image' import { palette } from '../../theme' import LinearGradient from 'react-native-linear-gradient' import { SyncService } from '../../services' +import { uploadAssets } from '../../services/sync-service' interface ImageGalleryViewerScreenProps { navigation: NavigationProp @@ -274,7 +275,29 @@ export const ImageGalleryViewerScreen: React.FC< ]) }, [asset]) - const uploadToBox = async () => { + async function uploadToBox() { + //Ignore asset greater than 200 MB + if (!asset?.fileSize || asset.fileSize > 200 * 1000 * 1000) { + Toast.show({ + type: 'info', + text1: 'Large asset!', + text2: 'Unable to upload assets greater than 200 MB for now!', + position: 'top', + bottomOffset: 40, + }) + return + } + setLoading(true) + try { + await uploadAssets([asset]) + } catch (err) { + console.error(err) + } finally { + setLoading(false) + } + } + + const uploadToBoxOld = async () => { if (asset?.syncStatus === SyncStatus.NOTSYNCED && !asset?.isDeleted) { //Ignore asset greater than 200 MB if (!asset?.fileSize || asset.fileSize > 200 * 1000 * 1000) { diff --git a/app/services/sync-service.ts b/app/services/sync-service.ts index 146b8b2a..cf5b6fd9 100644 --- a/app/services/sync-service.ts +++ b/app/services/sync-service.ts @@ -6,12 +6,15 @@ import BackgroundJob, { import { fula, chainApi } from '@functionland/react-native-fula' // import { TaggedEncryption } from '@functionland/fula-sec' import { AssetEntity } from '../realmdb/entities' -import { SyncStatus } from '../types' +import { Asset, SyncStatus } from '../types' import { Assets, Boxs, FolderSettings } from './localdb/index' import * as Constants from '../utils/constants' import { Helper, DeviceUtils, KeyChain } from '../utils' import { ApiPromise } from '@polkadot/api' import * as helper from '../utils/helper' +import Toast from 'react-native-toast-message' +import notifee, { AndroidColor } from '@notifee/react-native' +import { createForegroundTask } from './foreground' type TaskParams = { callback?: (success: boolean, assetId: string, error?: Error) => void @@ -61,6 +64,10 @@ const uploadAssetBackgroundTask = async (taskParameters?: TaskParams) => { } console.log('uploadAssetBackgroundTask fulaConfig') console.log(fulaConfig) + let resolveUploadCompleted = () => {} + const uploadCompleted = new Promise(resolve => { + resolveUploadCompleted = resolve + }) for (let index = 0; index < assets?.length; index++) { const asset = assets[index] console.log('uploadAssetBackgroundTask asset...', index) @@ -71,18 +78,40 @@ const uploadAssetBackgroundTask = async (taskParameters?: TaskParams) => { continue } - // Prepare task notification message - if (BackgroundJob.isRunning()) { - await BackgroundJob.updateNotification({ - taskTitle: `Uploading asset #${index + 1}/${assets?.length}`, - taskDesc: `Syncing your assets ...`, - progressBar: { + // // Prepare task notification message + // if (BackgroundJob.isRunning()) { + // await BackgroundJob.updateNotification({ + // taskTitle: `Uploading asset #${index + 1}/${assets?.length}`, + // taskDesc: `Syncing your assets ...`, + // progressBar: { + // max: assets?.length, + // value: index, + // indeterminate: assets?.length == 1, + // }, + // }) + // } + + // Show notification + await notifee.requestPermission() + await notifee.createChannel({ + id: 'sync', + name: "Sync Status" + }) + notifee.registerForegroundService(() => uploadCompleted) + await notifee.displayNotification({ + title: 'Sync in progress...', + subtitle: `Syncing ${assets?.length} photo${assets?.length > 1 ? 's': ''}`, + android: { + channelId: 'sync', + groupSummary: true, + groupId: 'syncGroup', + asForegroundService: true, + progress: { max: assets?.length, - value: index, - indeterminate: assets?.length == 1, - }, - }) - } + current: index + } + } + }) // Prepare the filepath and filename const _filePath = asset.uri?.split('file:')[1] @@ -93,6 +122,17 @@ const uploadAssetBackgroundTask = async (taskParameters?: TaskParams) => { ? slashSplit[slashSplit?.length - 1] : 'unknown' + index } + await notifee.displayNotification({ + title: 'Uploading Photo', + subtitle: `File ${filename} in progress...`, + android: { + channelId: 'sync', + groupId: 'syncGroup', + progress: { + indeterminate: true + } + } + }) // Upload file to the WNFS if (_filePath) { const cid = await fula.writeFile( @@ -118,6 +158,7 @@ const uploadAssetBackgroundTask = async (taskParameters?: TaskParams) => { } } } + resolveUploadCompleted() try { //TODO: Replicate request should be sent to blockchain let storedCids = await fula.listRecentCidsAsString() @@ -219,6 +260,124 @@ const downloadAssetsBackgroundTask = async (taskParameters?: TaskParams) => { await BackgroundJob.stop() } } + +let [successCount, failCount] = [0, 0] + +export async function uploadAssets(assets: Asset[]) { + if (!assets || assets.length == 0) { + return + } + const uploadAndNotifyResult = async asset => { + try { + await uploadAsset(asset) + successCount++ + await notifee.displayNotification({ + title: `${asset.filename}`, + subtitle: 'uploaded', + // body: ``, + android: { + channelId: 'syncStatus', + groupId: 'syncStatusGroup' + } + }) + } catch (error) { + console.error(error) + failCount++ + await notifee.displayNotification({ + title: `${asset.filename}`, + subtitle: 'failed', + body: `Error: ${JSON.stringify(error)}`, + android: { + channelId: 'syncStatus', + groupId: 'syncStatusGroup' + } + }) + } + await notifee.displayNotification({ + id: 'statusSummary', + subtitle: `upload ${successCount ? `${successCount} succeeded` : '' }` + + `${successCount? ', ': ''}${failCount ? `${failCount} failed` : '' }`, + android: { + channelId: 'syncStatus', + groupSummary: true, + groupId: 'syncStatusGroup' + } + }) + } + await notifee.requestPermission() + await notifee.createChannel({ + id: 'sync', + name: 'Sync', + vibration: false + }) + await notifee.createChannel({ + id: 'syncStatus', + name: 'Sync Status', + vibration: false + }) + notifee.registerForegroundService(async notification => { + const uploads: Promise[] = [] + for (let index = 0; index < assets.length; index++) { + let asset = assets[index] + const remainingCount = assets.length - index + await notifee.displayNotification({ + id: notification.id, + title: `Uploading ${remainingCount} photo${remainingCount > 1 ? 's': ''}`, + body: `${asset.filename} in progress`, + android: { + ...notification.android, + progress: { + max: assets.length, + current: index + } + } + }) + uploads.push(uploadAndNotifyResult(asset)) + await Promise.all(uploads) + } + }) + + await notifee.displayNotification({ + title: 'Upload started', + android: { + channelId: 'sync', + ongoing: true, + asForegroundService: true, + colorized: true, + color: AndroidColor.NAVY + } + }) +} + +async function uploadAsset(asset: Asset) { + Toast.show({ + type: 'info', + text1: asset.filename, + text2: 'uploadingg', + position: 'top', + bottomOffset: 40, + }) + await new Promise(resolve => setTimeout(resolve, 3000)) + throw new Error('pfff') + // const filePath = asset.uri?.split('file:')[1] + // if (!filePath) { + // throw Error('Invalid asset uri') + // } + // const cid = await fula.writeFile(`${Constants.FOTOS_WNFS_ROOT}/${asset.filename}`, filePath) + // console.log('----------') + // console.log(cid) + // console.log('----------') + // await Helper.storeFulaRootCID(cid) + // //Update asset record in database + // const newAsset = { + // id: asset.id, + // cid: cid, + // syncDate: new Date(), + // syncStatus: SyncStatus.SYNCED, + // } + // Assets.addOrUpdate([newAsset]) +} + // /** // * You need to make sure the box addresses are added and then call this method // * @param options