diff --git a/src/libs/client.js b/src/libs/client.js index 49206c162..58e98ce80 100644 --- a/src/libs/client.js +++ b/src/libs/client.js @@ -30,6 +30,7 @@ export { } from '/libs/clientHelpers/initClient' export { call2FAInitClient } from '/libs/clientHelpers/twoFactorAuthentication' import { CozyPersistedStorageKeys, getData } from '/libs/localStore/storage' +import { getLinks } from '/pouchdb/getPouchLinks' const log = Minilog('LoginScreen') @@ -44,6 +45,7 @@ export const getClient = async () => { return false } const { uri, oauthOptions, token } = oauthData + const links = getLinks() const client = new CozyClient({ uri, oauth: { token }, @@ -51,7 +53,8 @@ export const getClient = async () => { appMetadata: { slug: 'flagship', version: packageJSON.version - } + }, + links }) listenTokenRefresh(client) client.getStackClient().setOAuthOptions(oauthOptions) diff --git a/src/libs/clientHelpers/createClient.ts b/src/libs/clientHelpers/createClient.ts index 0a3a30bb6..d64b895a2 100644 --- a/src/libs/clientHelpers/createClient.ts +++ b/src/libs/clientHelpers/createClient.ts @@ -13,6 +13,7 @@ import googleServicesJson from '/../android/app/src/prod/google-services.json' import packageJSON from '../../../package.json' import { startListening } from '/app/domain/authentication/services/AuthService' +import { getLinks } from '/pouchdb/getPouchLinks' /** * Create a CozyClient for the given Cozy instance and register it @@ -21,6 +22,8 @@ import { startListening } from '/app/domain/authentication/services/AuthService' * @returns {CozyClient} - The created and registered CozyClient */ export const createClient = async (instance: string): Promise => { + const links = getLinks() + const options = { scope: ['*'], oauth: { @@ -37,7 +40,8 @@ export const createClient = async (instance: string): Promise => { appMetadata: { slug: 'flagship', version: packageJSON.version - } + }, + links } const client = new CozyClient(options) diff --git a/src/pouchdb/getPouchLinks.js b/src/pouchdb/getPouchLinks.js new file mode 100644 index 000000000..422731297 --- /dev/null +++ b/src/pouchdb/getPouchLinks.js @@ -0,0 +1,30 @@ +import { platformReactNative } from '/pouchdb/platformReactNative' + +import { default as PouchLink } from 'cozy-pouch-link' + +export const offlineDoctypes = [ + 'io.cozy.accounts', + 'io.cozy.apps', + 'io.cozy.contacts', + 'io.cozy.files', + 'io.cozy.jobs', + 'io.cozy.konnectors', + 'io.cozy.permissions', + 'io.cozy.settings', + 'io.cozy.tags', + 'io.cozy.triggers' +] + +export const getLinks = () => { + const pouchLinkOptions = { + doctypes: offlineDoctypes, + initialSync: true, + platform: platformReactNative + } + + const pouchLink = new PouchLink({ + ...pouchLinkOptions + }) + + return [pouchLink] +} diff --git a/src/pouchdb/platformReactNative.appState.ts b/src/pouchdb/platformReactNative.appState.ts new file mode 100644 index 000000000..41d93b11c --- /dev/null +++ b/src/pouchdb/platformReactNative.appState.ts @@ -0,0 +1,34 @@ +import EventEmitter from 'events' + +import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native' + +import Minilog from 'cozy-minilog' + +const log = Minilog('🛋️ PlatormReactNative.appState') + +let appState = AppState.currentState +let appStateHandler: NativeEventSubscription | undefined = undefined + +export const listenAppState = (eventEmitter: EventEmitter): void => { + appStateHandler = AppState.addEventListener('change', nextAppState => { + log.debug('🛋️ AppState event', nextAppState) + if (isGoingToSleep(nextAppState)) { + eventEmitter.emit('resume') + } + if (isGoingToWakeUp(nextAppState)) { + eventEmitter.emit('pause') + } + + appState = nextAppState + }) +} + +export const stopListeningAppState = (): void => { + appStateHandler?.remove() +} + +const isGoingToSleep = (nextAppState: AppStateStatus): boolean => + Boolean(appState.match(/active/) && nextAppState === 'background') + +const isGoingToWakeUp = (nextAppState: AppStateStatus): boolean => + Boolean(appState.match(/background/) && nextAppState === 'active') diff --git a/src/pouchdb/platformReactNative.events.ts b/src/pouchdb/platformReactNative.events.ts new file mode 100644 index 000000000..8382f7853 --- /dev/null +++ b/src/pouchdb/platformReactNative.events.ts @@ -0,0 +1,28 @@ +import { EventEmitter } from 'events' + +import { listenAppState } from '/pouchdb/platformReactNative.appState' +import { listenNetInfo } from '/pouchdb/platformReactNative.netInfo' + +export const pouchDbEmitter = new EventEmitter() + +const listenPouchEvents = (): void => { + listenAppState(pouchDbEmitter) + listenNetInfo(pouchDbEmitter) +} + +listenPouchEvents() + +export const events = { + addEventListener: ( + eventName: string, + handler: (...args: unknown[]) => void + ): void => { + pouchDbEmitter.addListener(eventName, handler) + }, + removeEventListener: ( + eventName: string, + handler: (...args: unknown[]) => void + ): void => { + pouchDbEmitter.removeListener(eventName, handler) + } +} diff --git a/src/pouchdb/platformReactNative.isOnline.ts b/src/pouchdb/platformReactNative.isOnline.ts new file mode 100644 index 000000000..92ca9f0ef --- /dev/null +++ b/src/pouchdb/platformReactNative.isOnline.ts @@ -0,0 +1,5 @@ +import { NetService } from '/libs/services/NetService' + +export const isOnline = (): Promise => { + return NetService.isConnected() +} diff --git a/src/pouchdb/platformReactNative.netInfo.ts b/src/pouchdb/platformReactNative.netInfo.ts new file mode 100644 index 000000000..2d52a3b8a --- /dev/null +++ b/src/pouchdb/platformReactNative.netInfo.ts @@ -0,0 +1,24 @@ +import EventEmitter from 'events' + +import NetInfo, { NetInfoSubscription } from '@react-native-community/netinfo' + +import Minilog from 'cozy-minilog' + +const log = Minilog('🛋️ PlatormReactNative.netInfo') + +let netInfoHandler: NetInfoSubscription | undefined = undefined + +export const listenNetInfo = (eventEmitter: EventEmitter): void => { + netInfoHandler = NetInfo.addEventListener(state => { + log.debug('🛋️ NetInfo event', state.isConnected) + if (state.isConnected) { + eventEmitter.emit('online') + } else { + eventEmitter.emit('offline') + } + }) +} + +export const stopListeningNetInfo = (): void => { + netInfoHandler?.() +} diff --git a/src/pouchdb/platformReactNative.storage.ts b/src/pouchdb/platformReactNative.storage.ts new file mode 100644 index 000000000..f294bc4ca --- /dev/null +++ b/src/pouchdb/platformReactNative.storage.ts @@ -0,0 +1,14 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' + +export const storage = { + getItem: async (key: string): Promise => { + return AsyncStorage.getItem(key) + }, + setItem: async (key: string, value: string | undefined): Promise => { + if (value === undefined) return + return AsyncStorage.setItem(key, value) + }, + removeItem: async (key: string): Promise => { + return AsyncStorage.removeItem(key) + } +} diff --git a/src/pouchdb/platformReactNative.ts b/src/pouchdb/platformReactNative.ts new file mode 100644 index 000000000..9241e70d8 --- /dev/null +++ b/src/pouchdb/platformReactNative.ts @@ -0,0 +1,12 @@ +import { events } from '/pouchdb/platformReactNative.events' +import { isOnline } from '/pouchdb/platformReactNative.isOnline' +import { storage } from '/pouchdb/platformReactNative.storage' +import PouchDB from '/pouchdb/pouchdb' + +export const platformReactNative = { + storage, + events, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + pouchAdapter: PouchDB, + isOnline +}