aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ios/Frontend.xcodeproj/project.pbxproj250
-rw-r--r--ios/Podfile2
-rw-r--r--ios/Podfile.lock155
-rw-r--r--package.json3
-rw-r--r--src/assets/images/no_chats.pngbin0 -> 28760 bytes
-rw-r--r--src/assets/images/no_chats@2x.pngbin0 -> 12709 bytes
-rw-r--r--src/assets/images/no_chats@3x.pngbin0 -> 46139 bytes
-rw-r--r--src/components/comments/AddComment.tsx98
-rw-r--r--src/components/comments/CommentTile.tsx141
-rw-r--r--src/components/comments/CommentsContainer.tsx116
-rw-r--r--src/components/common/Avatar.tsx18
-rw-r--r--src/components/common/AvatarTitle.tsx14
-rw-r--r--src/components/common/EmptyContentView.tsx132
-rw-r--r--src/components/common/TaggTypeahead.tsx75
-rw-r--r--src/components/common/TaggUserRowCell.tsx52
-rw-r--r--src/components/common/index.ts3
-rw-r--r--src/components/messages/ChannelPreview.tsx9
-rw-r--r--src/components/messages/ChatHeader.tsx11
-rw-r--r--src/components/messages/ChatInput.tsx12
-rw-r--r--src/components/messages/MessageAvatar.tsx15
-rw-r--r--src/components/moments/MomentPostContent.tsx23
-rw-r--r--src/components/moments/MomentPostHeader.tsx4
-rw-r--r--src/components/notifications/Notification.tsx10
-rw-r--r--src/components/profile/ProfileHeader.tsx22
-rw-r--r--src/components/profile/ProfilePreview.tsx13
-rw-r--r--src/components/profile/TaggAvatar.tsx (renamed from src/components/profile/Avatar.tsx)21
-rw-r--r--src/components/profile/index.ts1
-rw-r--r--src/components/search/ExploreSectionUser.tsx16
-rw-r--r--src/components/search/SearchResultCell.tsx8
-rw-r--r--src/components/taggs/TwitterTaggPost.tsx21
-rw-r--r--src/constants/strings.ts2
-rw-r--r--src/screens/badge/BadgeScreenHeader.tsx4
-rw-r--r--src/screens/chat/ChatListScreen.tsx4
-rw-r--r--src/screens/chat/ChatResultsCell.tsx10
-rw-r--r--src/screens/chat/ChatScreen.tsx31
-rw-r--r--src/screens/main/NotificationsScreen.tsx4
-rw-r--r--src/screens/main/notification/EmptyNotificationView.tsx48
-rw-r--r--src/screens/onboarding/Login.tsx2
-rw-r--r--src/screens/onboarding/OnboardingStepThree.tsx5
-rw-r--r--src/screens/profile/CaptionScreen.tsx17
-rw-r--r--src/screens/profile/MomentCommentsScreen.tsx124
-rw-r--r--src/screens/profile/SocialMediaTaggs.tsx2
-rw-r--r--src/types/types.ts5
-rw-r--r--src/utils/comments.tsx87
-rw-r--r--src/utils/users.ts29
-rw-r--r--yarn.lock32
46 files changed, 1001 insertions, 650 deletions
diff --git a/ios/Frontend.xcodeproj/project.pbxproj b/ios/Frontend.xcodeproj/project.pbxproj
index 4cd4db33..aa86fb3d 100644
--- a/ios/Frontend.xcodeproj/project.pbxproj
+++ b/ios/Frontend.xcodeproj/project.pbxproj
@@ -12,16 +12,16 @@
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 1E7AD3FE86DF4BD0A9C17980 /* libPods-Frontend-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F8E4573A72CA8220DAA9AF5 /* libPods-Frontend-tvOSTests.a */; };
- 28153F30DD8A96545B6DDE3D /* libPods-Frontend-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CAFA98ACCF23BEB39AD0A53 /* libPods-Frontend-tvOS.a */; };
+ 162320D6BACFC1F441EC22C1 /* libPods-Frontend.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 032770E196D0B343FBF58097 /* libPods-Frontend.a */; };
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2DCD954D1E0B4F2C00145EB5 /* FrontendTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* FrontendTests.m */; };
- 493A42D1B1923CF79BDBA497 /* libPods-Frontend-FrontendTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F9583A4B15B8BC744CC480BD /* libPods-Frontend-FrontendTests.a */; };
+ 8CFABFFB75409DE440B1F946 /* libPods-Frontend-FrontendTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C8C01B1DA113E97C596E47C /* libPods-Frontend-FrontendTests.a */; };
+ B6D41FC4D095A2EF7C3277A9 /* libPods-Frontend-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F8C4537388D0708785A4770E /* libPods-Frontend-tvOS.a */; };
B7B3F698256E07C400EF4575 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B7B3F697256E07C400EF4575 /* GoogleService-Info.plist */; };
B7B3F699256E07C400EF4575 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B7B3F697256E07C400EF4575 /* GoogleService-Info.plist */; };
- FE86B674D4BDCF5024DDFC4A /* libPods-Frontend.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A25FA993A8B7865AC123945B /* libPods-Frontend.a */; };
+ E6C87B035E8221C50D635E8F /* libPods-Frontend-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AC3226BEAF24D06C41E5569 /* libPods-Frontend-tvOSTests.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -46,6 +46,7 @@
00E356EE1AD99517003FC87E /* FrontendTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FrontendTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* FrontendTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FrontendTests.m; sourceTree = "<group>"; };
+ 032770E196D0B343FBF58097 /* libPods-Frontend.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend.a"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* Frontend.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Frontend.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Frontend/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Frontend/AppDelegate.m; sourceTree = "<group>"; };
@@ -53,25 +54,24 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Frontend/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Frontend/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Frontend/main.m; sourceTree = "<group>"; };
+ 1AC3226BEAF24D06C41E5569 /* libPods-Frontend-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
2D02E47B1E0B4A5D006451C7 /* Frontend-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Frontend-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2D02E4901E0B4A5D006451C7 /* Frontend-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Frontend-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
- 545F2AEA87DB571518CCFA32 /* Pods-Frontend.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend.debug.xcconfig"; path = "Target Support Files/Pods-Frontend/Pods-Frontend.debug.xcconfig"; sourceTree = "<group>"; };
- 567A4E39A63C7DE8FD446FC2 /* Pods-Frontend-FrontendTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-FrontendTests.release.xcconfig"; path = "Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests.release.xcconfig"; sourceTree = "<group>"; };
- 602415FF24B9FF3F87744F70 /* Pods-Frontend-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOSTests/Pods-Frontend-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
+ 4633B8D52C20A00C958034E6 /* Pods-Frontend-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOSTests/Pods-Frontend-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
+ 4C153C13952A77003E919731 /* Pods-Frontend-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOS.release.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOS/Pods-Frontend-tvOS.release.xcconfig"; sourceTree = "<group>"; };
69C3C9D324E1B851003075D8 /* Feather.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = "<group>"; };
- 6CAFA98ACCF23BEB39AD0A53 /* libPods-Frontend-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- 9F8E4573A72CA8220DAA9AF5 /* libPods-Frontend-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- A25FA993A8B7865AC123945B /* libPods-Frontend.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- A967DF75AA8AD56D8D15B597 /* Pods-Frontend-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOS.release.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOS/Pods-Frontend-tvOS.release.xcconfig"; sourceTree = "<group>"; };
+ 6C8C01B1DA113E97C596E47C /* libPods-Frontend-FrontendTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend-FrontendTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 82C6ED904DE229CD9C824BE9 /* Pods-Frontend.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend.release.xcconfig"; path = "Target Support Files/Pods-Frontend/Pods-Frontend.release.xcconfig"; sourceTree = "<group>"; };
+ 9441D0AF6446AB2B76D53150 /* Pods-Frontend-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOSTests/Pods-Frontend-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
+ A8F8B1059699DFE5975BAB3B /* Pods-Frontend-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOS/Pods-Frontend-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
B7B3F697256E07C400EF4575 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
B7D7DF1925880C7800C18E93 /* FrontendDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = FrontendDebug.entitlements; path = Frontend/FrontendDebug.entitlements; sourceTree = "<group>"; };
- C43E63ACF638693AFCCCEFD3 /* Pods-Frontend-FrontendTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-FrontendTests.debug.xcconfig"; path = "Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests.debug.xcconfig"; sourceTree = "<group>"; };
- C7E3BB8A63613F3856CDAFF6 /* Pods-Frontend-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOSTests/Pods-Frontend-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
- CCC6F52EEBC98F07FC072D7F /* Pods-Frontend.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend.release.xcconfig"; path = "Target Support Files/Pods-Frontend/Pods-Frontend.release.xcconfig"; sourceTree = "<group>"; };
+ B848841B31EAA032CEAC624B /* Pods-Frontend-FrontendTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-FrontendTests.release.xcconfig"; path = "Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests.release.xcconfig"; sourceTree = "<group>"; };
+ BA3B1C20B549B4C3DD9BDEFF /* Pods-Frontend.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend.debug.xcconfig"; path = "Target Support Files/Pods-Frontend/Pods-Frontend.debug.xcconfig"; sourceTree = "<group>"; };
+ D6233E676C26104C225F994F /* Pods-Frontend-FrontendTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-FrontendTests.debug.xcconfig"; path = "Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests.debug.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
- F275760F243CFBFE245CDDC8 /* Pods-Frontend-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Frontend-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Frontend-tvOS/Pods-Frontend-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
- F9583A4B15B8BC744CC480BD /* libPods-Frontend-FrontendTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend-FrontendTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ F8C4537388D0708785A4770E /* libPods-Frontend-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Frontend-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -79,7 +79,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 493A42D1B1923CF79BDBA497 /* libPods-Frontend-FrontendTests.a in Frameworks */,
+ 8CFABFFB75409DE440B1F946 /* libPods-Frontend-FrontendTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -87,7 +87,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- FE86B674D4BDCF5024DDFC4A /* libPods-Frontend.a in Frameworks */,
+ 162320D6BACFC1F441EC22C1 /* libPods-Frontend.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -95,7 +95,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 28153F30DD8A96545B6DDE3D /* libPods-Frontend-tvOS.a in Frameworks */,
+ B6D41FC4D095A2EF7C3277A9 /* libPods-Frontend-tvOS.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -103,7 +103,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 1E7AD3FE86DF4BD0A9C17980 /* libPods-Frontend-tvOSTests.a in Frameworks */,
+ E6C87B035E8221C50D635E8F /* libPods-Frontend-tvOSTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -149,10 +149,10 @@
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
- A25FA993A8B7865AC123945B /* libPods-Frontend.a */,
- F9583A4B15B8BC744CC480BD /* libPods-Frontend-FrontendTests.a */,
- 6CAFA98ACCF23BEB39AD0A53 /* libPods-Frontend-tvOS.a */,
- 9F8E4573A72CA8220DAA9AF5 /* libPods-Frontend-tvOSTests.a */,
+ 032770E196D0B343FBF58097 /* libPods-Frontend.a */,
+ 6C8C01B1DA113E97C596E47C /* libPods-Frontend-FrontendTests.a */,
+ F8C4537388D0708785A4770E /* libPods-Frontend-tvOS.a */,
+ 1AC3226BEAF24D06C41E5569 /* libPods-Frontend-tvOSTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -201,14 +201,14 @@
DC1ED7ABEFF4D056945504EA /* Pods */ = {
isa = PBXGroup;
children = (
- 545F2AEA87DB571518CCFA32 /* Pods-Frontend.debug.xcconfig */,
- CCC6F52EEBC98F07FC072D7F /* Pods-Frontend.release.xcconfig */,
- C43E63ACF638693AFCCCEFD3 /* Pods-Frontend-FrontendTests.debug.xcconfig */,
- 567A4E39A63C7DE8FD446FC2 /* Pods-Frontend-FrontendTests.release.xcconfig */,
- F275760F243CFBFE245CDDC8 /* Pods-Frontend-tvOS.debug.xcconfig */,
- A967DF75AA8AD56D8D15B597 /* Pods-Frontend-tvOS.release.xcconfig */,
- 602415FF24B9FF3F87744F70 /* Pods-Frontend-tvOSTests.debug.xcconfig */,
- C7E3BB8A63613F3856CDAFF6 /* Pods-Frontend-tvOSTests.release.xcconfig */,
+ BA3B1C20B549B4C3DD9BDEFF /* Pods-Frontend.debug.xcconfig */,
+ 82C6ED904DE229CD9C824BE9 /* Pods-Frontend.release.xcconfig */,
+ D6233E676C26104C225F994F /* Pods-Frontend-FrontendTests.debug.xcconfig */,
+ B848841B31EAA032CEAC624B /* Pods-Frontend-FrontendTests.release.xcconfig */,
+ A8F8B1059699DFE5975BAB3B /* Pods-Frontend-tvOS.debug.xcconfig */,
+ 4C153C13952A77003E919731 /* Pods-Frontend-tvOS.release.xcconfig */,
+ 9441D0AF6446AB2B76D53150 /* Pods-Frontend-tvOSTests.debug.xcconfig */,
+ 4633B8D52C20A00C958034E6 /* Pods-Frontend-tvOSTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -220,11 +220,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "FrontendTests" */;
buildPhases = (
- 28B2F0B3018A6952F17878CA /* [CP] Check Pods Manifest.lock */,
+ A79A7EF8439F90A801249EBE /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
- 6052DFFE4C25A50B464D7EDD /* [CP] Copy Pods Resources */,
+ AD3F50D8788DFD331D4AEF7D /* [CP] Embed Pods Frameworks */,
+ 8246E283BC1298AD621D00BC /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -240,14 +241,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Frontend" */;
buildPhases = (
- 55E11A8968CEA26E8DB0C49C /* [CP] Check Pods Manifest.lock */,
+ 0BFB58C1355276095725E674 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
- 5F19A5045F2557A3A7A71AA2 /* [CP] Copy Pods Resources */,
- 4136E2305F8E25C7C69F8EEF /* [CP-User] [RNFB] Core Configuration */,
+ 901AC37769F9C0ACE97F2ECF /* [CP] Embed Pods Frameworks */,
+ 40BC5C221AB5093182A8B9DE /* [CP] Copy Pods Resources */,
+ 5A5C99B7D995797D0BBC1D92 /* [CP-User] [RNFB] Core Configuration */,
);
buildRules = (
);
@@ -262,7 +264,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Frontend-tvOS" */;
buildPhases = (
- 7BCEB0E5F3DB51ADCE257331 /* [CP] Check Pods Manifest.lock */,
+ 8933A0166DD24089BC76D98F /* [CP] Check Pods Manifest.lock */,
FD10A7F122414F3F0027D42C /* Start Packager */,
2D02E4771E0B4A5D006451C7 /* Sources */,
2D02E4781E0B4A5D006451C7 /* Frameworks */,
@@ -282,7 +284,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Frontend-tvOSTests" */;
buildPhases = (
- 5369A53AD507805BDB117490 /* [CP] Check Pods Manifest.lock */,
+ C2CBCAC2303D8CE511B1BD24 /* [CP] Check Pods Manifest.lock */,
2D02E48C1E0B4A5D006451C7 /* Sources */,
2D02E48D1E0B4A5D006451C7 /* Frameworks */,
2D02E48E1E0B4A5D006451C7 /* Resources */,
@@ -398,7 +400,7 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
- 28B2F0B3018A6952F17878CA /* [CP] Check Pods Manifest.lock */ = {
+ 0BFB58C1355276095725E674 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -413,7 +415,7 @@
outputFileListPaths = (
);
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Frontend-FrontendTests-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-Frontend-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -434,61 +436,7 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
- 4136E2305F8E25C7C69F8EEF /* [CP-User] [RNFB] Core Configuration */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- name = "[CP-User] [RNFB] Core Configuration";
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\n\n # config.admob_delay_app_measurement_init\n _ADMOB_DELAY_APP_MEASUREMENT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_delay_app_measurement_init\")\n if [[ $_ADMOB_DELAY_APP_MEASUREMENT == \"true\" ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADDelayAppMeasurementInit\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"YES\")\n fi\n\n # config.admob_ios_app_id\n _ADMOB_IOS_APP_ID=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_ios_app_id\")\n if [[ $_ADMOB_IOS_APP_ID ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADApplicationIdentifier\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_ADMOB_IOS_APP_ID\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n";
- };
- 5369A53AD507805BDB117490 /* [CP] Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
- outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Frontend-tvOSTests-checkManifestLockResult.txt",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
- };
- 55E11A8968CEA26E8DB0C49C /* [CP] Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
- outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Frontend-checkManifestLockResult.txt",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
- };
- 5F19A5045F2557A3A7A71AA2 /* [CP] Copy Pods Resources */ = {
+ 40BC5C221AB5093182A8B9DE /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -542,7 +490,17 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Frontend/Pods-Frontend-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 6052DFFE4C25A50B464D7EDD /* [CP] Copy Pods Resources */ = {
+ 5A5C99B7D995797D0BBC1D92 /* [CP-User] [RNFB] Core Configuration */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ name = "[CP-User] [RNFB] Core Configuration";
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\n\n # config.admob_delay_app_measurement_init\n _ADMOB_DELAY_APP_MEASUREMENT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_delay_app_measurement_init\")\n if [[ $_ADMOB_DELAY_APP_MEASUREMENT == \"true\" ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADDelayAppMeasurementInit\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"YES\")\n fi\n\n # config.admob_ios_app_id\n _ADMOB_IOS_APP_ID=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_ios_app_id\")\n if [[ $_ADMOB_IOS_APP_ID ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADApplicationIdentifier\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_ADMOB_IOS_APP_ID\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n";
+ };
+ 8246E283BC1298AD621D00BC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -596,7 +554,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 7BCEB0E5F3DB51ADCE257331 /* [CP] Check Pods Manifest.lock */ = {
+ 8933A0166DD24089BC76D98F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -618,6 +576,86 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
+ 901AC37769F9C0ACE97F2ECF /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Frontend/Pods-Frontend-frameworks.sh",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Frontend/Pods-Frontend-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ A79A7EF8439F90A801249EBE /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Frontend-FrontendTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ AD3F50D8788DFD331D4AEF7D /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests-frameworks.sh",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Frontend-FrontendTests/Pods-Frontend-FrontendTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ C2CBCAC2303D8CE511B1BD24 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Frontend-tvOSTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -723,7 +761,7 @@
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = C43E63ACF638693AFCCCEFD3 /* Pods-Frontend-FrontendTests.debug.xcconfig */;
+ baseConfigurationReference = D6233E676C26104C225F994F /* Pods-Frontend-FrontendTests.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
@@ -748,7 +786,7 @@
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 567A4E39A63C7DE8FD446FC2 /* Pods-Frontend-FrontendTests.release.xcconfig */;
+ baseConfigurationReference = B848841B31EAA032CEAC624B /* Pods-Frontend-FrontendTests.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
@@ -770,7 +808,7 @@
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 545F2AEA87DB571518CCFA32 /* Pods-Frontend.debug.xcconfig */;
+ baseConfigurationReference = BA3B1C20B549B4C3DD9BDEFF /* Pods-Frontend.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@@ -803,7 +841,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = CCC6F52EEBC98F07FC072D7F /* Pods-Frontend.release.xcconfig */;
+ baseConfigurationReference = 82C6ED904DE229CD9C824BE9 /* Pods-Frontend.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@@ -829,7 +867,7 @@
};
2D02E4971E0B4A5E006451C7 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = F275760F243CFBFE245CDDC8 /* Pods-Frontend-tvOS.debug.xcconfig */;
+ baseConfigurationReference = A8F8B1059699DFE5975BAB3B /* Pods-Frontend-tvOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
@@ -857,7 +895,7 @@
};
2D02E4981E0B4A5E006451C7 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = A967DF75AA8AD56D8D15B597 /* Pods-Frontend-tvOS.release.xcconfig */;
+ baseConfigurationReference = 4C153C13952A77003E919731 /* Pods-Frontend-tvOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
@@ -885,7 +923,7 @@
};
2D02E4991E0B4A5E006451C7 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 602415FF24B9FF3F87744F70 /* Pods-Frontend-tvOSTests.debug.xcconfig */;
+ baseConfigurationReference = 9441D0AF6446AB2B76D53150 /* Pods-Frontend-tvOSTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
@@ -912,7 +950,7 @@
};
2D02E49A1E0B4A5E006451C7 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = C7E3BB8A63613F3856CDAFF6 /* Pods-Frontend-tvOSTests.release.xcconfig */;
+ baseConfigurationReference = 4633B8D52C20A00C958034E6 /* Pods-Frontend-tvOSTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
diff --git a/ios/Podfile b/ios/Podfile
index 73187053..4eca4100 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -15,7 +15,7 @@ target 'Frontend' do
# An issue in flipper-folly podspec caused failure in building.
# Using an older version of flipper folly for that purpose.
# https://github.com/facebook/react-native/issues/30836
- use_flipper!({ 'Flipper-Folly' => '2.3.0' })
+ use_flipper!({ 'Flipper-Folly' => '2.5.3', 'Flipper' => '0.87.0', 'Flipper-RSocket' => '1.3.1' })
post_install do |installer|
flipper_post_install(installer)
end
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 961d650a..883e3552 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -3,7 +3,6 @@ PODS:
- BVLinearGradient (2.5.6):
- React
- CocoaAsyncSocket (7.6.5)
- - CocoaLibEvent (1.0.0)
- DoubleConversion (1.1.6)
- FBLazyVector (0.63.3)
- FBReactNativeSpec (0.63.3):
@@ -36,17 +35,17 @@ PODS:
- FirebaseCoreDiagnostics (~> 7.4)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/Logger (~> 7.0)
- - FirebaseCoreDiagnostics (7.7.0):
+ - FirebaseCoreDiagnostics (7.9.0):
- GoogleDataTransport (~> 8.0)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/Logger (~> 7.0)
- nanopb (~> 2.30907.0)
- - FirebaseInstallations (7.7.0):
+ - FirebaseInstallations (7.11.0):
- FirebaseCore (~> 7.0)
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/UserDefaults (~> 7.0)
- PromisesObjC (~> 1.2)
- - FirebaseInstanceID (7.7.0):
+ - FirebaseInstanceID (7.11.0):
- FirebaseCore (~> 7.0)
- FirebaseInstallations (~> 7.0)
- GoogleUtilities/Environment (~> 7.0)
@@ -58,50 +57,61 @@ PODS:
- GoogleUtilities/Environment (~> 7.0)
- GoogleUtilities/Reachability (~> 7.0)
- GoogleUtilities/UserDefaults (~> 7.0)
- - Flipper (0.54.0):
- - Flipper-Folly (~> 2.2)
- - Flipper-RSocket (~> 1.1)
+ - Flipper (0.87.0):
+ - Flipper-Folly (~> 2.5)
+ - Flipper-RSocket (~> 1.3)
- Flipper-DoubleConversion (1.1.7)
- - Flipper-Folly (2.3.0):
+ - Flipper-Folly (2.5.3):
- boost-for-react-native
- - CocoaLibEvent (~> 1.0)
- Flipper-DoubleConversion
- Flipper-Glog
- - OpenSSL-Universal (= 1.0.2.20)
+ - libevent (~> 2.1.12)
+ - OpenSSL-Universal (= 1.1.180)
- Flipper-Glog (0.3.6)
- Flipper-PeerTalk (0.0.4)
- - Flipper-RSocket (1.1.0):
- - Flipper-Folly (~> 2.2)
- - FlipperKit (0.54.0):
- - FlipperKit/Core (= 0.54.0)
- - FlipperKit/Core (0.54.0):
- - Flipper (~> 0.54.0)
+ - Flipper-RSocket (1.3.1):
+ - Flipper-Folly (~> 2.5)
+ - FlipperKit (0.87.0):
+ - FlipperKit/Core (= 0.87.0)
+ - FlipperKit/Core (0.87.0):
+ - Flipper (~> 0.87.0)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- - FlipperKit/CppBridge (0.54.0):
- - Flipper (~> 0.54.0)
- - FlipperKit/FBCxxFollyDynamicConvert (0.54.0):
- - Flipper-Folly (~> 2.2)
- - FlipperKit/FBDefines (0.54.0)
- - FlipperKit/FKPortForwarding (0.54.0):
+ - FlipperKit/CppBridge (0.87.0):
+ - Flipper (~> 0.87.0)
+ - FlipperKit/FBCxxFollyDynamicConvert (0.87.0):
+ - Flipper-Folly (~> 2.5)
+ - FlipperKit/FBDefines (0.87.0)
+ - FlipperKit/FKPortForwarding (0.87.0):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- - FlipperKit/FlipperKitHighlightOverlay (0.54.0)
- - FlipperKit/FlipperKitLayoutPlugin (0.54.0):
+ - FlipperKit/FlipperKitHighlightOverlay (0.87.0)
+ - FlipperKit/FlipperKitLayoutHelpers (0.87.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
+ - FlipperKit/FlipperKitLayoutIOSDescriptors (0.87.0):
+ - FlipperKit/Core
+ - FlipperKit/FlipperKitHighlightOverlay
+ - FlipperKit/FlipperKitLayoutHelpers
- YogaKit (~> 1.18)
- - FlipperKit/FlipperKitLayoutTextSearchable (0.54.0)
- - FlipperKit/FlipperKitNetworkPlugin (0.54.0):
+ - FlipperKit/FlipperKitLayoutPlugin (0.87.0):
- FlipperKit/Core
- - FlipperKit/FlipperKitReactPlugin (0.54.0):
+ - FlipperKit/FlipperKitHighlightOverlay
+ - FlipperKit/FlipperKitLayoutHelpers
+ - FlipperKit/FlipperKitLayoutIOSDescriptors
+ - FlipperKit/FlipperKitLayoutTextSearchable
+ - YogaKit (~> 1.18)
+ - FlipperKit/FlipperKitLayoutTextSearchable (0.87.0)
+ - FlipperKit/FlipperKitNetworkPlugin (0.87.0):
+ - FlipperKit/Core
+ - FlipperKit/FlipperKitReactPlugin (0.87.0):
- FlipperKit/Core
- - FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0):
+ - FlipperKit/FlipperKitUserDefaultsPlugin (0.87.0):
- FlipperKit/Core
- - FlipperKit/SKIOSNetworkPlugin (0.54.0):
+ - FlipperKit/SKIOSNetworkPlugin (0.87.0):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- Folly (2020.01.13.00):
@@ -120,35 +130,36 @@ PODS:
- GoogleUtilities/Network (~> 7.0)
- "GoogleUtilities/NSData+zlib (~> 7.0)"
- nanopb (~> 2.30907.0)
- - GoogleDataTransport (8.2.0):
+ - GoogleDataTransport (8.3.1):
+ - GoogleUtilities/Environment (~> 7.2)
- nanopb (~> 2.30907.0)
- - GoogleUtilities/AppDelegateSwizzler (7.2.2):
+ - PromisesObjC (~> 1.2)
+ - GoogleUtilities/AppDelegateSwizzler (7.4.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- - GoogleUtilities/Environment (7.2.2):
+ - GoogleUtilities/Environment (7.4.0):
- PromisesObjC (~> 1.2)
- - GoogleUtilities/Logger (7.2.2):
+ - GoogleUtilities/Logger (7.4.0):
- GoogleUtilities/Environment
- - GoogleUtilities/MethodSwizzler (7.2.2):
+ - GoogleUtilities/MethodSwizzler (7.4.0):
- GoogleUtilities/Logger
- - GoogleUtilities/Network (7.2.2):
+ - GoogleUtilities/Network (7.4.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (7.2.2)"
- - GoogleUtilities/Reachability (7.2.2):
+ - "GoogleUtilities/NSData+zlib (7.4.0)"
+ - GoogleUtilities/Reachability (7.4.0):
- GoogleUtilities/Logger
- - GoogleUtilities/UserDefaults (7.2.2):
+ - GoogleUtilities/UserDefaults (7.4.0):
- GoogleUtilities/Logger
+ - libevent (2.1.12)
- nanopb (2.30907.0):
- nanopb/decode (= 2.30907.0)
- nanopb/encode (= 2.30907.0)
- nanopb/decode (2.30907.0)
- nanopb/encode (2.30907.0)
- - OpenSSL-Universal (1.0.2.20):
- - OpenSSL-Universal/Static (= 1.0.2.20)
- - OpenSSL-Universal/Static (1.0.2.20)
+ - OpenSSL-Universal (1.1.180)
- PromisesObjC (1.2.12)
- RCTRequired (0.63.3)
- RCTTypeSafety (0.63.3):
@@ -467,7 +478,7 @@ PODS:
- React
- RNVectorIcons (7.1.0):
- React
- - TOCropViewController (2.5.5)
+ - TOCropViewController (2.6.0)
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
@@ -478,25 +489,25 @@ DEPENDENCIES:
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
- Firebase/Analytics
- - Flipper (~> 0.54.0)
+ - Flipper (= 0.87.0)
- Flipper-DoubleConversion (= 1.1.7)
- - Flipper-Folly (= 2.3.0)
+ - Flipper-Folly (= 2.5.3)
- Flipper-Glog (= 0.3.6)
- Flipper-PeerTalk (~> 0.0.4)
- - Flipper-RSocket (~> 1.1)
- - FlipperKit (~> 0.54.0)
- - FlipperKit/Core (~> 0.54.0)
- - FlipperKit/CppBridge (~> 0.54.0)
- - FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0)
- - FlipperKit/FBDefines (~> 0.54.0)
- - FlipperKit/FKPortForwarding (~> 0.54.0)
- - FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0)
- - FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0)
- - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0)
- - FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0)
- - FlipperKit/FlipperKitReactPlugin (~> 0.54.0)
- - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0)
- - FlipperKit/SKIOSNetworkPlugin (~> 0.54.0)
+ - Flipper-RSocket (= 1.3.1)
+ - FlipperKit (= 0.87.0)
+ - FlipperKit/Core (= 0.87.0)
+ - FlipperKit/CppBridge (= 0.87.0)
+ - FlipperKit/FBCxxFollyDynamicConvert (= 0.87.0)
+ - FlipperKit/FBDefines (= 0.87.0)
+ - FlipperKit/FKPortForwarding (= 0.87.0)
+ - FlipperKit/FlipperKitHighlightOverlay (= 0.87.0)
+ - FlipperKit/FlipperKitLayoutPlugin (= 0.87.0)
+ - FlipperKit/FlipperKitLayoutTextSearchable (= 0.87.0)
+ - FlipperKit/FlipperKitNetworkPlugin (= 0.87.0)
+ - FlipperKit/FlipperKitReactPlugin (= 0.87.0)
+ - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.87.0)
+ - FlipperKit/SKIOSNetworkPlugin (= 0.87.0)
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
@@ -553,7 +564,6 @@ SPEC REPOS:
trunk:
- boost-for-react-native
- CocoaAsyncSocket
- - CocoaLibEvent
- Firebase
- FirebaseAnalytics
- FirebaseCore
@@ -571,6 +581,7 @@ SPEC REPOS:
- GoogleAppMeasurement
- GoogleDataTransport
- GoogleUtilities
+ - libevent
- nanopb
- OpenSSL-Universal
- PromisesObjC
@@ -689,31 +700,31 @@ SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
- CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d
FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f
Firebase: e1e089d9aac215a52442583f818ab61de3c4581b
FirebaseAnalytics: 9f8f4feab1f3fddf4e4515f8f022fe6aa9e51043
FirebaseCore: 0a43b7f1c5b36f3358cd703011ca4c7e0df55870
- FirebaseCoreDiagnostics: 179bf3831213451c8addd036aca7fcf5492ec154
- FirebaseInstallations: 42c86e7b02ff75b7f27f85833bf5dcb5f38a9774
- FirebaseInstanceID: cf940324a20ac14a27ad1e931d15ac9d335526db
+ FirebaseCoreDiagnostics: 3d36e05da74cb8b7ce30e6594a8f201b982c725c
+ FirebaseInstallations: a58d4f72ec5861840b84df489f2668d970df558a
+ FirebaseInstanceID: ad5135045a498d7775903efd39762d2cdfa1be27
FirebaseMessaging: 4b9b2850fcfcaac2820097ee3703ba6cfff3df84
- Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
+ Flipper: 1bd2db48dcc31e4b167b9a33ec1df01c2ded4893
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
- Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a
+ Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
- Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
- FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
+ Flipper-RSocket: 127954abe8b162fcaf68d2134d34dc2bd7076154
+ FlipperKit: 651f50a42eb95c01b3e89a60996dd6aded529eeb
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
GoogleAppMeasurement: c542a2feaac9ab98fd074e8f1a02c3585bbfbd47
- GoogleDataTransport: 1024b1a4dfbd7a0e92cb20d7e0a6f1fb66b449a4
- GoogleUtilities: 31c5b01f978a70c6cff2afc6272b3f1921614b43
+ GoogleDataTransport: 8b0e733ea77c9218778e5a9e34ba9508b8328939
+ GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc
+ libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
nanopb: 59221d7f958fb711001e6a449489542d92ae113e
- OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd
+ OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047
RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab
@@ -761,10 +772,10 @@ SPEC CHECKSUMS:
RNShare: 503c37af86611beadccba46156fcc42170c9fb42
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59
- TOCropViewController: da59f531f8ac8a94ef6d6c0fc34009350f9e8bfe
+ TOCropViewController: 3105367e808b7d3d886a74ff59bf4804e7d3ab38
Yoga: 7d13633d129fd179e01b8953d38d47be90db185a
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
-PODFILE CHECKSUM: f676a6cdf5f98f7fdbfb1eec2ba55b39b1887a2c
+PODFILE CHECKSUM: e24412577971b52c81c348785bf01cb915155d6d
COCOAPODS: 1.10.1
diff --git a/package.json b/package.json
index 2612e67f..16932be4 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"react-native-animatable": "^1.3.3",
"react-native-confirmation-code-field": "^6.5.0",
"react-native-contacts": "^6.0.4",
+ "react-native-controlled-mentions": "^2.2.5",
"react-native-date-picker": "^3.2.5",
"react-native-device-info": "^7.3.1",
"react-native-document-picker": "^5.0.3",
@@ -101,4 +102,4 @@
"./node_modules/react-native-gesture-handler/jestSetup.js"
]
}
-}
+} \ No newline at end of file
diff --git a/src/assets/images/no_chats.png b/src/assets/images/no_chats.png
new file mode 100644
index 00000000..4e321f17
--- /dev/null
+++ b/src/assets/images/no_chats.png
Binary files differ
diff --git a/src/assets/images/no_chats@2x.png b/src/assets/images/no_chats@2x.png
new file mode 100644
index 00000000..d906df09
--- /dev/null
+++ b/src/assets/images/no_chats@2x.png
Binary files differ
diff --git a/src/assets/images/no_chats@3x.png b/src/assets/images/no_chats@3x.png
new file mode 100644
index 00000000..f0f05c7b
--- /dev/null
+++ b/src/assets/images/no_chats@3x.png
Binary files differ
diff --git a/src/components/comments/AddComment.tsx b/src/components/comments/AddComment.tsx
index 3b195a2b..dd016109 100644
--- a/src/components/comments/AddComment.tsx
+++ b/src/components/comments/AddComment.tsx
@@ -1,45 +1,50 @@
-import React, {useEffect, useRef} from 'react';
+import React, {useContext, useEffect, useRef, useState} from 'react';
import {
- Image,
Keyboard,
KeyboardAvoidingView,
Platform,
StyleSheet,
+ TextInput,
View,
} from 'react-native';
-import {TextInput, TouchableOpacity} from 'react-native-gesture-handler';
+import {MentionInput} from 'react-native-controlled-mentions';
+import {TouchableOpacity} from 'react-native-gesture-handler';
import {useDispatch, useSelector} from 'react-redux';
import UpArrowIcon from '../../assets/icons/up_arrow.svg';
import {TAGG_LIGHT_BLUE} from '../../constants';
+import {CommentContext} from '../../screens/profile/MomentCommentsScreen';
import {postComment} from '../../services';
import {updateReplyPosted} from '../../store/actions';
import {RootState} from '../../store/rootreducer';
+import {CommentThreadType, CommentType} from '../../types';
import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
-
-/**
- * This file provides the add comment view for a user.
- * Displays the logged in user's profile picture to the left and then provides space to add a comment.
- * Comment is posted when enter is pressed as requested by product team.
- */
+import {mentionPartTypes} from '../../utils/comments';
+import {Avatar} from '../common';
export interface AddCommentProps {
- setNewCommentsAvailable: Function;
- objectId: string;
+ momentId: string;
placeholderText: string;
- isCommentInFocus: boolean;
}
-const AddComment: React.FC<AddCommentProps> = ({
- setNewCommentsAvailable,
- objectId,
- placeholderText,
- isCommentInFocus,
-}) => {
- const [comment, setComment] = React.useState('');
- const [keyboardVisible, setKeyboardVisible] = React.useState(false);
-
+const AddComment: React.FC<AddCommentProps> = ({momentId, placeholderText}) => {
+ const {setShouldUpdateAllComments, commentTapped} = useContext(
+ CommentContext,
+ );
+ const [inReplyToMention, setInReplyToMention] = useState('');
+ const [comment, setComment] = useState('');
+ const [keyboardVisible, setKeyboardVisible] = useState(false);
const {avatar} = useSelector((state: RootState) => state.user);
const dispatch = useDispatch();
+ const ref = useRef<TextInput>(null);
+ const isReplyingToComment =
+ commentTapped !== undefined && !('parent_comment' in commentTapped);
+ const isReplyingToReply =
+ commentTapped !== undefined && 'parent_comment' in commentTapped;
+ const objectId: string = commentTapped
+ ? 'parent_comment' in commentTapped
+ ? (commentTapped as CommentThreadType).parent_comment.comment_id
+ : (commentTapped as CommentType).comment_id
+ : momentId;
const addComment = async () => {
const trimmed = comment.trim();
@@ -47,18 +52,19 @@ const AddComment: React.FC<AddCommentProps> = ({
return;
}
const postedComment = await postComment(
- trimmed,
+ inReplyToMention + trimmed,
objectId,
- isCommentInFocus,
+ isReplyingToComment || isReplyingToReply,
);
if (postedComment) {
setComment('');
+ setInReplyToMention('');
//Set new reply posted object
//This helps us show the latest reply on top
//Data set is kind of stale but it works
- if (isCommentInFocus) {
+ if (isReplyingToComment || isReplyingToReply) {
dispatch(
updateReplyPosted({
comment_id: postedComment.comment_id,
@@ -66,7 +72,7 @@ const AddComment: React.FC<AddCommentProps> = ({
}),
);
}
- setNewCommentsAvailable(true);
+ setShouldUpdateAllComments(true);
}
};
@@ -82,14 +88,18 @@ const AddComment: React.FC<AddCommentProps> = ({
return () => Keyboard.removeListener('keyboardWillHide', hideKeyboard);
}, []);
- const ref = useRef<TextInput>(null);
-
- //If a comment is in Focus, bring the keyboard up so user is able to type in a reply
useEffect(() => {
- if (isCommentInFocus) {
+ if (isReplyingToComment || isReplyingToReply) {
+ // bring up keyboard
ref.current?.focus();
}
- }, [isCommentInFocus]);
+ if (commentTapped && isReplyingToReply) {
+ const commenter = (commentTapped as CommentThreadType).commenter;
+ setInReplyToMention(`@[${commenter.username}](${commenter.id}) `);
+ } else {
+ setInReplyToMention('');
+ }
+ }, [isReplyingToComment, isReplyingToReply, commentTapped]);
return (
<KeyboardAvoidingView
@@ -101,22 +111,19 @@ const AddComment: React.FC<AddCommentProps> = ({
keyboardVisible ? styles.whiteBackround : {},
]}>
<View style={styles.textContainer}>
- <Image
- style={styles.avatar}
- source={
- avatar
- ? {uri: avatar}
- : require('../../assets/images/avatar-placeholder.png')
- }
- />
- <TextInput
- style={styles.text}
+ <Avatar style={styles.avatar} uri={avatar} />
+ <MentionInput
+ containerStyle={styles.text}
placeholder={placeholderText}
- placeholderTextColor="grey"
- onChangeText={setComment}
- value={comment}
- multiline={true}
- ref={ref}
+ value={inReplyToMention + comment}
+ onChange={(newText: string) => {
+ // skipping the `inReplyToMention` text
+ setComment(
+ newText.substring(inReplyToMention.length, newText.length),
+ );
+ }}
+ inputRef={ref}
+ partTypes={mentionPartTypes}
/>
<View style={styles.submitButton}>
<TouchableOpacity style={styles.submitButton} onPress={addComment}>
@@ -148,6 +155,7 @@ const styles = StyleSheet.create({
flex: 1,
padding: '1%',
marginHorizontal: '1%',
+ maxHeight: 100,
},
avatar: {
height: 35,
diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx
index 34eef418..ce346af5 100644
--- a/src/components/comments/CommentTile.tsx
+++ b/src/components/comments/CommentTile.tsx
@@ -1,119 +1,114 @@
-/* eslint-disable radix */
-import React, {Fragment, useEffect, useRef, useState} from 'react';
-import {Text, View} from 'react-native-animatable';
-import {ProfilePreview} from '../profile';
-import {CommentType, ScreenType, TypeOfComment} from '../../types';
+import {useNavigation} from '@react-navigation/native';
+import React, {Fragment, useContext, useEffect, useRef, useState} from 'react';
import {Alert, Animated, StyleSheet} from 'react-native';
-import ClockIcon from '../../assets/icons/clock-icon-01.svg';
-import {TAGG_LIGHT_BLUE} from '../../constants';
+import {Text, View} from 'react-native-animatable';
import {RectButton, TouchableOpacity} from 'react-native-gesture-handler';
-import {getTimePosted, normalize, SCREEN_WIDTH} from '../../utils';
+import Swipeable from 'react-native-gesture-handler/Swipeable';
+import {useDispatch, useSelector, useStore} from 'react-redux';
import Arrow from '../../assets/icons/back-arrow-colored.svg';
+import ClockIcon from '../../assets/icons/clock-icon-01.svg';
import Trash from '../../assets/ionicons/trash-outline.svg';
-import CommentsContainer from './CommentsContainer';
-import Swipeable from 'react-native-gesture-handler/Swipeable';
-import {deleteComment, getCommentsCount} from '../../services';
+import {TAGG_LIGHT_BLUE} from '../../constants';
import {ERROR_FAILED_TO_DELETE_COMMENT} from '../../constants/strings';
-import {useSelector} from 'react-redux';
+import {CommentContext} from '../../screens/profile/MomentCommentsScreen';
+import {deleteComment, getCommentsCount} from '../../services';
import {RootState} from '../../store/rootReducer';
+import {
+ CommentThreadType,
+ CommentType,
+ ScreenType,
+ UserType,
+} from '../../types';
+import {
+ getTimePosted,
+ navigateToProfile,
+ normalize,
+ SCREEN_WIDTH,
+} from '../../utils';
+import {renderTextWithMentions} from '../../utils/comments';
+import {ProfilePreview} from '../profile';
+import CommentsContainer from './CommentsContainer';
/**
* Displays users's profile picture, comment posted by them and the time difference between now and when a comment was posted.
*/
interface CommentTileProps {
- comment_object: CommentType;
+ commentObject: CommentType | CommentThreadType;
screenType: ScreenType;
- typeOfComment: TypeOfComment;
- setCommentObjectInFocus?: (comment: CommentType | undefined) => void;
- newCommentsAvailable: boolean;
- setNewCommentsAvailable: (available: boolean) => void;
+ isThread: boolean;
+ shouldUpdateParent: boolean;
+ setShouldUpdateParent: (update: boolean) => void;
canDelete: boolean;
}
const CommentTile: React.FC<CommentTileProps> = ({
- comment_object,
+ commentObject,
screenType,
- typeOfComment,
- setCommentObjectInFocus,
- newCommentsAvailable,
- setNewCommentsAvailable,
+ setShouldUpdateParent,
+ shouldUpdateParent,
canDelete,
+ isThread,
}) => {
- const timePosted = getTimePosted(comment_object.date_created);
+ const {setCommentTapped} = useContext(CommentContext);
+ const timePosted = getTimePosted(commentObject.date_created);
const [showReplies, setShowReplies] = useState<boolean>(false);
const [showKeyboard, setShowKeyboard] = useState<boolean>(false);
- const [newThreadAvailable, setNewThreadAvailable] = useState(true);
+ const [shouldUpdateChild, setShouldUpdateChild] = useState(true);
const swipeRef = useRef<Swipeable>(null);
- const isThread = typeOfComment === 'Thread';
-
const {replyPosted} = useSelector((state: RootState) => state.user);
+ const state: RootState = useStore().getState();
+ const navigation = useNavigation();
+ const dispatch = useDispatch();
- /**
- * Bubbling up, for handling a new comment in a thread.
- */
useEffect(() => {
- if (newCommentsAvailable) {
- setNewThreadAvailable(true);
+ if (shouldUpdateParent) {
+ setShouldUpdateChild(true);
}
- }, [newCommentsAvailable]);
+ }, [shouldUpdateParent]);
useEffect(() => {
- if (replyPosted && typeOfComment === 'Comment') {
- if (replyPosted.parent_comment.comment_id === comment_object.comment_id) {
+ if (replyPosted && !isThread) {
+ if (replyPosted.parent_comment.comment_id === commentObject.comment_id) {
setShowReplies(true);
}
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [replyPosted]);
- /**
- * Case : A COMMENT IS IN FOCUS && REPLY SECTION IS HIDDEN
- * Bring the current comment to focus
- * Case : No COMMENT IS IN FOCUS && REPLY SECTION IS SHOWN
- * Unfocus comment in focus
- */
const toggleAddComment = () => {
- //Do not allow user to reply to a thread
- if (!isThread) {
- if (setCommentObjectInFocus) {
- if (!showKeyboard) {
- setCommentObjectInFocus(comment_object);
- } else {
- setCommentObjectInFocus(undefined);
- }
- }
- setShowKeyboard(!showKeyboard);
- }
+ setCommentTapped(commentObject);
+ setShowKeyboard(!showKeyboard);
};
const toggleReplies = async () => {
- if (showReplies) {
+ if (showReplies && isThread) {
+ const comment = (commentObject as CommentThreadType).parent_comment;
//To update count of replies in case we deleted a reply
- comment_object.replies_count = parseInt(
- await getCommentsCount(comment_object.comment_id, true),
+ comment.replies_count = parseInt(
+ await getCommentsCount(comment.comment_id, true),
+ 10,
);
}
- setNewThreadAvailable(true);
+ setShouldUpdateChild(true);
setShowReplies(!showReplies);
};
/**
* Method to compute text to be shown for replies button
*/
- const getRepliesText = () =>
+ const getRepliesText = (comment: CommentType) =>
showReplies
? 'Hide'
- : comment_object.replies_count > 0
- ? `Replies (${comment_object.replies_count})`
+ : comment.replies_count > 0
+ ? `Replies (${comment.replies_count})`
: 'Replies';
const renderRightAction = (text: string, color: string) => {
const pressHandler = async () => {
swipeRef.current?.close();
- const success = await deleteComment(comment_object.comment_id, isThread);
+ const success = await deleteComment(commentObject.comment_id, isThread);
if (success) {
- setNewCommentsAvailable(true);
+ setShouldUpdateParent(true);
} else {
Alert.alert(ERROR_FAILED_TO_DELETE_COMMENT);
}
@@ -149,12 +144,17 @@ const CommentTile: React.FC<CommentTileProps> = ({
<View
style={[styles.container, isThread ? styles.moreMarginWithThread : {}]}>
<ProfilePreview
- profilePreview={comment_object.commenter}
+ profilePreview={commentObject.commenter}
previewType={'Comment'}
screenType={screenType}
/>
<TouchableOpacity style={styles.body} onPress={toggleAddComment}>
- <Text style={styles.comment}>{comment_object.comment}</Text>
+ {renderTextWithMentions({
+ value: commentObject.comment,
+ styles: styles.comment,
+ onPress: (user: UserType) =>
+ navigateToProfile(state, dispatch, navigation, screenType, user),
+ })}
<View style={styles.clockIconAndTime}>
<ClockIcon style={styles.clockIcon} />
<Text style={styles.date_time}>{' ' + timePosted}</Text>
@@ -162,11 +162,13 @@ const CommentTile: React.FC<CommentTileProps> = ({
</View>
</TouchableOpacity>
{/*** Show replies text only if there are some replies present */}
- {typeOfComment === 'Comment' && comment_object.replies_count > 0 && (
+ {!isThread && (commentObject as CommentType).replies_count > 0 && (
<TouchableOpacity
style={styles.repliesTextAndIconContainer}
onPress={toggleReplies}>
- <Text style={styles.repliesText}>{getRepliesText()}</Text>
+ <Text style={styles.repliesText}>
+ {getRepliesText(commentObject as CommentType)}
+ </Text>
<Arrow
width={12}
height={11}
@@ -183,12 +185,11 @@ const CommentTile: React.FC<CommentTileProps> = ({
{showReplies && (
<View>
<CommentsContainer
- objectId={comment_object.comment_id}
+ objectId={commentObject.comment_id}
screenType={screenType}
- setNewCommentsAvailable={setNewThreadAvailable}
- newCommentsAvailable={newThreadAvailable}
- typeOfComment={'Thread'}
- commentId={replyPosted?.comment_id}
+ shouldUpdate={shouldUpdateChild}
+ setShouldUpdate={setShouldUpdateChild}
+ isThread={true}
/>
</View>
)}
diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx
index 3dc8a71c..d5d02a92 100644
--- a/src/components/comments/CommentsContainer.tsx
+++ b/src/components/comments/CommentsContainer.tsx
@@ -1,24 +1,23 @@
-import React, {useEffect, useRef, useState} from 'react';
+import moment from 'moment';
+import React, {useContext, useEffect, useRef, useState} from 'react';
import {StyleSheet} from 'react-native';
import {FlatList} from 'react-native-gesture-handler';
import {useDispatch, useSelector} from 'react-redux';
-import CommentTile from './CommentTile';
+import {CommentContext} from '../../screens/profile/MomentCommentsScreen';
import {getComments} from '../../services';
import {updateReplyPosted} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
-import {CommentType, ScreenType, TypeOfComment} from '../../types';
+import {CommentThreadType, CommentType, ScreenType} from '../../types';
import {SCREEN_HEIGHT} from '../../utils';
+import CommentTile from './CommentTile';
+
export type CommentsContainerProps = {
screenType: ScreenType;
- //objectId can be either moment_id or comment_id
objectId: string;
commentId?: string;
- setCommentsLength?: (count: number) => void;
- newCommentsAvailable: boolean;
- setNewCommentsAvailable: (value: boolean) => void;
- typeOfComment: TypeOfComment;
- setCommentObjectInFocus?: (comment: CommentType | undefined) => void;
- commentObjectInFocus?: CommentType;
+ shouldUpdate: boolean;
+ setShouldUpdate: (update: boolean) => void;
+ isThread: boolean;
};
/**
@@ -28,14 +27,12 @@ export type CommentsContainerProps = {
const CommentsContainer: React.FC<CommentsContainerProps> = ({
screenType,
objectId,
- setCommentsLength,
- newCommentsAvailable,
- setNewCommentsAvailable,
- typeOfComment,
- setCommentObjectInFocus,
- commentObjectInFocus,
+ isThread,
+ shouldUpdate,
+ setShouldUpdate,
commentId,
}) => {
+ const {setCommentsLength, commentTapped} = useContext(CommentContext);
const {username: loggedInUsername} = useSelector(
(state: RootState) => state.user.user,
);
@@ -45,57 +42,30 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
useEffect(() => {
const loadComments = async () => {
- await getComments(objectId, typeOfComment === 'Thread').then(
- (comments) => {
- if (comments && subscribedToLoadComments) {
- setCommentsList(comments);
- if (setCommentsLength) {
- setCommentsLength(comments.length);
- }
- setNewCommentsAvailable(false);
+ await getComments(objectId, isThread).then((comments) => {
+ if (comments && subscribedToLoadComments) {
+ setCommentsList(comments);
+ if (setCommentsLength) {
+ setCommentsLength(comments.length);
}
- },
- );
+ setShouldUpdate(false);
+ }
+ });
};
let subscribedToLoadComments = true;
- if (newCommentsAvailable) {
+ if (shouldUpdate) {
loadComments();
}
return () => {
subscribedToLoadComments = false;
};
- }, [
- dispatch,
- objectId,
- newCommentsAvailable,
- setNewCommentsAvailable,
- setCommentsLength,
- typeOfComment,
- ]);
-
- // eslint-disable-next-line no-shadow
- const swapCommentTo = (commentId: string, toIndex: number) => {
- const index = commentsList.findIndex(
- (item) => item.comment_id === commentId,
- );
- if (index > 0) {
- let comments = [...commentsList];
- const temp = comments[index];
- comments[index] = comments[toIndex];
- comments[toIndex] = temp;
- setCommentsList(comments);
- }
- };
+ }, [shouldUpdate]);
useEffect(() => {
- //Scroll only if a new comment and not a reply was posted
- const shouldScroll = () =>
- typeOfComment === 'Comment' && !commentObjectInFocus;
-
const performAction = () => {
if (commentId) {
swapCommentTo(commentId, 0);
- } else if (shouldScroll()) {
+ } else if (!isThread && !commentTapped) {
setTimeout(() => {
ref.current?.scrollToEnd({animated: true});
}, 500);
@@ -108,41 +78,47 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({
//Clean up the reply id present in store
return () => {
- if (commentId && typeOfComment === 'Thread') {
+ if (commentId && isThread) {
setTimeout(() => {
dispatch(updateReplyPosted(undefined));
}, 200);
}
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [commentsList, commentId]);
- //WIP : TODO : Bring the comment in focus above the keyboard
- // useEffect(() => {
- // if (commentObjectInFocus && commentsList.length >= 3) {
- // swapCommentTo(commentObjectInFocus.comment_id, 2);
- // }
- // // eslint-disable-next-line react-hooks/exhaustive-deps
- // }, [commentObjectInFocus]);
+ // eslint-disable-next-line no-shadow
+ const swapCommentTo = (commentId: string, toIndex: number) => {
+ const index = commentsList.findIndex(
+ (item) => item.comment_id === commentId,
+ );
+ if (index > 0) {
+ let comments = [...commentsList];
+ const temp = comments[index];
+ comments[index] = comments[toIndex];
+ comments[toIndex] = temp;
+ setCommentsList(comments);
+ }
+ };
const ITEM_HEIGHT = SCREEN_HEIGHT / 7.0;
- const renderComment = ({item}: {item: CommentType}) => (
+ const renderComment = ({item}: {item: CommentType | CommentThreadType}) => (
<CommentTile
key={item.comment_id}
- comment_object={item}
+ commentObject={item}
screenType={screenType}
- typeOfComment={typeOfComment}
- setCommentObjectInFocus={setCommentObjectInFocus}
- newCommentsAvailable={newCommentsAvailable}
- setNewCommentsAvailable={setNewCommentsAvailable}
+ isThread={isThread}
+ shouldUpdateParent={shouldUpdate}
+ setShouldUpdateParent={setShouldUpdate}
canDelete={item.commenter.username === loggedInUsername}
/>
);
return (
<FlatList
- data={commentsList}
+ data={commentsList.sort(
+ (a, b) => moment(a.date_created).unix() - moment(b.date_created).unix(),
+ )}
ref={ref}
keyExtractor={(item, index) => index.toString()}
decelerationRate={'fast'}
diff --git a/src/components/common/Avatar.tsx b/src/components/common/Avatar.tsx
new file mode 100644
index 00000000..831cf906
--- /dev/null
+++ b/src/components/common/Avatar.tsx
@@ -0,0 +1,18 @@
+import React, {FC} from 'react';
+import {Image, ImageStyle, StyleProp} from 'react-native';
+
+type AvatarProps = {
+ style: StyleProp<ImageStyle>;
+ uri: string | undefined;
+};
+const Avatar: FC<AvatarProps> = ({style, uri}) => {
+ return (
+ <Image
+ style={style}
+ defaultSource={require('../../assets/images/avatar-placeholder.png')}
+ source={{uri, cache: 'reload'}}
+ />
+ );
+};
+
+export default Avatar;
diff --git a/src/components/common/AvatarTitle.tsx b/src/components/common/AvatarTitle.tsx
index 81351327..a2a7c0aa 100644
--- a/src/components/common/AvatarTitle.tsx
+++ b/src/components/common/AvatarTitle.tsx
@@ -1,10 +1,11 @@
import React from 'react';
-import {Image, StyleSheet, View} from 'react-native';
+import {StyleSheet, View} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import {TAGGS_GRADIENT} from '../../constants';
+import Avatar from './Avatar';
type AvatarTitleProps = {
- avatar: string | null;
+ avatar: string | undefined;
};
const AvatarTitle: React.FC<AvatarTitleProps> = ({avatar}) => {
return (
@@ -16,14 +17,7 @@ const AvatarTitle: React.FC<AvatarTitleProps> = ({avatar}) => {
angleCenter={{x: 0.5, y: 0.5}}
style={styles.gradient}
/>
- <Image
- style={styles.avatar}
- source={
- avatar
- ? {uri: avatar}
- : require('../../assets/images/avatar-placeholder.png')
- }
- />
+ <Avatar style={styles.avatar} uri={avatar} />
</View>
);
};
diff --git a/src/components/common/EmptyContentView.tsx b/src/components/common/EmptyContentView.tsx
new file mode 100644
index 00000000..14ad4af1
--- /dev/null
+++ b/src/components/common/EmptyContentView.tsx
@@ -0,0 +1,132 @@
+import React from 'react';
+import {Image, Text, StyleSheet, View} from 'react-native';
+import LinearGradient from 'react-native-linear-gradient';
+import {
+ UP_TO_DATE,
+ NO_NEW_NOTIFICATIONS,
+ FIRST_MESSAGE,
+ START_CHATTING,
+} from '../../constants/strings';
+import {NOTIFICATION_GRADIENT} from '../../constants/constants';
+import {SCREEN_HEIGHT, normalize, SCREEN_WIDTH} from '../../utils';
+import {EmptyViewProps} from '../../types/index';
+
+const EmptyContentView: React.FC<EmptyViewProps> = ({viewType}) => {
+ const _getNotificationImage = () => {
+ return (
+ <LinearGradient
+ style={styles.backgroundLinearView}
+ useAngle={true}
+ angle={180}
+ colors={NOTIFICATION_GRADIENT}>
+ <Image
+ source={require('../../assets/images/empty_notifications.png')}
+ />
+ </LinearGradient>
+ );
+ };
+
+ const _getChatImage = () => {
+ return (
+ <LinearGradient
+ style={styles.backgroundLinearView}
+ useAngle={true}
+ angle={180}
+ colors={NOTIFICATION_GRADIENT}>
+ <Image
+ style={styles.imageStyles}
+ source={require('../../assets/images/no_chats.png')}
+ />
+ </LinearGradient>
+ );
+ };
+
+ const _getImageForType = () => {
+ switch (viewType) {
+ case 'Notification':
+ return _getNotificationImage();
+ case 'ChatList':
+ return _getChatImage();
+ }
+ };
+
+ const _getTextForNotification = () => {
+ return (
+ <>
+ <View style={styles.topMargin}>
+ <Text style={styles.upperTextStyle}>{UP_TO_DATE}</Text>
+ </View>
+ <View>
+ <Text style={styles.bottomTextStyle}>{NO_NEW_NOTIFICATIONS}</Text>
+ </View>
+ </>
+ );
+ };
+
+ const _getTextForChat = () => {
+ return (
+ <View style={styles.chatTextStyles}>
+ <View style={styles.topMargin}>
+ <Text style={styles.upperTextStyle}>{START_CHATTING}</Text>
+ </View>
+ <View>
+ <Text style={styles.bottomTextStyle}>{FIRST_MESSAGE}</Text>
+ </View>
+ </View>
+ );
+ };
+
+ const _getTextForType = () => {
+ switch (viewType) {
+ case 'Notification':
+ return _getTextForNotification();
+ case 'ChatList':
+ return _getTextForChat();
+ }
+ };
+
+ return (
+ <View style={styles.container}>
+ {_getImageForType()}
+ {_getTextForType()}
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ topMargin: {
+ marginTop: SCREEN_HEIGHT * 0.025,
+ paddingBottom: '5%',
+ },
+ upperTextStyle: {
+ textAlign: 'center',
+ fontWeight: '700',
+ fontSize: normalize(23),
+ lineHeight: normalize(40),
+ },
+ chatTextStyles: {
+ width: '85%',
+ },
+ bottomTextStyle: {
+ textAlign: 'center',
+ color: '#808080',
+ fontWeight: '600',
+ fontSize: normalize(20),
+ lineHeight: normalize(30),
+ },
+ imageStyles: {
+ width: SCREEN_WIDTH * 0.72,
+ height: SCREEN_WIDTH * 0.72,
+ },
+ backgroundLinearView: {
+ borderRadius: (SCREEN_WIDTH * 0.72) / 2,
+ },
+});
+
+export default EmptyContentView;
diff --git a/src/components/common/TaggTypeahead.tsx b/src/components/common/TaggTypeahead.tsx
new file mode 100644
index 00000000..7cd99278
--- /dev/null
+++ b/src/components/common/TaggTypeahead.tsx
@@ -0,0 +1,75 @@
+import React, {Fragment, useEffect, useState} from 'react';
+import {ScrollView, StyleSheet} from 'react-native';
+import {MentionSuggestionsProps} from 'react-native-controlled-mentions';
+import {SEARCH_ENDPOINT_MESSAGES} from '../../constants';
+import {loadSearchResults} from '../../services';
+import {ProfilePreviewType} from '../../types';
+import {SCREEN_WIDTH} from '../../utils';
+import TaggUserRowCell from './TaggUserRowCell';
+
+const TaggTypeahead: React.FC<MentionSuggestionsProps> = ({
+ keyword,
+ onSuggestionPress,
+}) => {
+ const [results, setResults] = useState<ProfilePreviewType[]>([]);
+ const [height, setHeight] = useState(0);
+
+ useEffect(() => {
+ getQuerySuggested();
+ }, [keyword]);
+
+ const getQuerySuggested = async () => {
+ if (!keyword || keyword.length < 3) {
+ setResults([]);
+ return;
+ }
+ const searchResults = await loadSearchResults(
+ `${SEARCH_ENDPOINT_MESSAGES}?query=${keyword}`,
+ );
+ if (searchResults && searchResults.users) {
+ setResults(searchResults.users);
+ }
+ };
+
+ if (results.length === 0) {
+ return <Fragment />;
+ }
+
+ return (
+ <ScrollView
+ style={[styles.container, {top: -(height + 30)}]}
+ showsVerticalScrollIndicator={false}
+ onLayout={(event) => {
+ setHeight(event.nativeEvent.layout.height);
+ }}>
+ {results.map((user) => (
+ <TaggUserRowCell
+ onPress={() => {
+ onSuggestionPress({
+ id: user.id,
+ name: user.username,
+ });
+ setResults([]);
+ }}
+ user={user}
+ />
+ ))}
+ </ScrollView>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ marginLeft: SCREEN_WIDTH * 0.05,
+ width: SCREEN_WIDTH * 0.9,
+ maxHeight: 264,
+ borderRadius: 10,
+ backgroundColor: 'white',
+ position: 'absolute',
+ alignSelf: 'center',
+ zIndex: 1,
+ borderWidth: 1,
+ },
+});
+
+export default TaggTypeahead;
diff --git a/src/components/common/TaggUserRowCell.tsx b/src/components/common/TaggUserRowCell.tsx
new file mode 100644
index 00000000..446dedc9
--- /dev/null
+++ b/src/components/common/TaggUserRowCell.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
+import {ProfilePreviewType} from '../../types';
+import {normalize} from '../../utils';
+import Avatar from './Avatar';
+
+type TaggUserRowCellProps = {
+ onPress: () => void;
+ user: ProfilePreviewType;
+};
+const TaggUserRowCell: React.FC<TaggUserRowCellProps> = ({onPress, user}) => {
+ return (
+ <TouchableOpacity onPress={onPress} style={styles.container}>
+ <Avatar style={styles.image} uri={user.thumbnail_url} />
+ <View style={styles.textContent}>
+ <Text style={styles.username}>{`@${user.username}`}</Text>
+ <Text style={styles.name}>
+ {user.first_name} {user.last_name}
+ </Text>
+ </View>
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ paddingHorizontal: 25,
+ paddingVertical: 15,
+ width: '100%',
+ },
+ image: {
+ width: normalize(30),
+ height: normalize(30),
+ borderRadius: 30,
+ },
+ textContent: {
+ flexDirection: 'column',
+ justifyContent: 'space-between',
+ marginLeft: 20,
+ },
+ username: {
+ fontWeight: '500',
+ fontSize: normalize(14),
+ },
+ name: {
+ fontWeight: '500',
+ fontSize: normalize(12),
+ color: '#828282',
+ },
+});
+export default TaggUserRowCell;
diff --git a/src/components/common/index.ts b/src/components/common/index.ts
index 5a601f1d..b38056c6 100644
--- a/src/components/common/index.ts
+++ b/src/components/common/index.ts
@@ -23,3 +23,6 @@ export {default as FriendsButton} from './FriendsButton';
export {default as TaggSquareButton} from './TaggSquareButton';
export {default as GradientBorderButton} from './GradientBorderButton';
export {default as BasicButton} from './BasicButton';
+export {default as Avatar} from './Avatar';
+export {default as TaggTypeahead} from './TaggTypeahead';
+export {default as TaggUserRowCell} from './TaggUserRowCell';
diff --git a/src/components/messages/ChannelPreview.tsx b/src/components/messages/ChannelPreview.tsx
index 3d31d42a..878e5a6b 100644
--- a/src/components/messages/ChannelPreview.tsx
+++ b/src/components/messages/ChannelPreview.tsx
@@ -22,6 +22,7 @@ import {
} from '../../types';
import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
import {getMember, isOnline} from '../../utils/messages';
+import {Avatar} from '../common';
const ChannelPreview: React.FC<
ChannelPreviewMessengerProps<
@@ -87,13 +88,9 @@ const ChannelPreview: React.FC<
navigation.navigate('Chat');
}}>
<View>
- <Image
+ <Avatar
style={styles.avatar}
- source={
- member
- ? {uri: member.user?.thumbnail_url}
- : require('../../assets/images/avatar-placeholder.png')
- }
+ uri={member?.user?.thumbnail_url as string}
/>
{online && <View style={styles.online} />}
</View>
diff --git a/src/components/messages/ChatHeader.tsx b/src/components/messages/ChatHeader.tsx
index 7ddaa7e6..37dab0fd 100644
--- a/src/components/messages/ChatHeader.tsx
+++ b/src/components/messages/ChatHeader.tsx
@@ -1,6 +1,6 @@
import {useNavigation} from '@react-navigation/native';
import React, {useContext} from 'react';
-import {Image, StyleSheet, View} from 'react-native';
+import {StyleSheet, View} from 'react-native';
import {Text} from 'react-native-animatable';
import {TouchableOpacity} from 'react-native-gesture-handler';
import {useDispatch, useStore} from 'react-redux';
@@ -15,6 +15,7 @@ import {
userXInStore,
} from '../../utils';
import {formatLastSeenText, getMember, isOnline} from '../../utils/messages';
+import {Avatar} from '../common';
type ChatHeaderProps = {
screenType: ScreenType;
@@ -50,13 +51,9 @@ const ChatHeader: React.FC<ChatHeaderProps> = (props) => {
<View style={styles.container}>
<TouchableOpacity style={styles.tappables} onPress={toProfile}>
<View>
- <Image
+ <Avatar
style={styles.avatar}
- source={
- member
- ? {uri: member.user?.thumbnail_url}
- : require('../../assets/images/avatar-placeholder.png')
- }
+ uri={member?.user?.thumbnail_url as string}
/>
{online && <View style={styles.online} />}
</View>
diff --git a/src/components/messages/ChatInput.tsx b/src/components/messages/ChatInput.tsx
index a6e5c458..5585d246 100644
--- a/src/components/messages/ChatInput.tsx
+++ b/src/components/messages/ChatInput.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import {Image, StyleSheet, View} from 'react-native';
+import {StyleSheet, View} from 'react-native';
import {useStore} from 'react-redux';
import {
AutoCompleteInput,
@@ -17,6 +17,7 @@ import {
LocalUserType,
} from '../../types';
import {normalize} from '../../utils';
+import {Avatar} from '../common';
import {ChatInputSubmit} from '../messages';
const ChatInput: React.FC<
@@ -65,14 +66,7 @@ const ChatInput: React.FC<
return (
<View style={styles.container}>
<View style={styles.textContainer}>
- <Image
- style={styles.avatar}
- source={
- avatar
- ? {uri: avatar}
- : require('../../assets/images/avatar-placeholder.png')
- }
- />
+ <Avatar style={styles.avatar} uri={avatar} />
<AutoCompleteInput />
<View style={styles.actionButtons}>
{/* TODO: Not working, toggled off for now */}
diff --git a/src/components/messages/MessageAvatar.tsx b/src/components/messages/MessageAvatar.tsx
index d275eae5..bcd4e7a8 100644
--- a/src/components/messages/MessageAvatar.tsx
+++ b/src/components/messages/MessageAvatar.tsx
@@ -1,9 +1,10 @@
import React, {useContext} from 'react';
-import {Image, StyleSheet, View} from 'react-native';
-import {getMember, normalize} from '../../utils';
-import {useMessageContext} from 'stream-chat-react-native-core';
+import {StyleSheet, View} from 'react-native';
import {useStore} from 'react-redux';
+import {useMessageContext} from 'stream-chat-react-native-core';
import {ChatContext} from '../../App';
+import {getMember, normalize} from '../../utils';
+import {Avatar} from '../common';
const MessageAvatar: React.FC = () => {
const {channel} = useContext(ChatContext);
@@ -14,13 +15,9 @@ const MessageAvatar: React.FC = () => {
return (
<View style={styles.messageAvatarContainer}>
{message.lastGroupMessage === true && (
- <Image
+ <Avatar
style={styles.messageAvatar}
- source={
- member
- ? {uri: member.user?.thumbnail_url}
- : require('../../assets/images/avatar-placeholder.png')
- }
+ uri={member?.user?.thumbnail_url as string}
/>
)}
</View>
diff --git a/src/components/moments/MomentPostContent.tsx b/src/components/moments/MomentPostContent.tsx
index d68ceaa3..03034925 100644
--- a/src/components/moments/MomentPostContent.tsx
+++ b/src/components/moments/MomentPostContent.tsx
@@ -1,8 +1,17 @@
+import {useNavigation} from '@react-navigation/native';
import React, {useEffect} from 'react';
import {Image, StyleSheet, Text, View, ViewProps} from 'react-native';
+import {useDispatch, useStore} from 'react-redux';
import {getCommentsCount} from '../../services';
-import {ScreenType} from '../../types';
-import {getTimePosted, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+import {RootState} from '../../store/rootReducer';
+import {ScreenType, UserType} from '../../types';
+import {
+ getTimePosted,
+ navigateToProfile,
+ SCREEN_HEIGHT,
+ SCREEN_WIDTH,
+} from '../../utils';
+import {renderTextWithMentions} from '../../utils/comments';
import {CommentsCount} from '../comments';
interface MomentPostContentProps extends ViewProps {
@@ -22,6 +31,9 @@ const MomentPostContent: React.FC<MomentPostContentProps> = ({
}) => {
const [elapsedTime, setElapsedTime] = React.useState<string>();
const [comments_count, setCommentsCount] = React.useState('');
+ const state: RootState = useStore().getState();
+ const navigation = useNavigation();
+ const dispatch = useDispatch();
useEffect(() => {
const fetchCommentsCount = async () => {
@@ -47,7 +59,12 @@ const MomentPostContent: React.FC<MomentPostContentProps> = ({
/>
<Text style={styles.text}>{elapsedTime}</Text>
</View>
- <Text style={styles.captionText}>{caption}</Text>
+ {renderTextWithMentions({
+ value: caption,
+ styles: styles.captionText,
+ onPress: (user: UserType) =>
+ navigateToProfile(state, dispatch, navigation, screenType, user),
+ })}
</View>
);
};
diff --git a/src/components/moments/MomentPostHeader.tsx b/src/components/moments/MomentPostHeader.tsx
index 8cf509ab..20d9150a 100644
--- a/src/components/moments/MomentPostHeader.tsx
+++ b/src/components/moments/MomentPostHeader.tsx
@@ -10,7 +10,7 @@ import {MomentMoreInfoDrawer} from '../profile';
import {loadUserMoments} from '../../store/actions';
import {useDispatch, useSelector, useStore} from 'react-redux';
import {ScreenType} from '../../types';
-import Avatar from '../profile/Avatar';
+import TaggAvatar from '../profile/TaggAvatar';
import {useNavigation} from '@react-navigation/native';
import {RootState} from '../../store/rootReducer';
import {fetchUserX, userXInStore} from '../../utils';
@@ -54,7 +54,7 @@ const MomentPostHeader: React.FC<MomentPostHeaderProps> = ({
return (
<View style={[styles.container, style]}>
<TouchableOpacity onPress={navigateToProfile} style={styles.header}>
- <Avatar
+ <TaggAvatar
style={styles.avatar}
userXId={userXId}
screenType={screenType}
diff --git a/src/components/notifications/Notification.tsx b/src/components/notifications/Notification.tsx
index 3cc1c7f1..a74480b4 100644
--- a/src/components/notifications/Notification.tsx
+++ b/src/components/notifications/Notification.tsx
@@ -30,6 +30,7 @@ import {
SCREEN_WIDTH,
userXInStore,
} from '../../utils';
+import {Avatar} from '../common';
import AcceptDeclineButtons from '../common/AcceptDeclineButtons';
interface NotificationProps {
@@ -225,14 +226,7 @@ const Notification: React.FC<NotificationProps> = (props) => {
<TouchableWithoutFeedback
onPress={navigateToProfile}
style={styles.avatarContainer}>
- <Image
- style={styles.avatar}
- source={
- avatar
- ? {uri: avatar, cache: 'reload'}
- : require('../../assets/images/avatar-placeholder.png')
- }
- />
+ <Avatar style={styles.avatar} uri={avatar} />
</TouchableWithoutFeedback>
{notification_type === 'SYSTEM_MSG' ? (
// Only verbage
diff --git a/src/components/profile/ProfileHeader.tsx b/src/components/profile/ProfileHeader.tsx
index 35ec0ea9..14f7dc71 100644
--- a/src/components/profile/ProfileHeader.tsx
+++ b/src/components/profile/ProfileHeader.tsx
@@ -8,7 +8,7 @@ import {RootState} from '../../store/rootreducer';
import {ScreenType} from '../../types';
import {hasSeenBadgeTutorial, normalize} from '../../utils';
import BadgeDetailView from '../common/BadgeDetailView';
-import Avatar from './Avatar';
+import TaggAvatar from './TaggAvatar';
import BadgeTutorial from './BadgeTutorial';
import FriendsCount from './FriendsCount';
import ProfileMoreInfoDrawer from './ProfileMoreInfoDrawer';
@@ -45,7 +45,6 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = ({
const [drawerVisible, setDrawerVisible] = useState(false);
const [showBadgeView, setBadgeViewVisible] = useState(false);
- const [firstName, lastName] = [...name.split(' ')];
const containerRef = useRef(null);
const childRef = useRef(null);
@@ -86,6 +85,10 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = ({
}
};
+ useEffect(() => {
+ setDrawerVisible(drawerVisible);
+ }, [drawerVisible]);
+
return (
<View ref={containerRef} style={styles.container}>
<ProfileMoreInfoDrawer
@@ -96,6 +99,7 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = ({
userXName={userXName}
setIsOpen={setDrawerVisible}
/>
+
{userId === loggedInUserId && measure && (
<BadgeTutorial
uniIconProps={{
@@ -107,21 +111,15 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = ({
/>
)}
<View style={styles.row}>
- <Avatar
+ <TaggAvatar
style={styles.avatar}
userXId={userXId}
screenType={screenType}
/>
<View style={styles.header}>
- {name.length <= 16 ? (
- <Text style={styles.name}>{name}</Text>
- ) : (
- <View>
- <Text style={styles.name}>{firstName}</Text>
- <Text style={styles.name}>{lastName}</Text>
- </View>
- )}
-
+ <Text style={styles.name} numberOfLines={2}>
+ {name}
+ </Text>
<View style={styles.friendsAndUniversity}>
<FriendsCount screenType={screenType} userXId={userXId} />
<TouchableOpacity
diff --git a/src/components/profile/ProfilePreview.tsx b/src/components/profile/ProfilePreview.tsx
index bea989d9..66d68d8f 100644
--- a/src/components/profile/ProfilePreview.tsx
+++ b/src/components/profile/ProfilePreview.tsx
@@ -2,7 +2,6 @@ import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
import {
Alert,
- Image,
StyleSheet,
Text,
TouchableOpacity,
@@ -23,6 +22,7 @@ import {
userXInStore,
} from '../../utils';
import {addUserToRecentlySearched} from '../../utils/search';
+import {Avatar} from '../common';
/**
* This component returns user's profile picture friended by username as a touchable component.
@@ -48,7 +48,7 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
}) => {
const navigation = useNavigation();
const {user: loggedInUser} = useSelector((state: RootState) => state.user);
- const [avatar, setAvatar] = useState<string | null>(null);
+ const [avatar, setAvatar] = useState<string>();
const dispatch = useDispatch();
useEffect(() => {
@@ -187,14 +187,7 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
<TouchableOpacity
onPress={addToRecentlyStoredAndNavigateToProfile}
style={containerStyle}>
- <Image
- style={avatarStyle}
- source={
- avatar
- ? {uri: avatar}
- : require('../../assets/images/avatar-placeholder.png')
- }
- />
+ <Avatar style={avatarStyle} uri={avatar} />
<View style={nameContainerStyle}>
{(previewType === 'Search' || previewType === 'Recent') && (
<>
diff --git a/src/components/profile/Avatar.tsx b/src/components/profile/TaggAvatar.tsx
index e57a56a3..ea0bdb65 100644
--- a/src/components/profile/Avatar.tsx
+++ b/src/components/profile/TaggAvatar.tsx
@@ -1,28 +1,27 @@
import React from 'react';
-import {Image, StyleSheet} from 'react-native';
+import {StyleSheet} from 'react-native';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/rootreducer';
import {ScreenType} from '../../types';
+import {Avatar} from '../common';
const PROFILE_DIM = 100;
-interface AvatarProps {
+interface TaggAvatarProps {
style?: object;
userXId: string | undefined;
screenType: ScreenType;
}
-const Avatar: React.FC<AvatarProps> = ({style, screenType, userXId}) => {
+const TaggAvatar: React.FC<TaggAvatarProps> = ({
+ style,
+ screenType,
+ userXId,
+}) => {
const {avatar} = useSelector((state: RootState) =>
userXId ? state.userX[screenType][userXId] : state.user,
);
- return (
- <Image
- style={[styles.image, style]}
- defaultSource={require('../../assets/images/avatar-placeholder.png')}
- source={{uri: avatar, cache: 'reload'}}
- />
- );
+ return <Avatar style={[styles.image, style]} uri={avatar} />;
};
const styles = StyleSheet.create({
@@ -33,4 +32,4 @@ const styles = StyleSheet.create({
},
});
-export default Avatar;
+export default TaggAvatar;
diff --git a/src/components/profile/index.ts b/src/components/profile/index.ts
index 260f4217..c544c3f2 100644
--- a/src/components/profile/index.ts
+++ b/src/components/profile/index.ts
@@ -8,3 +8,4 @@ export {default as Friends} from './Friends';
export {default as ProfileMoreInfoDrawer} from './ProfileMoreInfoDrawer';
export {default as MomentMoreInfoDrawer} from './MomentMoreInfoDrawer';
export {default as UniversityIcon} from './UniversityIcon';
+export {default as TaggAvatar} from './TaggAvatar';
diff --git a/src/components/search/ExploreSectionUser.tsx b/src/components/search/ExploreSectionUser.tsx
index d8c92be2..c949acd4 100644
--- a/src/components/search/ExploreSectionUser.tsx
+++ b/src/components/search/ExploreSectionUser.tsx
@@ -1,13 +1,13 @@
import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
-import {TextStyle, ViewStyle} from 'react-native';
import {
- Image,
StyleProp,
StyleSheet,
Text,
+ TextStyle,
TouchableOpacity,
ViewProps,
+ ViewStyle,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import {useDispatch, useSelector, useStore} from 'react-redux';
@@ -15,6 +15,7 @@ import {loadImageFromURL} from '../../services';
import {RootState} from '../../store/rootReducer';
import {ProfilePreviewType, ScreenType} from '../../types';
import {fetchUserX, normalize, userXInStore} from '../../utils';
+import {Avatar} from '../common';
/**
* Search Screen for user recommendations and a search
@@ -30,7 +31,7 @@ const ExploreSectionUser: React.FC<ExploreSectionUserProps> = ({
externalStyles,
}) => {
const {id, username, first_name, last_name} = user;
- const [avatar, setAvatar] = useState<string | null>(null);
+ const [avatar, setAvatar] = useState<string>();
const navigation = useNavigation();
const {user: loggedInUser} = useSelector((state: RootState) => state.user);
const state: RootState = useStore().getState();
@@ -71,14 +72,7 @@ const ExploreSectionUser: React.FC<ExploreSectionUserProps> = ({
angle={90}
angleCenter={{x: 0.5, y: 0.5}}
style={styles.gradient}>
- <Image
- source={
- avatar
- ? {uri: avatar}
- : require('../../assets/images/avatar-placeholder.png')
- }
- style={styles.profile}
- />
+ <Avatar style={styles.profile} uri={avatar} />
</LinearGradient>
<Text style={[styles.name, externalStyles?.name]} numberOfLines={2}>
{first_name} {last_name}
diff --git a/src/components/search/SearchResultCell.tsx b/src/components/search/SearchResultCell.tsx
index 5a6ea110..16e62a53 100644
--- a/src/components/search/SearchResultCell.tsx
+++ b/src/components/search/SearchResultCell.tsx
@@ -22,10 +22,10 @@ import {
} from '../../utils';
import {
checkIfUserIsBlocked,
- defaultUserProfile,
fetchUserX,
userXInStore,
} from '../../utils/users';
+import {Avatar} from '../common';
interface SearchResults {
profileData: ProfilePreviewType;
@@ -129,11 +129,7 @@ const SearchResultsCell: React.FC<SearchResults> = ({
<TouchableOpacity
onPress={addToRecentlyStoredAndNavigateToProfile}
style={styles.cellContainer}>
- <Image
- defaultSource={defaultUserProfile()}
- source={{uri: avatar}}
- style={styles.imageContainer}
- />
+ <Avatar style={styles.imageContainer} uri={avatar} />
<View style={[styles.initialTextContainer, styles.multiText]}>
<Text style={styles.initialTextStyle}>{`@${username}`}</Text>
<Text style={styles.secondaryTextStyle}>
diff --git a/src/components/taggs/TwitterTaggPost.tsx b/src/components/taggs/TwitterTaggPost.tsx
index 0a6f53d8..db07ba66 100644
--- a/src/components/taggs/TwitterTaggPost.tsx
+++ b/src/components/taggs/TwitterTaggPost.tsx
@@ -11,7 +11,7 @@ import {
} from '../../constants';
import {TwitterPostType} from '../../types';
import {handleOpenSocialUrlOnBrowser, SCREEN_WIDTH} from '../../utils';
-import {DateLabel, PostCarousel} from '../common';
+import {Avatar, DateLabel, PostCarousel} from '../common';
interface TwitterTaggPostProps {
ownerHandle: string;
@@ -31,14 +31,7 @@ const TwitterTaggPost: React.FC<TwitterTaggPostProps> = ({
)}
{/* Post header (avatar and handle) */}
<View style={styles.header}>
- <Image
- style={styles.avatar}
- source={
- post.profile_pic
- ? {uri: post.profile_pic}
- : require('../../assets/images/avatar-placeholder.png')
- }
- />
+ <Avatar style={styles.avatar} uri={post.profile_pic} />
<Text
style={styles.headerText}
onPress={() => handleOpenSocialUrlOnBrowser(post.handle, 'Twitter')}>
@@ -84,13 +77,9 @@ const TwitterTaggPost: React.FC<TwitterTaggPostProps> = ({
<View style={styles.replyHeader}>
{post.in_reply_to.text !== 'This tweet is unavailable' && (
<>
- <Image
- style={styles.replyAvatar}
- source={
- post.in_reply_to.profile_pic
- ? {uri: post.in_reply_to.profile_pic}
- : require('../../assets/images/avatar-placeholder.png')
- }
+ <Avatar
+ style={styles.avatar}
+ uri={post.in_reply_to.profile_pic}
/>
<Text
style={styles.replyHandleText}
diff --git a/src/constants/strings.ts b/src/constants/strings.ts
index 50e4518b..e8f2725d 100644
--- a/src/constants/strings.ts
+++ b/src/constants/strings.ts
@@ -56,6 +56,8 @@ export const ERROR_UPLOAD_MOMENT = 'Unable to upload moment. Please retry';
export const ERROR_UPLOAD_SMALL_PROFILE_PIC = "Can't have a profile without a pic to represent you, please upload a small profile picture";
export const ERROR_UPLOAD_SP_PHOTO = 'Unable to update suggested people photo. Please retry!';
export const ERROR_VERIFICATION_FAILED_SHORT = 'Verification failed 😓';
+export const FIRST_MESSAGE = 'How about sending your first message to your friend';
+export const START_CHATTING = 'Let’s Start Chatting!';
export const MARKED_AS_MSG = (str: string) => `Marked as ${str}`;
export const MOMENT_DELETED_MSG = 'Moment deleted....Some moments have to go, to create space for greater ones';
export const NO_NEW_NOTIFICATIONS = 'You have no new notifications';
diff --git a/src/screens/badge/BadgeScreenHeader.tsx b/src/screens/badge/BadgeScreenHeader.tsx
index aef49c85..81bbf42b 100644
--- a/src/screens/badge/BadgeScreenHeader.tsx
+++ b/src/screens/badge/BadgeScreenHeader.tsx
@@ -15,9 +15,7 @@ const BadgeScreenHeader: React.FC<BadgeScreenHeaderProps> = ({university}) => {
style={styles.icon}
/>
<View style={styles.universityTextContainer}>
- <Text style={styles.universityText}>
- {university} University Badges
- </Text>
+ <Text style={styles.universityText}>{university} Badges</Text>
</View>
<View style={styles.searchTextContainer}>
<Text style={styles.searchText}>
diff --git a/src/screens/chat/ChatListScreen.tsx b/src/screens/chat/ChatListScreen.tsx
index d2cfcb5d..1df5c2da 100644
--- a/src/screens/chat/ChatListScreen.tsx
+++ b/src/screens/chat/ChatListScreen.tsx
@@ -9,6 +9,7 @@ import {TabsGradient} from '../../components';
import {ChannelPreview, MessagesHeader} from '../../components/messages';
import {MainStackParams} from '../../routes';
import {RootState} from '../../store/rootReducer';
+import EmptyContentView from '../../components/common/EmptyContentView';
import {
LocalAttachmentType,
LocalChannelType,
@@ -99,6 +100,9 @@ const ChatListScreen: React.FC<ChatListScreenProps> = () => {
sort={{last_message_at: -1}}
maxUnreadCount={99}
Preview={ChannelPreview}
+ EmptyStateIndicator={() => {
+ return <EmptyContentView viewType={'ChatList'} />;
+ }}
/>
</View>
</Chat>
diff --git a/src/screens/chat/ChatResultsCell.tsx b/src/screens/chat/ChatResultsCell.tsx
index e1eb97dd..14062810 100644
--- a/src/screens/chat/ChatResultsCell.tsx
+++ b/src/screens/chat/ChatResultsCell.tsx
@@ -1,13 +1,13 @@
import {useNavigation} from '@react-navigation/native';
import React, {useContext, useEffect, useState} from 'react';
-import {Alert, Image, StyleSheet, Text, View} from 'react-native';
+import {Alert, StyleSheet, Text, View} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler';
import {ChatContext} from '../../App';
+import {Avatar} from '../../components';
import {ERROR_FAILED_TO_CREATE_CHANNEL} from '../../constants/strings';
import {loadImageFromURL} from '../../services';
import {ProfilePreviewType, UserType} from '../../types';
import {createChannel, normalize, SCREEN_WIDTH} from '../../utils';
-import {defaultUserProfile} from '../../utils/users';
interface ChatResults {
profileData: ProfilePreviewType;
@@ -58,11 +58,7 @@ const ChatResultsCell: React.FC<ChatResults> = ({
<TouchableOpacity
onPress={createChannelIfNotPresentAndNavigate}
style={styles.cellContainer}>
- <Image
- defaultSource={defaultUserProfile()}
- source={{uri: avatar}}
- style={styles.imageContainer}
- />
+ <Avatar style={styles.imageContainer} uri={avatar} />
<View style={[styles.initialTextContainer, styles.multiText]}>
<Text style={styles.initialTextStyle}>{`@${username}`}</Text>
<Text style={styles.secondaryTextStyle}>
diff --git a/src/screens/chat/ChatScreen.tsx b/src/screens/chat/ChatScreen.tsx
index 5874b8b6..a8e975eb 100644
--- a/src/screens/chat/ChatScreen.tsx
+++ b/src/screens/chat/ChatScreen.tsx
@@ -1,6 +1,6 @@
-import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
+import {useFocusEffect} from '@react-navigation/core';
import {StackNavigationProp} from '@react-navigation/stack';
-import React, {useContext, useEffect} from 'react';
+import React, {useCallback, useContext, useEffect} from 'react';
import {StyleSheet} from 'react-native';
import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
import {
@@ -9,8 +9,8 @@ import {
DeepPartial,
MessageInput,
MessageList,
- useAttachmentPickerContext,
Theme,
+ useAttachmentPickerContext,
} from 'stream-chat-react-native';
import {ChatContext} from '../../App';
import {
@@ -19,12 +19,11 @@ import {
DateHeader,
MessageAvatar,
MessageFooter,
- TabsGradient,
TypingIndicator,
} from '../../components';
import {MainStackParams} from '../../routes';
import {ScreenType} from '../../types';
-import {HeaderHeight, isIPhoneX, normalize, SCREEN_WIDTH} from '../../utils';
+import {HeaderHeight, normalize, SCREEN_WIDTH} from '../../utils';
type ChatScreenNavigationProp = StackNavigationProp<MainStackParams, 'Chat'>;
interface ChatScreenProps {
@@ -33,9 +32,8 @@ interface ChatScreenProps {
/*
* Screen that displays all of the user's active conversations.
*/
-const ChatScreen: React.FC<ChatScreenProps> = () => {
+const ChatScreen: React.FC<ChatScreenProps> = ({navigation}) => {
const {channel, chatClient} = useContext(ChatContext);
- const tabbarHeight = useBottomTabBarHeight();
const {setTopInset} = useAttachmentPickerContext();
const insets = useSafeAreaInsets();
const chatTheme: DeepPartial<Theme> = {
@@ -129,12 +127,25 @@ const ChatScreen: React.FC<ChatScreenProps> = () => {
setTopInset(insets.top + HeaderHeight);
});
+ //Function to get the parent TabBar navigator and setting the option for this screen.
+ useFocusEffect(
+ useCallback(() => {
+ navigation.dangerouslyGetParent()?.setOptions({
+ tabBarVisible: false,
+ });
+ return () => {
+ navigation.dangerouslyGetParent()?.setOptions({
+ tabBarVisible: true,
+ });
+ };
+ }, [navigation]),
+ );
+
return (
<SafeAreaView
style={[
styles.container,
- // unable to figure out the padding issue, a hacky solution
- {paddingBottom: isIPhoneX() ? tabbarHeight + 20 : tabbarHeight + 50},
+ styles.textBoxStyles, // Update : removed hacky soln for a common height. Original : unable to figure out the padding issue, a hacky solution {paddingBottom: isIPhoneX() ? tabbarHeight + 20 : tabbarHeight + 50},
]}>
<ChatHeader screenType={ScreenType.Chat} />
<Chat client={chatClient} style={chatTheme}>
@@ -157,7 +168,6 @@ const ChatScreen: React.FC<ChatScreenProps> = () => {
<MessageInput Input={ChatInput} />
</Channel>
</Chat>
- <TabsGradient />
</SafeAreaView>
);
};
@@ -167,6 +177,7 @@ const styles = StyleSheet.create({
backgroundColor: 'white',
flex: 1,
},
+ textBoxStyles: {paddingBottom: 60},
});
export default ChatScreen;
diff --git a/src/screens/main/NotificationsScreen.tsx b/src/screens/main/NotificationsScreen.tsx
index 3efd9af8..9fbc4cfe 100644
--- a/src/screens/main/NotificationsScreen.tsx
+++ b/src/screens/main/NotificationsScreen.tsx
@@ -28,7 +28,7 @@ import {
import {RootState} from '../../store/rootReducer';
import {NotificationType, ScreenType} from '../../types';
import {getDateAge, normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
-import EmptyNotificationView from './notification/EmptyNotificationView';
+import EmptyContentView from '../../components/common/EmptyContentView';
const NotificationsScreen: React.FC = () => {
const {newNotificationReceived} = useSelector(
@@ -304,7 +304,7 @@ const NotificationsScreen: React.FC = () => {
extraData={requestLimit}
ListEmptyComponent={
<View style={styles.emptyViewContainer}>
- <EmptyNotificationView />
+ <EmptyContentView viewType={'Notification'} />
</View>
}
/>
diff --git a/src/screens/main/notification/EmptyNotificationView.tsx b/src/screens/main/notification/EmptyNotificationView.tsx
deleted file mode 100644
index f43cfb2a..00000000
--- a/src/screens/main/notification/EmptyNotificationView.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import {Image, Text, StyleSheet, View} from 'react-native';
-import LinearGradient from 'react-native-linear-gradient';
-import {UP_TO_DATE, NO_NEW_NOTIFICATIONS} from '../../../constants/strings';
-import {NOTIFICATION_GRADIENT} from '../../../constants/constants';
-import {SCREEN_HEIGHT, normalize} from '../../../utils';
-const EmptyNotificationView: React.FC = () => {
- return (
- <View style={styles.container}>
- <LinearGradient
- style={styles.backgroundLinearView}
- useAngle={true}
- angle={180}
- colors={NOTIFICATION_GRADIENT}>
- <Image
- source={require('../../../assets/images/empty_notifications.png')}
- />
- </LinearGradient>
- <View style={styles.topMargin}>
- <Text style={styles.upperTextStyle}>{UP_TO_DATE}</Text>
- </View>
- <View>
- <Text style={styles.bottomTextStyle}>{NO_NEW_NOTIFICATIONS}</Text>
- </View>
- </View>
- );
-};
-
-const styles = StyleSheet.create({
- container: {alignItems: 'center'},
- topMargin: {marginTop: SCREEN_HEIGHT * 0.025},
- upperTextStyle: {
- fontWeight: '700',
- fontSize: normalize(23),
- lineHeight: normalize(40),
- },
- bottomTextStyle: {
- color: '#2D3B45',
- fontWeight: '600',
- fontSize: normalize(20),
- lineHeight: normalize(40),
- },
- backgroundLinearView: {
- borderRadius: 135.5,
- },
-});
-
-export default EmptyNotificationView;
diff --git a/src/screens/onboarding/Login.tsx b/src/screens/onboarding/Login.tsx
index 041fba05..3b970864 100644
--- a/src/screens/onboarding/Login.tsx
+++ b/src/screens/onboarding/Login.tsx
@@ -168,7 +168,7 @@ const Login: React.FC<LoginProps> = ({navigation}: LoginProps) => {
//Stores token received in the response into client's AsynStorage
try {
userLogin(dispatch, {userId: data.UserID, username});
- fcmService.sendFcmTokenToServer();
+ fcmService.sendFcmTokenToServer(chatClient);
connectChatAccount(data.UserID, chatClient);
} catch (err) {
Alert.alert(ERROR_INVALID_LOGIN);
diff --git a/src/screens/onboarding/OnboardingStepThree.tsx b/src/screens/onboarding/OnboardingStepThree.tsx
index 638f0889..34173b39 100644
--- a/src/screens/onboarding/OnboardingStepThree.tsx
+++ b/src/screens/onboarding/OnboardingStepThree.tsx
@@ -27,7 +27,6 @@ import {
ERROR_SELECT_CLASS_YEAR,
ERROR_SELECT_GENDER,
ERROR_SELECT_UNIVERSITY,
- ERROR_UPLOAD_SMALL_PROFILE_PIC,
} from '../../constants/strings';
import {OnboardingStackParams} from '../../routes/onboarding';
import {patchEditProfile} from '../../services';
@@ -160,10 +159,6 @@ const OnboardingStepThree: React.FC<OnboardingStepThreeProps> = ({
};
const handleSubmit = async () => {
- if (!form.smallPic) {
- Alert.alert(ERROR_UPLOAD_SMALL_PROFILE_PIC);
- return;
- }
if (form.classYear === -1) {
Alert.alert(ERROR_SELECT_CLASS_YEAR);
return;
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 156ee41c..041f0da2 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -11,9 +11,10 @@ import {
TouchableWithoutFeedback,
View,
} from 'react-native';
+import {MentionInput} from 'react-native-controlled-mentions';
import {Button} from 'react-native-elements';
import {useDispatch, useSelector} from 'react-redux';
-import {SearchBackground, TaggBigInput} from '../../components';
+import {SearchBackground} from '../../components';
import {CaptionScreenHeader} from '../../components/';
import TaggLoadingIndicator from '../../components/common/TaggLoadingIndicator';
import {TAGG_LIGHT_BLUE_2} from '../../constants';
@@ -26,6 +27,7 @@ import {
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {SCREEN_WIDTH, StatusBarHeight} from '../../utils';
+import {mentionPartTypes} from '../../utils/comments';
/**
* Upload Screen to allow users to upload posts to Tagg
@@ -49,10 +51,6 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
const [caption, setCaption] = useState('');
const [loading, setLoading] = useState(false);
- const handleCaptionUpdate = (newCaption: string) => {
- setCaption(newCaption);
- };
-
const navigateToProfile = () => {
//Since the logged In User is navigating to own profile, useXId is not required
navigation.navigate('Profile', {
@@ -112,12 +110,13 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
source={{uri: image.path}}
resizeMode={'cover'}
/>
- <TaggBigInput
- style={styles.text}
- multiline
+ <MentionInput
+ containerStyle={styles.text}
placeholder="Write something....."
placeholderTextColor="gray"
- onChangeText={handleCaptionUpdate}
+ value={caption}
+ onChange={setCaption}
+ partTypes={mentionPartTypes}
/>
</View>
</KeyboardAvoidingView>
diff --git a/src/screens/profile/MomentCommentsScreen.tsx b/src/screens/profile/MomentCommentsScreen.tsx
index b0208f6f..1a913e58 100644
--- a/src/screens/profile/MomentCommentsScreen.tsx
+++ b/src/screens/profile/MomentCommentsScreen.tsx
@@ -7,13 +7,8 @@ import {AddComment} from '../../components/';
import CommentsContainer from '../../components/comments/CommentsContainer';
import {ADD_COMMENT_TEXT} from '../../constants/strings';
import {headerBarOptions, MainStackParams} from '../../routes/main';
-import {CommentType} from '../../types';
-import {
- HeaderHeight,
- normalize,
- SCREEN_HEIGHT,
- SCREEN_WIDTH,
-} from '../../utils';
+import {CommentThreadType, CommentType} from '../../types';
+import {HeaderHeight, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
/**
* Comments Screen for an image uploaded
@@ -30,18 +25,35 @@ interface MomentCommentsScreenProps {
route: MomentCommentsScreenRouteProps;
}
+type MomentCommentContextType = {
+ commentTapped: CommentType | CommentThreadType | undefined;
+ setCommentTapped: (
+ comment: CommentType | CommentThreadType | undefined,
+ ) => void;
+ shouldUpdateAllComments: boolean;
+ setShouldUpdateAllComments: (available: boolean) => void;
+ commentsLength: number;
+ setCommentsLength: (length: number) => void;
+};
+
+export const CommentContext = React.createContext(
+ {} as MomentCommentContextType,
+);
+
const MomentCommentsScreen: React.FC<MomentCommentsScreenProps> = ({route}) => {
const navigation = useNavigation();
const {moment_id, screenType, comment_id} = route.params;
//Receives comment length from child CommentsContainer
const [commentsLength, setCommentsLength] = useState<number>(0);
- const [newCommentsAvailable, setNewCommentsAvailable] = React.useState(true);
+ const [shouldUpdateAllComments, setShouldUpdateAllComments] = React.useState(
+ true,
+ );
//Keeps track of the current comments object in focus so that the application knows which comment to post a reply to
- const [commentObjectInFocus, setCommentObjectInFocus] = useState<
- CommentType | undefined
- >(undefined);
+ const [commentTapped, setCommentTapped] = useState<
+ CommentType | CommentThreadType | undefined
+ >();
useEffect(() => {
navigation.setOptions({
@@ -50,36 +62,39 @@ const MomentCommentsScreen: React.FC<MomentCommentsScreenProps> = ({route}) => {
}, [commentsLength, navigation]);
return (
- <View style={styles.background}>
- <SafeAreaView>
- <View style={styles.body}>
- <CommentsContainer
- objectId={moment_id}
- commentId={comment_id}
- screenType={screenType}
- setCommentsLength={setCommentsLength}
- newCommentsAvailable={newCommentsAvailable}
- setNewCommentsAvailable={setNewCommentsAvailable}
- setCommentObjectInFocus={setCommentObjectInFocus}
- commentObjectInFocus={commentObjectInFocus}
- typeOfComment={'Comment'}
- />
- <AddComment
- placeholderText={
- commentObjectInFocus
- ? ADD_COMMENT_TEXT(commentObjectInFocus.commenter.username)
- : ADD_COMMENT_TEXT()
- }
- setNewCommentsAvailable={setNewCommentsAvailable}
- objectId={
- commentObjectInFocus ? commentObjectInFocus.comment_id : moment_id
- }
- isCommentInFocus={commentObjectInFocus ? true : false}
- />
- </View>
- </SafeAreaView>
- <TabsGradient />
- </View>
+ <CommentContext.Provider
+ value={{
+ commentTapped,
+ setCommentTapped,
+ shouldUpdateAllComments,
+ setShouldUpdateAllComments,
+ commentsLength,
+ setCommentsLength,
+ }}>
+ <View style={styles.background}>
+ <SafeAreaView>
+ <View style={styles.body}>
+ <CommentsContainer
+ objectId={moment_id}
+ commentId={comment_id}
+ screenType={screenType}
+ shouldUpdate={shouldUpdateAllComments}
+ setShouldUpdate={setShouldUpdateAllComments}
+ isThread={false}
+ />
+ <AddComment
+ placeholderText={
+ !commentTapped
+ ? ADD_COMMENT_TEXT()
+ : ADD_COMMENT_TEXT(commentTapped.commenter.username)
+ }
+ momentId={moment_id}
+ />
+ </View>
+ </SafeAreaView>
+ <TabsGradient />
+ </View>
+ </CommentContext.Provider>
);
};
@@ -88,39 +103,12 @@ const styles = StyleSheet.create({
backgroundColor: 'white',
height: '100%',
},
- header: {justifyContent: 'center', padding: '3%'},
- headerText: {
- position: 'absolute',
- alignSelf: 'center',
- fontSize: normalize(18),
- fontWeight: '700',
- lineHeight: normalize(21.48),
- letterSpacing: normalize(1.3),
- },
- headerButton: {
- width: '5%',
- aspectRatio: 1,
- padding: 0,
- marginLeft: '5%',
- alignSelf: 'flex-start',
- },
- headerButtonText: {
- color: 'black',
- fontSize: 18,
- fontWeight: '400',
- },
body: {
marginTop: HeaderHeight,
width: SCREEN_WIDTH * 0.9,
height: SCREEN_HEIGHT * 0.8,
paddingTop: '3%',
},
- scrollView: {
- paddingHorizontal: 20,
- },
- scrollViewContent: {
- justifyContent: 'center',
- },
});
export default MomentCommentsScreen;
diff --git a/src/screens/profile/SocialMediaTaggs.tsx b/src/screens/profile/SocialMediaTaggs.tsx
index 9186f187..52d20683 100644
--- a/src/screens/profile/SocialMediaTaggs.tsx
+++ b/src/screens/profile/SocialMediaTaggs.tsx
@@ -59,7 +59,7 @@ const SocialMediaTaggs: React.FC<SocialMediaTaggsProps> = ({
useEffect(() => {
navigation.setOptions({
headerTitle: () => {
- return <AvatarTitle avatar={avatar ?? null} />;
+ return <AvatarTitle avatar={avatar} />;
},
});
}, [avatar, navigation]);
diff --git a/src/types/types.ts b/src/types/types.ts
index 18ddbfba..00501d49 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -23,6 +23,9 @@ export interface CategoryPreviewType {
}
export type FriendshipStatusType = 'friends' | 'requested' | 'no_record';
+export interface EmptyViewProps {
+ viewType: 'Notification' | 'ChatList';
+}
export enum UniversityType {
Brown = 'Brown University',
@@ -218,8 +221,6 @@ export type NotificationType = {
unread: boolean;
};
-export type TypeOfComment = 'Comment' | 'Thread';
-
export type TypeOfNotification =
// notification_object is undefined
| 'DFT'
diff --git a/src/utils/comments.tsx b/src/utils/comments.tsx
new file mode 100644
index 00000000..a71e3857
--- /dev/null
+++ b/src/utils/comments.tsx
@@ -0,0 +1,87 @@
+import React from 'react';
+import {StyleProp, Text, TextStyle} from 'react-native';
+import {
+ isMentionPartType,
+ parseValue,
+ Part,
+ PartType,
+} from 'react-native-controlled-mentions';
+import TaggTypeahead from '../components/common/TaggTypeahead';
+import {TAGG_LIGHT_BLUE} from '../constants';
+import {UserType} from '../types';
+
+/**
+ * Part renderer
+ *
+ * https://github.com/dabakovich/react-native-controlled-mentions#rendering-mentioninputs-value
+ */
+const renderPart = (
+ part: Part,
+ index: number,
+ handlePress: (user: UserType) => void,
+) => {
+ // Just plain text
+ if (!part.partType) {
+ return <Text key={index}>{part.text}</Text>;
+ }
+
+ // Mention type part
+ if (isMentionPartType(part.partType)) {
+ return (
+ <Text
+ key={`${index}-${part.data?.trigger}`}
+ style={part.partType.textStyle}
+ onPress={() => {
+ if (part.data) {
+ handlePress({
+ userId: part.data.id,
+ username: part.data.name,
+ });
+ }
+ }}>
+ {part.text}
+ </Text>
+ );
+ }
+
+ // Other styled part types
+ return (
+ <Text key={`${index}-pattern`} style={part.partType.textStyle}>
+ {part.text}
+ </Text>
+ );
+};
+
+interface RenderProps {
+ value: string;
+ styles: StyleProp<TextStyle>;
+ onPress: (user: UserType) => void;
+}
+
+/**
+ * Value renderer. Parsing value to parts array and then mapping the array using 'renderPart'
+ *
+ * https://github.com/dabakovich/react-native-controlled-mentions#rendering-mentioninputs-value
+ */
+export const renderTextWithMentions: React.FC<RenderProps> = ({
+ value,
+ styles,
+ onPress,
+}) => {
+ const {parts} = parseValue(value, mentionPartTypes);
+ return (
+ <Text style={styles}>
+ {parts.map((part, index) => renderPart(part, index, onPress))}
+ </Text>
+ );
+};
+
+export const mentionPartTypes: PartType[] = [
+ {
+ trigger: '@',
+ renderSuggestions: (props) => <TaggTypeahead {...props} />,
+ allowedSpacesCount: 0,
+ isInsertSpaceAfterMention: true,
+ textStyle: {color: TAGG_LIGHT_BLUE},
+ },
+];
diff --git a/src/utils/users.ts b/src/utils/users.ts
index 87bcbdfc..334cb3c0 100644
--- a/src/utils/users.ts
+++ b/src/utils/users.ts
@@ -18,8 +18,8 @@ import {loadUserX} from './../store/actions/userX';
import {AppDispatch} from './../store/configureStore';
import {RootState} from './../store/rootReducer';
import {
- ProfilePreviewType,
ProfileInfoType,
+ ProfilePreviewType,
ScreenType,
UserType,
UniversityBadge,
@@ -170,11 +170,6 @@ export const checkIfUserIsBlocked = async (
return await isUserBlocked(userId, loggedInUser.userId, token);
};
-export const defaultUserProfile = () => {
- const defaultImage = require('../assets/images/avatar-placeholder.png');
- return defaultImage;
-};
-
/**
* Used to determine whether the logged-in user is able to view userX's private
* information or not.
@@ -223,3 +218,25 @@ export const removeUserBadge = async (
dispatch(updateUserBadges(badges));
}
};
+
+export const navigateToProfile = async (
+ state: RootState,
+ dispatch: any,
+ navigation: any,
+ screenType: ScreenType,
+ user: UserType,
+) => {
+ const loggedInUserId = state.user.user.userId;
+ const {userId, username} = user;
+ if (!userXInStore(state, screenType, userId)) {
+ await fetchUserX(
+ dispatch,
+ {userId: userId, username: username},
+ screenType,
+ );
+ }
+ navigation.push('Profile', {
+ userXId: userId === loggedInUserId ? undefined : userId,
+ screenType,
+ });
+};
diff --git a/yarn.lock b/yarn.lock
index d9aab38e..9088af02 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2692,6 +2692,11 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
+diff@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+ integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
+
doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -3943,7 +3948,7 @@ inquirer@^7.0.0:
strip-ansi "^6.0.0"
through "^2.3.6"
-internal-slot@^1.0.3:
+internal-slot@^1.0.2, internal-slot@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
@@ -6260,6 +6265,14 @@ react-native-contacts@^6.0.4:
resolved "https://registry.yarnpkg.com/react-native-contacts/-/react-native-contacts-6.0.5.tgz#26503c862a197eef790aee243053c0ceb23d7a0f"
integrity sha512-2BPW1bODJPnKbi/Wr2+m43hlrxcYrzMkWVAre3nMwqekSrsapMu/iSpQbxcB3Ia8cvBNH6Cu2tSqGpqY4Lc/lg==
+react-native-controlled-mentions@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/react-native-controlled-mentions/-/react-native-controlled-mentions-2.2.5.tgz#2eddcdf6b6a0ead0c448be4bb0239e10eca84a29"
+ integrity sha512-fNIQWZMPy9OvPKO3MeLX+J76Ld7OuvrrLn4xwXMOjsYjuEWtVBNc4t/ADxNc3woQCfuSEkST+SbafFpUwwLMIA==
+ dependencies:
+ diff "5.0.0"
+ string.prototype.matchall "4.0.3"
+
react-native-date-picker@^3.2.5:
version "3.2.10"
resolved "https://registry.yarnpkg.com/react-native-date-picker/-/react-native-date-picker-3.2.10.tgz#5e690db8e628255d8390e33b1e6f8fa9477f6fb9"
@@ -6631,7 +6644,7 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
-regexp.prototype.flags@^1.3.1:
+regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26"
integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==
@@ -7064,7 +7077,7 @@ shellwords@^0.1.1:
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
-side-channel@^1.0.4:
+side-channel@^1.0.3, side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
@@ -7385,6 +7398,19 @@ string-width@^4.1.0, string-width@^4.2.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
+string.prototype.matchall@4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz#24243399bc31b0a49d19e2b74171a15653ec996a"
+ integrity sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+ es-abstract "^1.18.0-next.1"
+ has-symbols "^1.0.1"
+ internal-slot "^1.0.2"
+ regexp.prototype.flags "^1.3.0"
+ side-channel "^1.0.3"
+
string.prototype.matchall@^4.0.2, string.prototype.matchall@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz#608f255e93e072107f5de066f81a2dfb78cf6b29"