diff --git a/App/Components/like-and-comment.tsx b/App/Components/like-and-comment.tsx index c34b6acef..0229cb3d0 100644 --- a/App/Components/like-and-comment.tsx +++ b/App/Components/like-and-comment.tsx @@ -11,12 +11,6 @@ import Icon from '@textile/react-native-icon' import { color, spacing, textStyle } from '../styles' -const CONTAINER: ViewStyle = { - paddingLeft: spacing.screenEdge, - paddingRight: spacing.screenEdge, - paddingTop: spacing.screenEdge -} - const ICONS: ViewStyle = { flexDirection: 'row' } @@ -56,7 +50,7 @@ const LikeAndComment = (props: Props) => { (!hasLiked && numberLikes > 0) || (hasLiked && numberLikes > 1) const displayCommentsCount = numberComments > 0 return ( - + {hasLiked && ( () => void pinchZoom?: boolean pinchHeight?: number pinchWidth?: number @@ -126,6 +131,11 @@ export default class Photo extends React.PureComponent { renderSelection() { // Just uses a touchable image, when touched will enable it's own modal in full screen + let progress: number | undefined + if (this.props.syncStatus) { + const { sizeComplete, sizeTotal } = this.props.syncStatus + progress = sizeComplete / sizeTotal + } return ( { this.props.photoWidth, this.props.photoWidth )} - + + + {this.props.syncStatus && !this.props.syncStatus.error && ( + + )} + {this.props.syncStatus && this.props.syncStatus.error && ( + + + + )} + ) diff --git a/App/Redux/RootReducer.ts b/App/Redux/RootReducer.ts index a378fc684..243fd755a 100644 --- a/App/Redux/RootReducer.ts +++ b/App/Redux/RootReducer.ts @@ -21,7 +21,6 @@ import { reducer as textileEventsReducer } from './TextileEventsRedux' import { groupReducer } from '../features/group' import { photosReducer } from '../features/photos' import { cafesReducer } from '../features/cafes' -import { fileSyncReducer } from '../features/file-sync' const migrations: MigrationManifest = { 0: persistedState => { @@ -360,14 +359,19 @@ const migrations: MigrationManifest = { const state = persistedState as any const { cafeSessions, ...rest } = state.account return { ...state, account: rest } + }, + 23: persistedState => { + const state = persistedState as any + const { fileSync, ...rest } = state + return rest } } const persistConfig: PersistConfig = { key: 'primary', storage: AsyncStorage, - version: 22, - whitelist: ['account', 'preferences', 'deviceLogs', 'fileSync'], + version: 23, + whitelist: ['account', 'preferences', 'deviceLogs'], migrate: createMigrate(migrations, { debug: false }), debug: false } @@ -386,8 +390,7 @@ const rootReducer = combineReducers({ textile: textileEventsReducer, group: groupReducer, photos: photosReducer, - cafes: cafesReducer, - fileSync: fileSyncReducer + cafes: cafesReducer }) export default persistReducer(persistConfig, rootReducer) diff --git a/App/Redux/Types.ts b/App/Redux/Types.ts index 984c68ad9..8699459b7 100644 --- a/App/Redux/Types.ts +++ b/App/Redux/Types.ts @@ -17,7 +17,6 @@ import { TextileEventsAction } from './TextileEventsRedux' import { GroupAction } from '../features/group' import { PhotosAction } from '../features/photos' import { CafesAction } from '../features/cafes' -import { FileSyncAction } from '../features/file-sync' export type RootState = StateType & PersistPartial export type RootAction = @@ -36,4 +35,3 @@ export type RootAction = | GroupAction | PhotosAction | CafesAction - | FileSyncAction diff --git a/App/Sagas/TextileEventsSagas.ts b/App/Sagas/TextileEventsSagas.ts index 335caf0cb..f297001c7 100644 --- a/App/Sagas/TextileEventsSagas.ts +++ b/App/Sagas/TextileEventsSagas.ts @@ -5,9 +5,9 @@ import { ActionType, getType } from 'typesafe-actions' import RNPushNotification from 'react-native-push-notification' import Textile, { EventSubscription, - FeedItemType, - ICafeSyncGroupStatus + FeedItemType } from '@textile/react-native-sdk' +import Long from 'long' import { toTypedNotification } from '../Services/Notifications' import { logNewEvent } from './DeviceLogs' @@ -28,7 +28,6 @@ import PhotoViewingActions, { import { contactsActions, ContactsAction } from '../features/contacts' import DeviceLogsActions, { DeviceLogsAction } from '../Redux/DeviceLogsRedux' import { groupActions, GroupAction } from '../features/group' -import { fileSyncActions, FileSyncAction } from '../features/file-sync' import AppConfig from '../Config/app-config' function displayNotification(message: string, title?: string) { @@ -49,7 +48,6 @@ function nodeEvents() { | DeviceLogsAction | NotificationsAction | TextileEventsAction - | FileSyncAction >(emitter => { const subscriptions: EventSubscription[] = [] subscriptions.push( @@ -161,17 +159,34 @@ function nodeEvents() { ) subscriptions.push( Textile.events.addSyncUpdateListener(status => { - emitter(fileSyncActions.syncUpdate(status)) + const sizeComplete = Long.fromValue(status.sizeComplete).toNumber() + const sizeTotal = Long.fromValue(status.sizeTotal).toNumber() + const groupSizeComplete = Long.fromValue( + status.groupsSizeComplete + ).toNumber() + const groupSizeTotal = Long.fromValue(status.groupsSizeTotal).toNumber() + const total = Math.max(sizeTotal, groupSizeTotal) + const { id, numComplete, numTotal } = status + emitter( + groupActions.fileSync.syncUpdate( + id, + numComplete, + numTotal, + groupSizeComplete, + total + ) + ) }) ) subscriptions.push( Textile.events.addSyncCompleteListener(status => { - emitter(fileSyncActions.syncComplete(status)) + emitter(groupActions.fileSync.syncComplete(status.id)) }) ) subscriptions.push( Textile.events.addSyncFailedListener(status => { - emitter(fileSyncActions.syncFailed(status)) + const { id, errorId, error } = status + emitter(groupActions.fileSync.syncFailed(id, errorId, error)) }) ) return () => { diff --git a/App/features/file-sync/actions.ts b/App/features/file-sync/actions.ts deleted file mode 100644 index 05d39f5a1..000000000 --- a/App/features/file-sync/actions.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createAction } from 'typesafe-actions' -import { ICafeSyncGroupStatus } from '@textile/react-native-sdk' - -export const syncUpdate = createAction('file-sync/SYNC_UPDATE', resolve => { - return (status: ICafeSyncGroupStatus) => resolve({ status }) -}) - -export const syncComplete = createAction('file-sync/SYNC_COMPLETE', resolve => { - return (status: ICafeSyncGroupStatus) => resolve({ status }) -}) - -export const syncFailed = createAction('file-sync/SYNC_FAILED', resolve => { - return (status: ICafeSyncGroupStatus) => resolve({ status }) -}) - -export const clearStatus = createAction('file-sync/CLEAR_STATUS', resolve => { - return (groupId: string) => resolve({ groupId }) -}) diff --git a/App/features/file-sync/index.ts b/App/features/file-sync/index.ts deleted file mode 100644 index 933a8b939..000000000 --- a/App/features/file-sync/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as fileSyncActions from './actions' -import fileSyncReducer, { FileSyncState, FileSyncAction } from './reducer' -// import * as fileSyncSelectors from './selectors' -// import fileSyncSaga from './sagas' - -// export { fileSyncActions, photosReducer, photosSelectors, PhotosState, PhotosAction, photosSaga } -export { fileSyncActions, fileSyncReducer, FileSyncState, FileSyncAction } diff --git a/App/features/file-sync/reducer.ts b/App/features/file-sync/reducer.ts deleted file mode 100644 index c2d16980b..000000000 --- a/App/features/file-sync/reducer.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { combineReducers } from 'redux' -import { ActionType, getType } from 'typesafe-actions' -import { ICafeSyncGroupStatus } from '@textile/react-native-sdk' - -import * as actions from './actions' - -export interface FileSyncState { - groups: { - [groupId: string]: ICafeSyncGroupStatus - } -} - -export type FileSyncAction = ActionType - -export default combineReducers({ - groups: (state = {}, action) => { - switch (action.type) { - case getType(actions.syncUpdate): - case getType(actions.syncFailed): { - const { status } = action.payload - return { ...state, [status.id]: status } - } - case getType(actions.syncComplete): { - const { [action.payload.status.id]: complete, ...remaining } = state - return remaining - } - case getType(actions.clearStatus): { - const { [action.payload.groupId]: cleared, ...remaining } = state - return remaining - } - default: - return state - } - } -}) diff --git a/App/features/group/actions.ts b/App/features/group/actions.ts index f97c956cb..e899c7e4e 100644 --- a/App/features/group/actions.ts +++ b/App/features/group/actions.ts @@ -2,6 +2,7 @@ import { feedActions as feed } from './feed' import { addMessageActions as addMessage } from './add-message' import { addPhotoActions as addPhoto } from './add-photo' import { renameGroupActions as renameGroup } from './rename-group' +import { fileSyncActions as fileSync } from './file-sync' import { ignoreActions as ignore } from './ignore' -export { feed, addMessage, addPhoto, renameGroup, ignore } +export { feed, addMessage, addPhoto, renameGroup, fileSync, ignore } diff --git a/App/features/group/file-sync/actions.ts b/App/features/group/file-sync/actions.ts new file mode 100644 index 000000000..7fe092ea4 --- /dev/null +++ b/App/features/group/file-sync/actions.ts @@ -0,0 +1,37 @@ +import { createAction } from 'typesafe-actions' + +export const syncUpdate = createAction( + 'group/file-sync/SYNC_UPDATE', + resolve => { + return ( + groupId: string, + numberComplete: number, + numberTotal: number, + sizeComplete: number, + sizeTotal: number + ) => + resolve({ groupId, numberComplete, numberTotal, sizeComplete, sizeTotal }) + } +) + +export const syncComplete = createAction( + 'group/file-sync/SYNC_COMPLETE', + resolve => { + return (groupId: string) => resolve({ groupId }) + } +) + +export const syncFailed = createAction( + 'group/file-sync/SYNC_FAILED', + resolve => { + return (groupId: string, errorId: string, reason: string) => + resolve({ groupId, errorId, reason }) + } +) + +export const clearStatus = createAction( + 'group/file-sync/CLEAR_STATUS', + resolve => { + return (groupId: string) => resolve({ groupId }) + } +) diff --git a/App/features/group/file-sync/index.ts b/App/features/group/file-sync/index.ts new file mode 100644 index 000000000..7ef39540f --- /dev/null +++ b/App/features/group/file-sync/index.ts @@ -0,0 +1,11 @@ +import * as fileSyncActions from './actions' +import fileSyncReducer, { FileSyncState, FileSyncAction } from './reducer' +import * as fileSyncSelectors from './selectors' + +export { + fileSyncActions, + fileSyncReducer, + fileSyncSelectors, + FileSyncState, + FileSyncAction +} diff --git a/App/features/group/file-sync/models.ts b/App/features/group/file-sync/models.ts new file mode 100644 index 000000000..6e0e4583c --- /dev/null +++ b/App/features/group/file-sync/models.ts @@ -0,0 +1,10 @@ +export interface GroupStatus { + numberComplete: number + numberTotal: number + sizeComplete: number + sizeTotal: number + error?: { + id: string + reason: string + } +} diff --git a/App/features/group/file-sync/reducer.ts b/App/features/group/file-sync/reducer.ts new file mode 100644 index 000000000..fe89912af --- /dev/null +++ b/App/features/group/file-sync/reducer.ts @@ -0,0 +1,54 @@ +import { combineReducers } from 'redux' +import { ActionType, getType } from 'typesafe-actions' +import { ICafeSyncGroupStatus } from '@textile/react-native-sdk' + +import * as actions from './actions' +import { GroupStatus } from './models' + +export interface FileSyncState { + groups: { + [groupId: string]: GroupStatus + } +} + +export type FileSyncAction = ActionType + +export default combineReducers({ + groups: (state = {}, action) => { + switch (action.type) { + case getType(actions.syncUpdate): { + const { + groupId, + numberComplete, + numberTotal, + sizeComplete, + sizeTotal + } = action.payload + return { + ...state, + [groupId]: { numberComplete, numberTotal, sizeComplete, sizeTotal } + } + } + case getType(actions.syncFailed): { + const { groupId, errorId, reason } = action.payload + const previous = state[groupId] + return { + ...state, + [groupId]: { ...previous, error: { id: errorId, reason } } + } + } + case getType(actions.syncComplete): { + const { groupId } = action.payload + const { [groupId]: complete, ...remaining } = state + return remaining + } + case getType(actions.clearStatus): { + const { groupId } = action.payload + const { [groupId]: cleared, ...remaining } = state + return remaining + } + default: + return state + } + } +}) diff --git a/App/features/group/file-sync/selectors.ts b/App/features/group/file-sync/selectors.ts new file mode 100644 index 000000000..9f3e598bf --- /dev/null +++ b/App/features/group/file-sync/selectors.ts @@ -0,0 +1,9 @@ +import { FileSyncState } from './reducer' + +export const makeStatusForId = (id: string) => (state: FileSyncState) => { + if (Object.keys(state.groups).indexOf(id) > -1) { + return state.groups[id] + } else { + return undefined + } +} diff --git a/App/features/group/models.ts b/App/features/group/models.ts index fc94cdc07..d4a8b8b5c 100644 --- a/App/features/group/models.ts +++ b/App/features/group/models.ts @@ -1,5 +1,10 @@ -import { FeedItemData } from '@textile/react-native-sdk' +import { FeedItemData, ICafeSyncGroupStatus } from '@textile/react-native-sdk' import { AddingMessageItem } from './add-message/models' import { AddingPhotoItem } from './add-photo/models' +import { GroupStatus } from './file-sync/models' -export type Item = FeedItemData | AddingPhotoItem | AddingMessageItem +export type SyncingFeedItemData = FeedItemData & { + syncStatus?: GroupStatus +} + +export type Item = SyncingFeedItemData | AddingPhotoItem | AddingMessageItem diff --git a/App/features/group/reducer.ts b/App/features/group/reducer.ts index b6e483410..b4d94a868 100644 --- a/App/features/group/reducer.ts +++ b/App/features/group/reducer.ts @@ -7,6 +7,7 @@ import { feedReducer, FeedState } from './feed' import { addMessageReducer, AddMessageState } from './add-message' import { addPhotoReducer, ProcessingImagesState } from './add-photo' import { renameGroupReducer, RenameGroupState } from './rename-group' +import { fileSyncReducer, FileSyncState } from './file-sync' import { ignoreReducer, IgnoreState } from './ignore' import * as actions from './actions' @@ -16,6 +17,7 @@ export interface GroupState { addMessage: AddMessageState addPhoto: ProcessingImagesState renameGroup: RenameGroupState + fileSync: FileSyncState ignore: IgnoreState } @@ -24,7 +26,7 @@ export type GroupAction = ActionType const persistConfig: PersistConfig = { key: 'group', storage: AsyncStorage, - whitelist: ['addPhoto'], + whitelist: ['addPhoto', 'fileSync'], debug: false } @@ -33,6 +35,7 @@ const reducer = combineReducers({ addMessage: addMessageReducer, addPhoto: addPhotoReducer, renameGroup: renameGroupReducer, + fileSync: fileSyncReducer, ignore: ignoreReducer }) diff --git a/App/features/group/selectors.ts b/App/features/group/selectors.ts index 328790273..53531203c 100644 --- a/App/features/group/selectors.ts +++ b/App/features/group/selectors.ts @@ -2,12 +2,23 @@ import { GroupState } from './reducer' import { Item } from './models' import { feedSelectors } from './feed' import { addPhotoSelectors } from './add-photo' +import { fileSyncSelectors } from './file-sync' export const groupItems = ( state: GroupState, groupId: string ): ReadonlyArray => { - const feed = feedSelectors.feedItems(state.feed, groupId) + const feed = feedSelectors + .feedItems(state.feed, groupId) + .map(feedItemData => { + const syncStatus = fileSyncSelectors.makeStatusForId(feedItemData.block)( + state.fileSync + ) + return { + ...feedItemData, + syncStatus + } + }) const processingImages = addPhotoSelectors.getProcessingImages( state.addPhoto, groupId @@ -18,4 +29,4 @@ export const groupItems = ( return withFeed } -export { feedSelectors, addPhotoSelectors } +export { feedSelectors, addPhotoSelectors, fileSyncSelectors } diff --git a/App/screens/group/group.tsx b/App/screens/group/group.tsx index 07e2821db..4e78ae00a 100644 --- a/App/screens/group/group.tsx +++ b/App/screens/group/group.tsx @@ -12,6 +12,7 @@ import { import { NavigationScreenProps, SafeAreaView } from 'react-navigation' import uuid from 'uuid/v4' import ActionSheet from 'react-native-actionsheet' +import Toast from 'react-native-easy-toast' import Textile, { IUser, Thread, FeedItemType } from '@textile/react-native-sdk' import moment from 'moment' @@ -125,6 +126,8 @@ class Group extends React.PureComponent { // Action sheet to handle block options like removing (ignoring) a message blockActionSheet: any + toast?: Toast + constructor(props: Props) { super(props) this.state = { @@ -207,6 +210,12 @@ class Group extends React.PureComponent { complete={this.completeRenameGroup} /> + { + this.toast = toast ? toast : undefined + }} + position="center" + /> ) } @@ -238,19 +247,10 @@ class Group extends React.PureComponent { renderRow = ({ item, index }: ListRenderItemInfo) => { switch (item.type) { case FeedItemType.Files: { - const { - user, - caption, - date, - data, - target, - files, - likes, - comments, - block - } = item.value + const { value, syncStatus, block } = item + const { user, caption, date, data, files, likes, comments } = value const isOwnPhoto = user.address === this.props.selfAddress - const canRemove = isOwnPhoto && !this.removing(item.block) + const canRemove = isOwnPhoto && !this.removing(block) const hasLiked = likes.findIndex( likeInfo => likeInfo.user.address === this.props.selfAddress @@ -296,6 +296,8 @@ class Group extends React.PureComponent { )} photoId={data} fileIndex={fileIndex} + syncStatus={syncStatus} + displayError={this.showToastWithMessage} photoWidth={screenWidth} hasLiked={hasLiked} numberLikes={likes.length} @@ -460,6 +462,14 @@ class Group extends React.PureComponent { return this.props.liking.indexOf(blockId) !== -1 } + showToastWithMessage = (message: string) => { + return () => { + if (this.toast) { + this.toast.show(message, 3000) + } + } + } + removing = (blockId: string) => { return this.props.removing.indexOf(blockId) !== -1 } diff --git a/ios/Podfile b/ios/Podfile index d046bdf9e..abef4513f 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -2,6 +2,7 @@ platform :ios, '10.0' target 'Textile' do pod 'React', :path => '../node_modules/react-native', :subspecs => [ + 'ART', 'Core', 'CxxBridge', 'DevSupport', diff --git a/ios/Textile.xcodeproj/project.pbxproj b/ios/Textile.xcodeproj/project.pbxproj index c5fcc1d26..001a7ee95 100644 --- a/ios/Textile.xcodeproj/project.pbxproj +++ b/ios/Textile.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 93C00609216C3873007786A5 /* libRNVersionNumber.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 93C00606216C385D007786A5 /* libRNVersionNumber.a */; }; 93C00620216D3334007786A5 /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 93C0061F216D325D007786A5 /* libRCTCameraRoll.a */; }; 93CCA014220135C700639B38 /* libRCTContacts.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 93CC9FE0220135A300639B38 /* libRCTContacts.a */; }; + 93CCECFC22E8FF9D00E0FC7B /* libART.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 93CCECC222E8FF8700E0FC7B /* libART.a */; }; 93D7697F2208C6FE00EEB573 /* MessageComposer.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D7697E2208C6FE00EEB573 /* MessageComposer.m */; }; 93F1805921FD459700883267 /* Biotif-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 93F1805621FD459700883267 /* Biotif-Bold.ttf */; }; 93F1805A21FD459700883267 /* Biotif-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 93F1805721FD459700883267 /* Biotif-Medium.ttf */; }; @@ -440,6 +441,20 @@ remoteGlobalIDString = 1441618E1BD0A79300FA4F59; remoteInfo = RCTContacts; }; + 93CCECC122E8FF8700E0FC7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 93CCECBC22E8FF8600E0FC7B /* ART.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0CF68AC11AF0540F00FF9E5C; + remoteInfo = ART; + }; + 93CCECC322E8FF8700E0FC7B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 93CCECBC22E8FF8600E0FC7B /* ART.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 323A12871E5F266B004975B8; + remoteInfo = "ART-tvOS"; + }; A27552BC21F28BEC00C603F5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 93C004FF216BB273007786A5 /* ReactNativeConfig.xcodeproj */; @@ -509,6 +524,7 @@ 93C0061A216D325C007786A5 /* RCTCameraRoll.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCameraRoll.xcodeproj; path = "../node_modules/react-native/Libraries/CameraRoll/RCTCameraRoll.xcodeproj"; sourceTree = ""; }; 93C00621216D385B007786A5 /* Textile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Textile.entitlements; path = Textile/Textile.entitlements; sourceTree = ""; }; 93CC9FD5220135A300639B38 /* RCTContacts.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTContacts.xcodeproj; path = "../node_modules/react-native-contacts/ios/RCTContacts.xcodeproj"; sourceTree = ""; }; + 93CCECBC22E8FF8600E0FC7B /* ART.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ART.xcodeproj; path = "../node_modules/react-native/Libraries/ART/ART.xcodeproj"; sourceTree = ""; }; 93D7697D2208C6FE00EEB573 /* MessageComposer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageComposer.h; sourceTree = ""; }; 93D7697E2208C6FE00EEB573 /* MessageComposer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageComposer.m; sourceTree = ""; }; 93F1805621FD459700883267 /* Biotif-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Biotif-Bold.ttf"; path = "../../App/Fonts/Biotif-Bold.ttf"; sourceTree = ""; }; @@ -536,6 +552,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 93CCECFC22E8FF9D00E0FC7B /* libART.a in Frameworks */, 932DF5DA2294C58E002683AB /* JavaScriptCore.framework in Frameworks */, 934C823A228B644D00EC996D /* libRNCameraRoll.a in Frameworks */, 93247E602278F1C1001C6381 /* libRNGestureHandler.a in Frameworks */, @@ -712,6 +729,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( + 93CCECBC22E8FF8600E0FC7B /* ART.xcodeproj */, 934C81F4228B640800EC996D /* RNCameraRoll.xcodeproj */, 93247E572278F1B0001C6381 /* RNGestureHandler.xcodeproj */, 93CC9FD5220135A300639B38 /* RCTContacts.xcodeproj */, @@ -900,6 +918,15 @@ name = Products; sourceTree = ""; }; + 93CCECBD22E8FF8600E0FC7B /* Products */ = { + isa = PBXGroup; + children = ( + 93CCECC222E8FF8700E0FC7B /* libART.a */, + 93CCECC422E8FF8700E0FC7B /* libART-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; 93D769782208C69D00EEB573 /* NativeModules */ = { isa = PBXGroup; children = ( @@ -1029,6 +1056,10 @@ productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; projectReferences = ( + { + ProductGroup = 93CCECBD22E8FF8600E0FC7B /* Products */; + ProjectRef = 93CCECBC22E8FF8600E0FC7B /* ART.xcodeproj */; + }, { ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; @@ -1502,6 +1533,20 @@ remoteRef = 93CC9FDF220135A300639B38 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 93CCECC222E8FF8700E0FC7B /* libART.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libART.a; + remoteRef = 93CCECC122E8FF8700E0FC7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 93CCECC422E8FF8700E0FC7B /* libART-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libART-tvOS.a"; + remoteRef = 93CCECC322E8FF8700E0FC7B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; A27552BD21F28BEC00C603F5 /* libReactNativeConfig-tvOS.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; diff --git a/package.json b/package.json index 53c241d07..2ca966341 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "react-native-image-pan-zoom": "^2.1.11", "react-native-image-picker": "^0.28.1", "react-native-modal": "^6.5.0", + "react-native-progress": "^3.6.0", "react-native-push-notification": "^3.1.1", "react-native-qrcode": "^0.2.7", "react-native-reanimated": "1.0.1", diff --git a/yarn.lock b/yarn.lock index 9eae4c659..a98d6c489 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5504,6 +5504,13 @@ react-native-platform-touchable@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/react-native-platform-touchable/-/react-native-platform-touchable-1.1.1.tgz#fde4acc65eea585d28b164d0c3716a42129a68e4" +react-native-progress@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/react-native-progress/-/react-native-progress-3.6.0.tgz#feaf37491f91bb421207fd761e20cb7258a2a3a6" + integrity sha512-zzTe595xaaskyfR5OzaGrU4O0R+YkgdEw+EspgGD7wh8Hu0fs6ue3xLW+HEbTjOCn62pCRivwi3NxbpWNBCC7Q== + dependencies: + prop-types "^15.7.2" + react-native-push-notification@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/react-native-push-notification/-/react-native-push-notification-3.1.1.tgz#99ce426e78e95788c298f73750cc4e68db04d7ab"