diff --git a/App.js b/App.js index b49840a..e09fae4 100644 --- a/App.js +++ b/App.js @@ -6,6 +6,7 @@ import { ExploreScreen } from "./src/screens/ExploreScreen.js"; import { MutualScreen } from "./src/screens/MutualScreen.js"; import { CreatePost } from "./src/screens/CreatePost.js"; import { CalendarScreen } from "./src/screens/CalendarScreen.js"; +import { WorkoutsScreen } from "./src/screens/WorkoutsScreen.js"; import { GoalsScreen } from "./src/screens/GoalsScreen.js"; import { ProfileScreen } from "./src/screens/ProfileScreen.js"; import { FollowerScreen } from "./src/screens/FollowerScreen.js"; @@ -18,6 +19,8 @@ import { withAuthenticator, AmplifyTheme } from "aws-amplify-react-native"; import { StyleSheet, View, TitleText } from "react-native"; import { Storage } from "@aws-amplify/storage"; import * as clients3 from "@aws-sdk/client-s3"; +import { useState } from "react"; +import { Toast } from "react-native-toast-message/lib/src/Toast.js"; import { blueThemeColor } from "./src/library/constants.js"; Amplify.configure({ @@ -49,42 +52,43 @@ Amplify.configure({ const Stack = createMaterialTopTabNavigator(); const app = () => { + const [refresh, setRefresh] = useState(false); return ( - - - - {/* */} - - - {/* */} - {/* */} - - - - {/* */} - - + <> + + + + {/* */} + {(props) => } + {(props) => } + {/* */} + {/* */} + + + + + {/* */} + + + + ); }; diff --git a/assets/loading.gif b/assets/loading.gif new file mode 100644 index 0000000..9590093 Binary files /dev/null and b/assets/loading.gif differ diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..8beb344 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,30 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace +.xcode.env.local + +# Bundle artifacts +*.jsbundle + +# CocoaPods +/Pods/ diff --git a/ios/.xcode.env b/ios/.xcode.env new file mode 100644 index 0000000..3d5782c --- /dev/null +++ b/ios/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/ios/NunchuckDucks.xcodeproj/project.pbxproj b/ios/NunchuckDucks.xcodeproj/project.pbxproj new file mode 100644 index 0000000..259f0ec --- /dev/null +++ b/ios/NunchuckDucks.xcodeproj/project.pbxproj @@ -0,0 +1,493 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 102A44CA1A0940D383E99876 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52004E5FCE45C49FE9A449 /* noop-file.swift */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; + 96905EF65AED1B983A6B3ABC /* libPods-NunchuckDucks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-NunchuckDucks.a */; }; + B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; }; + BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* NunchuckDucks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NunchuckDucks.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = NunchuckDucks/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = NunchuckDucks/AppDelegate.mm; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = NunchuckDucks/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NunchuckDucks/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NunchuckDucks/main.m; sourceTree = ""; }; + 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-NunchuckDucks.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NunchuckDucks.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 6C2E3173556A471DD304B334 /* Pods-NunchuckDucks.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NunchuckDucks.debug.xcconfig"; path = "Target Support Files/Pods-NunchuckDucks/Pods-NunchuckDucks.debug.xcconfig"; sourceTree = ""; }; + 7A4D352CD337FB3A3BF06240 /* Pods-NunchuckDucks.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NunchuckDucks.release.xcconfig"; path = "Target Support Files/Pods-NunchuckDucks/Pods-NunchuckDucks.release.xcconfig"; sourceTree = ""; }; + AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = NunchuckDucks/SplashScreen.storyboard; sourceTree = ""; }; + BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NunchuckDucks/ExpoModulesProvider.swift"; sourceTree = ""; }; + FD52004E5FCE45C49FE9A449 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "NunchuckDucks/noop-file.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 96905EF65AED1B983A6B3ABC /* libPods-NunchuckDucks.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13B07FAE1A68108700A75B9A /* NunchuckDucks */ = { + isa = PBXGroup; + children = ( + BB2F792B24A3F905000567C9 /* Supporting */, + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.mm */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB71A68108700A75B9A /* main.m */, + AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */, + FD52004E5FCE45C49FE9A449 /* noop-file.swift */, + ); + name = NunchuckDucks; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-NunchuckDucks.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* NunchuckDucks */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + D65327D7A22EEC0BE12398D9 /* Pods */, + D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* NunchuckDucks.app */, + ); + name = Products; + sourceTree = ""; + }; + 92DBD88DE9BF7D494EA9DA96 /* NunchuckDucks */ = { + isa = PBXGroup; + children = ( + FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */, + ); + name = NunchuckDucks; + sourceTree = ""; + }; + BB2F792B24A3F905000567C9 /* Supporting */ = { + isa = PBXGroup; + children = ( + BB2F792C24A3F905000567C9 /* Expo.plist */, + ); + name = Supporting; + path = NunchuckDucks/Supporting; + sourceTree = ""; + }; + D65327D7A22EEC0BE12398D9 /* Pods */ = { + isa = PBXGroup; + children = ( + 6C2E3173556A471DD304B334 /* Pods-NunchuckDucks.debug.xcconfig */, + 7A4D352CD337FB3A3BF06240 /* Pods-NunchuckDucks.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = { + isa = PBXGroup; + children = ( + 92DBD88DE9BF7D494EA9DA96 /* NunchuckDucks */, + ); + name = ExpoModulesProviders; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* NunchuckDucks */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "NunchuckDucks" */; + buildPhases = ( + 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, + FD10A7F022414F080027D42C /* Start Packager */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NunchuckDucks; + productName = NunchuckDucks; + productReference = 13B07F961A680F5B00A75B9A /* NunchuckDucks.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1130; + TargetAttributes = { + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1250; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "NunchuckDucks" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* NunchuckDucks */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BB2F792D24A3F905000567C9 /* Expo.plist in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" $PROJECT_ROOT ios relative | tail -n 1)\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n"; + }; + 08A4A3CD28434E44B6B9DE2E /* [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-NunchuckDucks-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; + }; + 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NunchuckDucks/Pods-NunchuckDucks-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NunchuckDucks/Pods-NunchuckDucks-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + FD10A7F022414F080027D42C /* Start Packager */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Start Packager"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\nexport RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > `$NODE_BINARY --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'\"`\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open `$NODE_BINARY --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/launchPackager.command'\"` || echo \"Can't start packager automatically\"\n fi\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */, + 102A44CA1A0940D383E99876 /* noop-file.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-NunchuckDucks.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = NunchuckDucks/NunchuckDucks.entitlements; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "FB_SONARKIT_ENABLED=1", + ); + INFOPLIST_FILE = NunchuckDucks/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = com.jewzydee.gymbit; + PRODUCT_NAME = NunchuckDucks; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-NunchuckDucks.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = NunchuckDucks/NunchuckDucks.entitlements; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = NunchuckDucks/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; + PRODUCT_BUNDLE_IDENTIFIER = com.jewzydee.gymbit; + PRODUCT_NAME = NunchuckDucks; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; + MTL_ENABLE_DEBUG_INFO = NO; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "NunchuckDucks" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "NunchuckDucks" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/ios/NunchuckDucks.xcodeproj/xcshareddata/xcschemes/NunchuckDucks.xcscheme b/ios/NunchuckDucks.xcodeproj/xcshareddata/xcschemes/NunchuckDucks.xcscheme new file mode 100644 index 0000000..7b01acd --- /dev/null +++ b/ios/NunchuckDucks.xcodeproj/xcshareddata/xcschemes/NunchuckDucks.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/NunchuckDucks.xcworkspace/contents.xcworkspacedata b/ios/NunchuckDucks.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..23fb1c9 --- /dev/null +++ b/ios/NunchuckDucks.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/NunchuckDucks/AppDelegate.h b/ios/NunchuckDucks/AppDelegate.h new file mode 100644 index 0000000..f7d2972 --- /dev/null +++ b/ios/NunchuckDucks/AppDelegate.h @@ -0,0 +1,9 @@ +#import +#import +#import + +#import + +@interface AppDelegate : EXAppDelegateWrapper + +@end diff --git a/ios/NunchuckDucks/AppDelegate.mm b/ios/NunchuckDucks/AppDelegate.mm new file mode 100644 index 0000000..a6e13e1 --- /dev/null +++ b/ios/NunchuckDucks/AppDelegate.mm @@ -0,0 +1,166 @@ +#import "AppDelegate.h" + +#import +#import +#import +#import +#import + +#import + +#if RCT_NEW_ARCH_ENABLED +#import +#import +#import +#import +#import +#import + +#import + +static NSString *const kRNConcurrentRoot = @"concurrentRoot"; + +@interface AppDelegate () { + RCTTurboModuleManager *_turboModuleManager; + RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; + std::shared_ptr _reactNativeConfig; + facebook::react::ContextContainer::Shared _contextContainer; +} +@end +#endif + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + RCTAppSetupPrepareApp(application); + + RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions]; + +#if RCT_NEW_ARCH_ENABLED + _contextContainer = std::make_shared(); + _reactNativeConfig = std::make_shared(); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); + _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; + bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; +#endif + + NSDictionary *initProps = [self prepareInitialProps]; + UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:initProps]; + + rootView.backgroundColor = [UIColor whiteColor]; + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [self.reactDelegate createRootViewController]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + + [super application:application didFinishLaunchingWithOptions:launchOptions]; + + return YES; +} + +- (NSArray> *)extraModulesForBridge:(RCTBridge *)bridge +{ + // If you'd like to export some custom RCTBridgeModules, add them here! + return @[]; +} + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + // Switch this bool to turn on and off the concurrent root + return true; +} + +- (NSDictionary *)prepareInitialProps +{ + NSMutableDictionary *initProps = [NSMutableDictionary new]; +#if RCT_NEW_ARCH_ENABLED + initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); +#endif + return initProps; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +// Linking API +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { + return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options]; +} + +// Universal Links +- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler { + BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; + return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result; +} + +// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken +{ + return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; +} + +// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries +- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error +{ + return [super application:application didFailToRegisterForRemoteNotificationsWithError:error]; +} + +// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler +{ + return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; +} + +#if RCT_NEW_ARCH_ENABLED + +#pragma mark - RCTCxxBridgeDelegate + +- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge +{ + _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:bridge.jsCallInvoker]; + return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); +} + +#pragma mark RCTTurboModuleManagerDelegate + +- (Class)getModuleClassFromName:(const char *)name +{ + return RCTCoreModulesClassProvider(name); +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker +{ + return nullptr; +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + initParams: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return nullptr; +} + +- (id)getModuleInstanceFromClass:(Class)moduleClass +{ + return RCTAppSetupDefaultModuleFromClass(moduleClass); +} + +#endif + +@end diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png new file mode 100644 index 0000000..ae59862 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png new file mode 100644 index 0000000..ff9d541 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png new file mode 100644 index 0000000..ba79135 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png new file mode 100644 index 0000000..d2b59a9 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png new file mode 100644 index 0000000..597bdb4 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png new file mode 100644 index 0000000..2f0e2b6 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png new file mode 100644 index 0000000..ff9d541 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png new file mode 100644 index 0000000..3b83139 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png new file mode 100644 index 0000000..6cd063f Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png new file mode 100644 index 0000000..6cd063f Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png new file mode 100644 index 0000000..5239009 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png new file mode 100644 index 0000000..69908ae Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png new file mode 100644 index 0000000..04580c4 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png new file mode 100644 index 0000000..74e8e26 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..f920cb0 --- /dev/null +++ b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images": [ + { + "idiom": "iphone", + "size": "20x20", + "scale": "2x", + "filename": "App-Icon-20x20@2x.png" + }, + { + "idiom": "iphone", + "size": "20x20", + "scale": "3x", + "filename": "App-Icon-20x20@3x.png" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "1x", + "filename": "App-Icon-29x29@1x.png" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "2x", + "filename": "App-Icon-29x29@2x.png" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "3x", + "filename": "App-Icon-29x29@3x.png" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "2x", + "filename": "App-Icon-40x40@2x.png" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "3x", + "filename": "App-Icon-40x40@3x.png" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "2x", + "filename": "App-Icon-60x60@2x.png" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "3x", + "filename": "App-Icon-60x60@3x.png" + }, + { + "idiom": "ipad", + "size": "20x20", + "scale": "1x", + "filename": "App-Icon-20x20@1x.png" + }, + { + "idiom": "ipad", + "size": "20x20", + "scale": "2x", + "filename": "App-Icon-20x20@2x.png" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "1x", + "filename": "App-Icon-29x29@1x.png" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "2x", + "filename": "App-Icon-29x29@2x.png" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "1x", + "filename": "App-Icon-40x40@1x.png" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "2x", + "filename": "App-Icon-40x40@2x.png" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "1x", + "filename": "App-Icon-76x76@1x.png" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "2x", + "filename": "App-Icon-76x76@2x.png" + }, + { + "idiom": "ipad", + "size": "83.5x83.5", + "scale": "2x", + "filename": "App-Icon-83.5x83.5@2x.png" + }, + { + "idiom": "ios-marketing", + "size": "1024x1024", + "scale": "1x", + "filename": "ItunesArtwork@2x.png" + } + ], + "info": { + "version": 1, + "author": "expo" + } +} \ No newline at end of file diff --git a/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png new file mode 100644 index 0000000..2732229 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/Contents.json b/ios/NunchuckDucks/Images.xcassets/Contents.json new file mode 100644 index 0000000..ed285c2 --- /dev/null +++ b/ios/NunchuckDucks/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "expo" + } +} diff --git a/ios/NunchuckDucks/Images.xcassets/SplashScreen.imageset/Contents.json b/ios/NunchuckDucks/Images.xcassets/SplashScreen.imageset/Contents.json new file mode 100644 index 0000000..3cf8489 --- /dev/null +++ b/ios/NunchuckDucks/Images.xcassets/SplashScreen.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images": [ + { + "idiom": "universal", + "filename": "image.png", + "scale": "1x" + }, + { + "idiom": "universal", + "scale": "2x" + }, + { + "idiom": "universal", + "scale": "3x" + } + ], + "info": { + "version": 1, + "author": "expo" + } +} \ No newline at end of file diff --git a/ios/NunchuckDucks/Images.xcassets/SplashScreen.imageset/image.png b/ios/NunchuckDucks/Images.xcassets/SplashScreen.imageset/image.png new file mode 100644 index 0000000..c52c2c6 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/SplashScreen.imageset/image.png differ diff --git a/ios/NunchuckDucks/Images.xcassets/SplashScreenBackground.imageset/Contents.json b/ios/NunchuckDucks/Images.xcassets/SplashScreenBackground.imageset/Contents.json new file mode 100644 index 0000000..3cf8489 --- /dev/null +++ b/ios/NunchuckDucks/Images.xcassets/SplashScreenBackground.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images": [ + { + "idiom": "universal", + "filename": "image.png", + "scale": "1x" + }, + { + "idiom": "universal", + "scale": "2x" + }, + { + "idiom": "universal", + "scale": "3x" + } + ], + "info": { + "version": 1, + "author": "expo" + } +} \ No newline at end of file diff --git a/ios/NunchuckDucks/Images.xcassets/SplashScreenBackground.imageset/image.png b/ios/NunchuckDucks/Images.xcassets/SplashScreenBackground.imageset/image.png new file mode 100644 index 0000000..33ddf20 Binary files /dev/null and b/ios/NunchuckDucks/Images.xcassets/SplashScreenBackground.imageset/image.png differ diff --git a/ios/NunchuckDucks/Info.plist b/ios/NunchuckDucks/Info.plist new file mode 100644 index 0000000..a9c0616 --- /dev/null +++ b/ios/NunchuckDucks/Info.plist @@ -0,0 +1,88 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + NunchuckDucks + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLSchemes + + com.jewzydee.gymbit + + + + CFBundleURLSchemes + + exp+gymbit + + + + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + NSCameraUsageDescription + Allow $(PRODUCT_NAME) to access your camera + NSMicrophoneUsageDescription + Allow $(PRODUCT_NAME) to access your microphone + NSPhotoLibraryUsageDescription + Allow $(PRODUCT_NAME) to access your photos + UILaunchStoryboardName + SplashScreen + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UIStatusBarStyle + UIStatusBarStyleDefault + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIUserInterfaceStyle + Light + UIViewControllerBasedStatusBarAppearance + + + \ No newline at end of file diff --git a/ios/NunchuckDucks/NunchuckDucks.entitlements b/ios/NunchuckDucks/NunchuckDucks.entitlements new file mode 100644 index 0000000..018a6e2 --- /dev/null +++ b/ios/NunchuckDucks/NunchuckDucks.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + \ No newline at end of file diff --git a/ios/NunchuckDucks/SplashScreen.storyboard b/ios/NunchuckDucks/SplashScreen.storyboard new file mode 100644 index 0000000..ed03a52 --- /dev/null +++ b/ios/NunchuckDucks/SplashScreen.storyboard @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/NunchuckDucks/Supporting/Expo.plist b/ios/NunchuckDucks/Supporting/Expo.plist new file mode 100644 index 0000000..6055895 --- /dev/null +++ b/ios/NunchuckDucks/Supporting/Expo.plist @@ -0,0 +1,16 @@ + + + + + EXUpdatesCheckOnLaunch + ALWAYS + EXUpdatesEnabled + + EXUpdatesLaunchWaitMs + 0 + EXUpdatesSDKVersion + 47.0.0 + EXUpdatesURL + https://exp.host/@jewzydee/gymbit + + \ No newline at end of file diff --git a/ios/NunchuckDucks/main.m b/ios/NunchuckDucks/main.m new file mode 100644 index 0000000..25181b6 --- /dev/null +++ b/ios/NunchuckDucks/main.m @@ -0,0 +1,10 @@ +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} + diff --git a/ios/NunchuckDucks/noop-file.swift b/ios/NunchuckDucks/noop-file.swift new file mode 100644 index 0000000..b2ffafb --- /dev/null +++ b/ios/NunchuckDucks/noop-file.swift @@ -0,0 +1,4 @@ +// +// @generated +// A blank Swift file must be created for native modules with Swift files to work correctly. +// diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..6e218c6 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,61 @@ +require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") +require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods") +require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules") + +require 'json' +podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {} + +platform :ios, podfile_properties['ios.deploymentTarget'] || '13.0' +install! 'cocoapods', + :deterministic_uuids => false + +target 'NunchuckDucks' do + use_expo_modules! + config = use_native_modules! + + use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] + + # Flags change depending on the env values. + flags = get_default_flags() + + use_react_native!( + :path => config[:reactNativePath], + :hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes', + :fabric_enabled => flags[:fabric_enabled], + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/..", + # + # Uncomment to opt-in to using Flipper + # Note that if you have use_frameworks! enabled, Flipper will not work + # :flipper_configuration => !ENV['CI'] ? FlipperConfiguration.enabled : FlipperConfiguration.disabled, + ) + + post_install do |installer| + react_native_post_install( + installer, + # Set `mac_catalyst_enabled` to `true` in order to apply patches + # necessary for Mac Catalyst builds + :mac_catalyst_enabled => false + ) + __apply_Xcode_12_5_M1_post_install_workaround(installer) + + # This is necessary for Xcode 14, because it signs resource bundles by default + # when building for devices. + installer.target_installation_results.pod_target_installation_results + .each do |pod_name, target_installation_result| + target_installation_result.resource_bundle_targets.each do |resource_bundle_target| + resource_bundle_target.build_configurations.each do |config| + config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' + end + end + end + end + + post_integrate do |installer| + begin + expo_patch_react_imports!(installer) + rescue => e + Pod::UI.warn e + end + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..8972d4a --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,688 @@ +PODS: + - boost (1.76.0) + - DoubleConversion (1.1.6) + - EXApplication (5.0.1): + - ExpoModulesCore + - EXConstants (14.0.2): + - ExpoModulesCore + - EXFileSystem (15.1.1): + - ExpoModulesCore + - EXFont (11.0.1): + - ExpoModulesCore + - EXImageLoader (4.0.0): + - ExpoModulesCore + - React-Core + - EXJSONUtils (0.4.0) + - EXManifests (0.4.0): + - EXJSONUtils + - Expo (47.0.13): + - ExpoModulesCore + - expo-dev-client (2.0.1): + - EXManifests + - expo-dev-launcher + - expo-dev-menu + - expo-dev-menu-interface + - EXUpdatesInterface + - expo-dev-launcher (2.0.2): + - EXManifests + - expo-dev-launcher/Main (= 2.0.2) + - expo-dev-menu + - expo-dev-menu-interface + - ExpoModulesCore + - EXUpdatesInterface + - React-Core + - expo-dev-launcher/Main (2.0.2): + - EXManifests + - expo-dev-launcher/Unsafe + - expo-dev-menu + - expo-dev-menu-interface + - ExpoModulesCore + - EXUpdatesInterface + - React-Core + - expo-dev-launcher/Unsafe (2.0.2): + - EXManifests + - expo-dev-menu + - expo-dev-menu-interface + - ExpoModulesCore + - EXUpdatesInterface + - React-Core + - expo-dev-menu (2.0.2): + - expo-dev-menu/Main (= 2.0.2) + - expo-dev-menu-interface (1.0.0) + - expo-dev-menu/GestureHandler (2.0.2) + - expo-dev-menu/Main (2.0.2): + - EXManifests + - expo-dev-menu-interface + - expo-dev-menu/Vendored + - ExpoModulesCore + - React-Core + - expo-dev-menu/Reanimated (2.0.2): + - DoubleConversion + - FBLazyVector + - FBReactNativeSpec + - glog + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-callinvoker + - React-Core + - React-Core/DevSupport + - React-Core/RCTWebSocket + - React-CoreModules + - React-cxxreact + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-RCTActionSheet + - React-RCTAnimation + - React-RCTBlob + - React-RCTImage + - React-RCTLinking + - React-RCTNetwork + - React-RCTSettings + - React-RCTText + - React-RCTVibration + - ReactCommon/turbomodule/core + - Yoga + - expo-dev-menu/SafeAreaView (2.0.2) + - expo-dev-menu/Vendored (2.0.2): + - expo-dev-menu/GestureHandler + - expo-dev-menu/Reanimated + - expo-dev-menu/SafeAreaView + - ExpoImagePicker (14.0.3): + - ExpoModulesCore + - ExpoKeepAwake (11.0.1): + - ExpoModulesCore + - ExpoModulesCore (1.1.1): + - React-Core + - ReactCommon/turbomodule/core + - EXSplashScreen (0.17.5): + - ExpoModulesCore + - React-Core + - EXUpdatesInterface (0.8.1) + - FBLazyVector (0.70.5) + - FBReactNativeSpec (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.70.5) + - RCTTypeSafety (= 0.70.5) + - React-Core (= 0.70.5) + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - fmt (6.2.1) + - glog (0.3.5) + - libwebp (1.2.4): + - libwebp/demux (= 1.2.4) + - libwebp/mux (= 1.2.4) + - libwebp/webp (= 1.2.4) + - libwebp/demux (1.2.4): + - libwebp/webp + - libwebp/mux (1.2.4): + - libwebp/demux + - libwebp/webp (1.2.4) + - RCT-Folly (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCTRequired (0.70.5) + - RCTTypeSafety (0.70.5): + - FBLazyVector (= 0.70.5) + - RCTRequired (= 0.70.5) + - React-Core (= 0.70.5) + - React (0.70.5): + - React-Core (= 0.70.5) + - React-Core/DevSupport (= 0.70.5) + - React-Core/RCTWebSocket (= 0.70.5) + - React-RCTActionSheet (= 0.70.5) + - React-RCTAnimation (= 0.70.5) + - React-RCTBlob (= 0.70.5) + - React-RCTImage (= 0.70.5) + - React-RCTLinking (= 0.70.5) + - React-RCTNetwork (= 0.70.5) + - React-RCTSettings (= 0.70.5) + - React-RCTText (= 0.70.5) + - React-RCTVibration (= 0.70.5) + - React-bridging (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - React-jsi (= 0.70.5) + - React-callinvoker (0.70.5) + - React-Codegen (0.70.5): + - FBReactNativeSpec (= 0.70.5) + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.70.5) + - RCTTypeSafety (= 0.70.5) + - React-Core (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-Core (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.70.5) + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/CoreModulesHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/Default (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/DevSupport (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.70.5) + - React-Core/RCTWebSocket (= 0.70.5) + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-jsinspector (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTActionSheetHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTAnimationHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTBlobHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTImageHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTLinkingHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTNetworkHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTSettingsHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTTextHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTVibrationHeaders (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-Core/RCTWebSocket (0.70.5): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.70.5) + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsiexecutor (= 0.70.5) + - React-perflogger (= 0.70.5) + - Yoga + - React-CoreModules (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.5) + - React-Codegen (= 0.70.5) + - React-Core/CoreModulesHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - React-RCTImage (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-cxxreact (0.70.5): + - boost (= 1.76.0) + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.70.5) + - React-jsi (= 0.70.5) + - React-jsinspector (= 0.70.5) + - React-logger (= 0.70.5) + - React-perflogger (= 0.70.5) + - React-runtimeexecutor (= 0.70.5) + - React-jsi (0.70.5): + - boost (= 1.76.0) + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-jsi/Default (= 0.70.5) + - React-jsi/Default (0.70.5): + - boost (= 1.76.0) + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.70.5): + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-perflogger (= 0.70.5) + - React-jsinspector (0.70.5) + - React-logger (0.70.5): + - glog + - react-native-get-random-values (1.8.0): + - React-Core + - react-native-netinfo (9.3.5): + - React-Core + - react-native-pager-view (6.0.1): + - React-Core + - react-native-safe-area-context (4.4.1): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - ReactCommon/turbomodule/core + - React-perflogger (0.70.5) + - React-RCTActionSheet (0.70.5): + - React-Core/RCTActionSheetHeaders (= 0.70.5) + - React-RCTAnimation (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.5) + - React-Codegen (= 0.70.5) + - React-Core/RCTAnimationHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-RCTBlob (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.70.5) + - React-Core/RCTBlobHeaders (= 0.70.5) + - React-Core/RCTWebSocket (= 0.70.5) + - React-jsi (= 0.70.5) + - React-RCTNetwork (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-RCTImage (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.5) + - React-Codegen (= 0.70.5) + - React-Core/RCTImageHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - React-RCTNetwork (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-RCTLinking (0.70.5): + - React-Codegen (= 0.70.5) + - React-Core/RCTLinkingHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-RCTNetwork (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.5) + - React-Codegen (= 0.70.5) + - React-Core/RCTNetworkHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-RCTSettings (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.70.5) + - React-Codegen (= 0.70.5) + - React-Core/RCTSettingsHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-RCTText (0.70.5): + - React-Core/RCTTextHeaders (= 0.70.5) + - React-RCTVibration (0.70.5): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.70.5) + - React-Core/RCTVibrationHeaders (= 0.70.5) + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (= 0.70.5) + - React-runtimeexecutor (0.70.5): + - React-jsi (= 0.70.5) + - ReactCommon/turbomodule/core (0.70.5): + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-bridging (= 0.70.5) + - React-callinvoker (= 0.70.5) + - React-Core (= 0.70.5) + - React-cxxreact (= 0.70.5) + - React-jsi (= 0.70.5) + - React-logger (= 0.70.5) + - React-perflogger (= 0.70.5) + - RNAWSCognito (6.1.2): + - React-Core + - RNCAsyncStorage (1.17.11): + - React-Core + - RNCPicker (2.4.8): + - React-Core + - RNFastImage (8.6.3): + - React-Core + - SDWebImage (~> 5.11.1) + - SDWebImageWebPCoder (~> 0.8.4) + - RNFS (2.20.0): + - React-Core + - RNScreens (3.18.2): + - React-Core + - React-RCTImage + - SDWebImage (5.11.1): + - SDWebImage/Core (= 5.11.1) + - SDWebImage/Core (5.11.1) + - SDWebImageWebPCoder (0.8.5): + - libwebp (~> 1.0) + - SDWebImage/Core (~> 5.10) + - Yoga (1.14.0) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - EXApplication (from `../node_modules/expo-application/ios`) + - EXConstants (from `../node_modules/expo-constants/ios`) + - EXFileSystem (from `../node_modules/expo-file-system/ios`) + - EXFont (from `../node_modules/expo-font/ios`) + - EXImageLoader (from `../node_modules/expo-image-loader/ios`) + - EXJSONUtils (from `../node_modules/expo-json-utils/ios`) + - EXManifests (from `../node_modules/expo-manifests/ios`) + - Expo (from `../node_modules/expo`) + - expo-dev-client (from `../node_modules/expo-dev-client/ios`) + - expo-dev-launcher (from `../node_modules/expo-dev-launcher`) + - expo-dev-menu (from `../node_modules/expo-dev-menu`) + - expo-dev-menu-interface (from `../node_modules/expo-dev-menu-interface/ios`) + - ExpoImagePicker (from `../node_modules/expo-image-picker/ios`) + - ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`) + - ExpoModulesCore (from `../node_modules/expo-modules-core`) + - EXSplashScreen (from `../node_modules/expo-splash-screen/ios`) + - EXUpdatesInterface (from `../node_modules/expo-updates-interface/ios`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-bridging (from `../node_modules/react-native/ReactCommon`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) + - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" + - react-native-pager-view (from `../node_modules/react-native-pager-view`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - RNAWSCognito (from `../node_modules/amazon-cognito-identity-js`) + - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" + - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" + - RNFastImage (from `../node_modules/react-native-fast-image`) + - RNFS (from `../node_modules/react-native-fs`) + - RNScreens (from `../node_modules/react-native-screens`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - fmt + - libwebp + - SDWebImage + - SDWebImageWebPCoder + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + EXApplication: + :path: "../node_modules/expo-application/ios" + EXConstants: + :path: "../node_modules/expo-constants/ios" + EXFileSystem: + :path: "../node_modules/expo-file-system/ios" + EXFont: + :path: "../node_modules/expo-font/ios" + EXImageLoader: + :path: "../node_modules/expo-image-loader/ios" + EXJSONUtils: + :path: "../node_modules/expo-json-utils/ios" + EXManifests: + :path: "../node_modules/expo-manifests/ios" + Expo: + :path: "../node_modules/expo" + expo-dev-client: + :path: "../node_modules/expo-dev-client/ios" + expo-dev-launcher: + :path: "../node_modules/expo-dev-launcher" + expo-dev-menu: + :path: "../node_modules/expo-dev-menu" + expo-dev-menu-interface: + :path: "../node_modules/expo-dev-menu-interface/ios" + ExpoImagePicker: + :path: "../node_modules/expo-image-picker/ios" + ExpoKeepAwake: + :path: "../node_modules/expo-keep-awake/ios" + ExpoModulesCore: + :path: "../node_modules/expo-modules-core" + EXSplashScreen: + :path: "../node_modules/expo-splash-screen/ios" + EXUpdatesInterface: + :path: "../node_modules/expo-updates-interface/ios" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/React/FBReactNativeSpec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-bridging: + :path: "../node_modules/react-native/ReactCommon" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + react-native-get-random-values: + :path: "../node_modules/react-native-get-random-values" + react-native-netinfo: + :path: "../node_modules/@react-native-community/netinfo" + react-native-pager-view: + :path: "../node_modules/react-native-pager-view" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + RNAWSCognito: + :path: "../node_modules/amazon-cognito-identity-js" + RNCAsyncStorage: + :path: "../node_modules/@react-native-async-storage/async-storage" + RNCPicker: + :path: "../node_modules/@react-native-picker/picker" + RNFastImage: + :path: "../node_modules/react-native-fast-image" + RNFS: + :path: "../node_modules/react-native-fs" + RNScreens: + :path: "../node_modules/react-native-screens" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: a7c83b31436843459a1961bfd74b96033dc77234 + DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 + EXApplication: 034b1c40a8e9fe1bff76a1e511ee90dff64ad834 + EXConstants: 3c86653c422dd77e40d10cbbabb3025003977415 + EXFileSystem: 60602b6eefa6873f97172c684b7537c9760b50d6 + EXFont: 319606bfe48c33b5b5063fb0994afdc496befe80 + EXImageLoader: 84b65e6bd9d3345d6fbb3ab936a546c54496a64d + EXJSONUtils: 09aef2c1fba1a116ca8c73a2c8299aac00d96b43 + EXManifests: 347f49430b63444579aa013f0ad057d16b8d1cc8 + Expo: b9fa98bf260992312ee3c424400819fb9beadafe + expo-dev-client: d723d52ccfbe2eb47ee24d1ac0cf5b39001589c2 + expo-dev-launcher: 953f564f7d006f1af50b119cacb48cafcad40c73 + expo-dev-menu: fa9e67b193032700e2908b4737d9d199c0b43c30 + expo-dev-menu-interface: 45581093393dacd51ce5e7f641cf9ed5064a2e3f + ExpoImagePicker: ce37302446e70145bb413f0f74886441abdae022 + ExpoKeepAwake: 69b59d0a8d2b24de9f82759c39b3821fec030318 + ExpoModulesCore: 485dff3a59b036a33b6050c0a5aea3cf1037fdd1 + EXSplashScreen: 3e989924f61a8dd07ee4ea584c6ba14be9b51949 + EXUpdatesInterface: bffd1ead18f0bab04fa784ca159c115607b8a23c + FBLazyVector: affa4ba1bfdaac110a789192f4d452b053a86624 + FBReactNativeSpec: fe8b5f1429cfe83a8d72dc8ed61dc7704cac8745 + fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef + RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda + RCTRequired: 21229f84411088e5d8538f21212de49e46cc83e2 + RCTTypeSafety: 62eed57a32924b09edaaf170a548d1fc96223086 + React: f0254ccddeeef1defe66c6b1bb9133a4f040792b + React-bridging: e46911666b7ec19538a620a221d6396cd293d687 + React-callinvoker: 66b62e2c34546546b2f21ab0b7670346410a2b53 + React-Codegen: b6999435966df3bdf82afa3f319ba0d6f9a8532a + React-Core: dabbc9d1fe0a11d884e6ee1599789cf8eb1058a5 + React-CoreModules: 5b6b7668f156f73a56420df9ec68ca2ec8f2e818 + React-cxxreact: c7ca2baee46db22a30fce9e639277add3c3f6ad1 + React-jsi: a565dcb49130ed20877a9bb1105ffeecbb93d02d + React-jsiexecutor: 31564fa6912459921568e8b0e49024285a4d584b + React-jsinspector: badd81696361249893a80477983e697aab3c1a34 + React-logger: fdda34dd285bdb0232e059b19d9606fa0ec3bb9c + react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a + react-native-netinfo: 85b2a435c4d3705c08b0c42ff2d6ef6b9622ea0a + react-native-pager-view: 3051346698a0ba0c4e13e40097cc11b00ee03cca + react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a + React-perflogger: e68d3795cf5d247a0379735cbac7309adf2fb931 + React-RCTActionSheet: 05452c3b281edb27850253db13ecd4c5a65bc247 + React-RCTAnimation: 578eebac706428e68466118e84aeacf3a282b4da + React-RCTBlob: f47a0aa61e7d1fb1a0e13da832b0da934939d71a + React-RCTImage: 60f54b66eed65d86b6dffaf4733d09161d44929d + React-RCTLinking: 91073205aeec4b29450ca79b709277319368ac9e + React-RCTNetwork: ca91f2c9465a7e335c8a5fae731fd7f10572213b + React-RCTSettings: 1a9a5d01337d55c18168c1abe0f4a589167d134a + React-RCTText: c591e8bd9347a294d8416357ca12d779afec01d5 + React-RCTVibration: 8e5c8c5d17af641f306d7380d8d0fe9b3c142c48 + React-runtimeexecutor: 7401c4a40f8728fd89df4a56104541b760876117 + ReactCommon: c9246996e73bf75a2c6c3ff15f1e16707cdc2da9 + RNAWSCognito: 06ca81fa480fd7f9ff539d01bc41f9d531ff0a19 + RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60 + RNCPicker: 0bf8ef8f7800524f32d2bb2a8bcadd53eda0ecd1 + RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8 + RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 + RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d + SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d + SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d + Yoga: eca980a5771bf114c41a754098cd85e6e0d90ed7 + +PODFILE CHECKSUM: 1abcb7441bca7078fb6ff33d9367ceb191efa7ed + +COCOAPODS: 1.11.3 diff --git a/ios/Podfile.properties.json b/ios/Podfile.properties.json new file mode 100644 index 0000000..f6d872e --- /dev/null +++ b/ios/Podfile.properties.json @@ -0,0 +1,3 @@ +{ + "expo.jsEngine": "jsc" +} diff --git a/package-lock.json b/package-lock.json index 67eccab..6e0071b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,13 +27,15 @@ "expo": "~47.0.12", "expo-dev-client": "~2.0.1", "expo-image-picker": "~14.0.2", - "expo-modules-autolinking": "^0.8.1", + "expo-modules-autolinking": "^1.0.0", "expo-splash-screen": "~0.17.5", "expo-status-bar": "~1.4.2", + "formik": "^2.2.9", "graphql": "^15.8.0", "react": "18.1.0", "react-dom": "18.1.0", "react-native": "0.70.5", + "react-native-fast-image": "^8.6.3", "react-native-fs": "^2.20.0", "react-native-get-random-values": "^1.8.0", "react-native-keyboard-aware-scroll-view": "^0.9.5", @@ -41,6 +43,7 @@ "react-native-safe-area-context": "4.4.1", "react-native-screens": "~3.18.0", "react-native-tab-view": "^3.3.4", + "react-native-toast-message": "^2.1.6", "react-native-url-polyfill": "^1.3.0", "react-navigation": "^4.4.4", "toggle-switch-react-native": "^3.3.0" @@ -18914,9 +18917,9 @@ } }, "node_modules/expo-modules-autolinking": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-0.8.1.tgz", - "integrity": "sha512-S8qfaXCv//7tQWV9M+JKx3CF7ypYhDdSUbkUQdaVO/r8D76/aRTArY/aRw1yEfaAOzyK8C8diDToV1itl51DfQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.1.2.tgz", + "integrity": "sha512-oOlkAccVnHwwR5ccvF/F/x4Omj9HWzSimMUlIVz0SVGdNBEqTPyn0L/d4uIufhyQbEWvrarqL8o5Yz11wEI0SQ==", "dependencies": { "chalk": "^4.1.0", "commander": "^7.2.0", @@ -19752,6 +19755,37 @@ "node": ">= 6" } }, + "node_modules/formik": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", + "integrity": "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==", + "funding": [ + { + "type": "individual", + "url": "https://opencollective.com/formik" + } + ], + "dependencies": { + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^1.10.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/formik/node_modules/deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -23492,6 +23526,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -26304,6 +26343,11 @@ "react": "^18.1.0" } }, + "node_modules/react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, "node_modules/react-freeze": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.3.tgz", @@ -26379,6 +26423,15 @@ "nullthrows": "^1.1.1" } }, + "node_modules/react-native-fast-image": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz", + "integrity": "sha512-Sdw4ESidXCXOmQ9EcYguNY2swyoWmx53kym2zRsvi+VeFCHEdkO+WG1DK+6W81juot40bbfLNhkc63QnWtesNg==", + "peerDependencies": { + "react": "^17 || ^18", + "react-native": ">=0.60.0" + } + }, "node_modules/react-native-fs": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz", @@ -26499,6 +26552,15 @@ "react-native-pager-view": "*" } }, + "node_modules/react-native-toast-message": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.1.6.tgz", + "integrity": "sha512-VctXuq20vmRa9AE13acaNZhrLcS3FaBS2zEevS3+vhBsnVZYG0FIlWIis9tVnpnNxUb3ART+BWtwQjzSttXTng==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-url-polyfill": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.3.0.tgz", @@ -28296,6 +28358,11 @@ "xtend": "~4.0.1" } }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -44696,9 +44763,9 @@ } }, "expo-modules-autolinking": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-0.8.1.tgz", - "integrity": "sha512-S8qfaXCv//7tQWV9M+JKx3CF7ypYhDdSUbkUQdaVO/r8D76/aRTArY/aRw1yEfaAOzyK8C8diDToV1itl51DfQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.1.2.tgz", + "integrity": "sha512-oOlkAccVnHwwR5ccvF/F/x4Omj9HWzSimMUlIVz0SVGdNBEqTPyn0L/d4uIufhyQbEWvrarqL8o5Yz11wEI0SQ==", "requires": { "chalk": "^4.1.0", "commander": "^7.2.0", @@ -45193,6 +45260,27 @@ "mime-types": "^2.1.12" } }, + "formik": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", + "integrity": "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==", + "requires": { + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" + } + } + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -47985,6 +48073,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -50187,6 +50280,11 @@ "scheduler": "^0.22.0" } }, + "react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, "react-freeze": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.3.tgz", @@ -50271,6 +50369,12 @@ "nullthrows": "^1.1.1" } }, + "react-native-fast-image": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz", + "integrity": "sha512-Sdw4ESidXCXOmQ9EcYguNY2swyoWmx53kym2zRsvi+VeFCHEdkO+WG1DK+6W81juot40bbfLNhkc63QnWtesNg==", + "requires": {} + }, "react-native-fs": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz", @@ -50359,6 +50463,12 @@ "use-latest-callback": "^0.1.5" } }, + "react-native-toast-message": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.1.6.tgz", + "integrity": "sha512-VctXuq20vmRa9AE13acaNZhrLcS3FaBS2zEevS3+vhBsnVZYG0FIlWIis9tVnpnNxUb3ART+BWtwQjzSttXTng==", + "requires": {} + }, "react-native-url-polyfill": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.3.0.tgz", @@ -51752,6 +51862,11 @@ "xtend": "~4.0.1" } }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index 23696d4..2b1071d 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,15 @@ "expo": "~47.0.12", "expo-dev-client": "~2.0.1", "expo-image-picker": "~14.0.2", - "expo-modules-autolinking": "^0.8.1", + "expo-modules-autolinking": "^1.0.0", "expo-splash-screen": "~0.17.5", "expo-status-bar": "~1.4.2", + "formik": "^2.2.9", "graphql": "^15.8.0", "react": "18.1.0", "react-dom": "18.1.0", "react-native": "0.70.5", + "react-native-fast-image": "^8.6.3", "react-native-fs": "^2.20.0", "react-native-get-random-values": "^1.8.0", "react-native-keyboard-aware-scroll-view": "^0.9.5", @@ -44,6 +46,7 @@ "react-native-safe-area-context": "4.4.1", "react-native-screens": "~3.18.0", "react-native-tab-view": "^3.3.4", + "react-native-toast-message": "^2.1.6", "react-native-url-polyfill": "^1.3.0", "react-navigation": "^4.4.4", "toggle-switch-react-native": "^3.3.0" diff --git a/src/components/CachedImage/CachedImage.js b/src/components/CachedImage/CachedImage.js new file mode 100644 index 0000000..db28a06 --- /dev/null +++ b/src/components/CachedImage/CachedImage.js @@ -0,0 +1,54 @@ +import { useEffect, useState } from "react"; +import { getUriFromCache, cacheRemoteUri } from "../../crud/CacheOperations"; +import FastImage from "react-native-fast-image"; + +export default function CachedImage({ username, picName, imageStyle, refresh, userPfp = false }) { + const [imageUri, setImageUri] = useState(null); + const [uriIsSet, setUriIsSet] = useState(false); + + async function setImageFromCacheOrAWS() { + /* + if (isPfp) { + console.log("usr", username, "pic", picName); + }*/ + let uriFromCache = await getUriFromCache(username, picName); + /* + if (isPfp) { + console.log(uriFromCache); + }*/ + if (uriFromCache === "") { + uriFromCache = await cacheRemoteUri(username, picName); + } + setImageUri(uriFromCache); + setUriIsSet(true); + } + + useEffect(() => { + /* + if (isPfp) { + console.log("IN CAHCED IMAGE"); + }*/ + setImageFromCacheOrAWS(); + }, [refresh]); + let prioritee = FastImage.priority.normal; + if (userPfp) { + //console.log("Hi"); + // if this is the user's pfp, load it ASAP because I don't want the pfp to be empty for half a second when you swipe to profile screen + // I don't really know if this makes it better at all but it was worth a shot + prioritee = FastImage.priority.high; + } + + return ( + uriIsSet && ( + + ) + ); //; +} diff --git a/src/components/CachedImage/index.js b/src/components/CachedImage/index.js new file mode 100644 index 0000000..2550abc --- /dev/null +++ b/src/components/CachedImage/index.js @@ -0,0 +1 @@ +export { default } from "./CachedImage"; diff --git a/src/components/Comment/Comment.js b/src/components/Comment/Comment.js index eb0e4d7..1a170fb 100644 --- a/src/components/Comment/Comment.js +++ b/src/components/Comment/Comment.js @@ -5,10 +5,7 @@ import ProfileMini from "../ProfileMini"; import { Storage } from "@aws-amplify/storage"; import CustomButton from "../CustomButton/CustomButton"; import CustomTextInput from "../CustomTextInput/CustomTextInput"; -import { - checkForDeletability, - createComment, -} from "../../crud/CommentOperations"; +import { checkForDeletability, createComment } from "../../crud/CommentOperations"; import { getCurrentUser, getImageFromCache } from "../../crud/CacheOperations"; import NonCurrUserProfileModal from "../modals/NonCurrUserProfileModal.js/NonCurrUserProfileModal"; import { getCurrentAuthenticatedUser } from "../../library/GetAuthenticatedUser"; @@ -17,8 +14,7 @@ import ErrorModal from "../modals/ErrorModal/ErrorModal"; const OptionsButton = require("../../../assets/icons/Gymbit_Icons_Black/Three_Dots_Black.png"); -const Comment = ({ commentModel, postID, replies, style }) => { - const [pfp, setPfp] = useState(""); +const Comment = ({ commentModel, postID, replies, style, refresh }) => { const [replyOpen, setReplyOpen] = useState(false); const [replyText, setReplyText] = useState(""); const [repliesOpen, setRepliesOpen] = useState(false); @@ -69,9 +65,9 @@ const Comment = ({ commentModel, postID, replies, style }) => { } else setErrorModalVisible(true); } - useEffect(() => { + /*useEffect(() => { getPic(); - }, []); + }, []);*/ async function onReplySubmit() { setReplyOpen(false); @@ -94,7 +90,6 @@ const Comment = ({ commentModel, postID, replies, style }) => { modalVisible={modalVisible} setModalVisible={setModalVisible} username={commentModel?.username} - image={pfp} > { errorMessage={errorMessage} setExternalModal={setCommentModalVisible} > - setModalVisible(true)} - style={styles.leftSide} - > + setModalVisible(true)} style={styles.leftSide} /> setModalVisible(true)}> {commentModel?.username} - checkIfDeletable(postID, commentModel?.username)} - > + checkIfDeletable(postID, commentModel?.username)}> diff --git a/src/components/Exercise/Exercise.js b/src/components/Exercise/Exercise.js new file mode 100644 index 0000000..d9f8ea5 --- /dev/null +++ b/src/components/Exercise/Exercise.js @@ -0,0 +1,42 @@ +import { View, Text, StyleSheet } from "react-native"; +import { blueThemeColor } from "../../library/constants"; +export default function Exercise(exercise, index) { + const name = exercise.exercise.exerciseName; + const notes = exercise.exercise.exerciseNotes; + return ( + + + {name} + + + {notes} + + + ); +} +const styles = StyleSheet.create({ + exerciseNameContainer: { + height: 30, + }, + exerciseName: { + color: blueThemeColor, + fontSize: 20, + fontWeight: "bold", + marginTop: 2, + marginLeft: 10, + //textAlign: "center", + //borderBottomWidth: 3, + }, + exerciseContainer: { + //flex: 1, + //minHeight: 100, + flexDirection: "column", + //backgroundColor: "#202124", + //alignItems: "center", + //alignSelf: "center", + width: "80%", + }, + exerciseNotes: { + marginLeft: 20, + }, +}); diff --git a/src/components/Exercise/index.js b/src/components/Exercise/index.js new file mode 100644 index 0000000..f095277 --- /dev/null +++ b/src/components/Exercise/index.js @@ -0,0 +1 @@ +export { default } from "./Exercise"; diff --git a/src/components/FollowerMini/FollowerMini.js b/src/components/FollowerMini/FollowerMini.js index 53c389f..8a3608a 100644 --- a/src/components/FollowerMini/FollowerMini.js +++ b/src/components/FollowerMini/FollowerMini.js @@ -38,12 +38,13 @@ const FollowerMini = ({ username, onProfileClick, onDelete, style }) => { return ( + modalVisible={modalVisible} + setModalVisible={setModalVisible} + username={username} + image={userImageSrc} + > - setModalVisible(true)}> + setModalVisible(true)} /> setModalVisible(true)} style={styles.usernameContainer}> @{username} diff --git a/src/components/HomeHeader/HomeHeader.js b/src/components/HomeHeader/HomeHeader.js index 625a156..235b46e 100644 --- a/src/components/HomeHeader/HomeHeader.js +++ b/src/components/HomeHeader/HomeHeader.js @@ -6,9 +6,11 @@ import { Touchable, Text, TextInput, + ScrollView, Pressable, + ActivityIndicator, } from "react-native"; -import React from "react"; +import React, { useRef } from "react"; import { useNavigation } from "@react-navigation/native"; import { useState, useEffect } from "react"; import { Storage } from "@aws-amplify/storage"; @@ -19,21 +21,34 @@ import getPictureFileName from "../../library/getPictureFileName"; import { createPost } from "../../crud/PostOperations"; import ImageSelector from "../../components/ImageSelector"; import { DataStore } from "@aws-amplify/datastore"; -import { getNotifications } from "../../crud/NotificationOperations"; import { getCurrentUser } from "../../crud/CacheOperations"; -import { blueThemeColor } from "../../library/constants"; +import { getWorkouts } from "../../crud/WorkoutOperations"; +import { blueThemeColor, grayThemeColor } from "../../library/constants"; +import { useNetInfo } from "@react-native-community/netinfo"; +import { Toast } from "react-native-toast-message/lib/src/Toast"; +import CustomButton from "../CustomButton/CustomButton"; +import CreateWorkoutModal from "../modals/CreateWorkoutModal"; +import { getNotifications } from "../../crud/NotificationOperations"; +import WorkoutSelection from "../WorkoutSelection"; +import FastImage from "react-native-fast-image"; /** * Creates the header that will go above the two home screens (Mutual and Explore) */ -const HomeHeader = ({ handlePress }) => { +const HomeHeader = ({ handlePress, refresh, setRefresh }) => { const navigation = useNavigation(); - const [refresh, setRefresh] = useState(true); + //const [refresh, setRefresh] = useState(true); const [blowup, setBlowup] = useState(false); const [text, setText] = useState(""); // the caption you write - const [workoutSelection, setWorkoutSelection] = useState([]); // array of workouts you selected + const [workoutSelection, setWorkoutSelection] = useState(null); // array of workouts you selected const [image, setImage] = useState(null); const [notificationCount, setNotificationCount] = useState(0); + const networkConnection = useNetInfo(); + const [createPostTouched, setCreatePostTouched] = useState(false); + const [showCreateWorkout, setShowCreateWorkout] = useState(false); + const [refreshWorkout, setRefreshWorkout] = useState(false); + const [scrollToBottom, setScrollToBottom] = useState(false); + const [showUploading, setShowUploading] = useState(false); Storage.configure(); const imageSRC = require("../../../assets/icons/Gymbit_Icons_Black/Back_Icon_Black.png"); @@ -51,32 +66,90 @@ const HomeHeader = ({ handlePress }) => { setNotificationCount(notifications.length); } + const handleCreatePostBlowUp = () => { + if (networkConnection.isConnected) { + setBlowup(!blowup); + } else { + setCreatePostTouched(!createPostTouched); + } + }; + useEffect(() => { findNotificationCount(); - }), - [navigation]; + }, [navigation]); + const showPostUploadedToast = () => { + Toast.show({ + type: "success", + text1: "Successfully uploaded your new post!", + //text2: "Go check it out on your mutuals page 🔥", + position: "bottom", + visibilityTime: 6000, + bottomOffset: 80, + }); + }; + const showPostNotUploadedToast = (usr) => { + if (usr === "") { + usr = "friend"; + } + Toast.show({ + type: "error", + text1: "Uh oh, there was trouble uploading your post...", + text2: "Try again later. Sorry, " + usr + " 😔", + position: "bottom", + visibilityTime: 6000, + bottomOffset: 80, + }); + }; + const showNetworkNotConnectedToast = () => { + Toast.show({ + type: "error", + text1: "No network connection detected.", + text2: "Can't create a post.", + position: "bottom", + visibilityTime: 4000, + bottomOffset: 80, + }); + }; async function savePost() { - await DataStore.start(); + setShowUploading(true); + //await DataStore.start(); + let username = await getCurrentUser(); try { // try catch just in case sending the image doesn't work - const { attributes } = await Auth.currentAuthenticatedUser(); - let username = attributes.preferred_username; + //const { attributes } = await getCurrentUser(); var fileName = username + "/" + getPictureFileName(); + await createPost(text, fileName, username, workoutSelection); + handleBlowUp(); + Toast.show({ + type: "info", + text1: "Your new post is loading!", + text2: "It'll show up soon 😄", + position: "bottom", + visibilityTime: 3000, + bottomOffset: 80, + }); const response = await fetch(image); const blob = await response.blob(); - await createPost(text, fileName, username); - Storage.put(fileName, blob); - setImage(null); + await Storage.put(fileName, blob); + setShowUploading(false); setText(""); - setWorkoutSelection([]); - } catch { - console.error("Error uploading file"); - // TODO make a UI popup thing that lets the user know that their post wasn't uploaded (please try again later) + setWorkoutSelection(null); + setImage(null); + showPostUploadedToast(); + } catch (error) { + showPostNotUploadedToast(username); + console.error("Error uploading file", error); } - handleBlowUp(); + setRefresh(!refresh); } + useEffect(() => { + if (networkConnection.isConnected === false) { + showNetworkNotConnectedToast(); + } + }, [createPostTouched]); + return ( <> @@ -87,29 +160,32 @@ const HomeHeader = ({ handlePress }) => { }} > {notificationCount} - + - + - - + + - {blowup ? ( + {blowup && ( + + {showCreateWorkout && ( + + )} @@ -120,84 +196,38 @@ const HomeHeader = ({ handlePress }) => { - - {workoutSelection.join(", ")} - - Post Gymbit - + + {showUploading ? ( + + ) : ( + + Post Gymbit + + )} - ) : ( - )} ); }; -function WorkoutSelection(props) { - const workoutSelection = props.workoutSelection; - const setWorkoutSelection = props.setWorkoutSelection; - const updateFunction = (text) => { - setWorkoutSelection([...new Set([...workoutSelection, text])]); - }; - return ( - - - - What did you do today? - - - - updateFunction("Run")} - style={styles.workoutSelection} - > - Run - - updateFunction("Leg Day")} - style={styles.workoutSelection} - > - Leg Day - - updateFunction("Back and Biceps")} - style={styles.workoutSelection} - > - Back and Biceps - - updateFunction("Chest and Triceps")} - style={styles.workoutSelection} - > - Chest and Triceps - - updateFunction("Bike")} - style={styles.workoutSelection} - > - Bike - - {workoutSelection.join(", ")} - - - ); -} - const styles = StyleSheet.create({ + header: { + //height: "10%", + }, container: { width: "100%", - height: 90, + height: 100, + //alignItems: "center", paddingTop: 38, backgroundColor: "white", flexDirection: "row", @@ -277,35 +307,17 @@ const styles = StyleSheet.create({ fontSize: 18, }, - workoutSelectionContainer: { - borderWidth: 3, - borderLeftWidth: 0, - alignItems: "center", - flex: 1, - }, - - what: { - backgroundColor: "#2E8CFF", - height: 40, - alignItems: "center", - justifyContent: "center", - width: "100%", - }, - - workoutSelection: { - flex: 1, - width: "100%", - }, backArrow: { width: 60, height: 60, paddingBottom: 50, alignSelf: "flex-start", paddingLeft: 10, - backgroundColor: "rgba(200,212,225,0.75)", + //backgroundColor: "rgba(200,212,225,0.75)", }, counter: { borderRadius: 100, + color: "#FFFFFF", backgroundColor: blueThemeColor, width: 20, textAlign: "center", diff --git a/src/components/ImageSelector/ImageSelector.js b/src/components/ImageSelector/ImageSelector.js index f1c3654..c1ca257 100644 --- a/src/components/ImageSelector/ImageSelector.js +++ b/src/components/ImageSelector/ImageSelector.js @@ -1,4 +1,4 @@ -import { View, Image, TouchableOpacity, Text, StyleSheet } from "react-native"; +import { View, Image, TouchableOpacity, Text, StyleSheet, Pressable } from "react-native"; import { AntDesign } from "@expo/vector-icons"; import * as ImagePicker from "expo-image-picker"; @@ -26,6 +26,16 @@ const styles = StyleSheet.create({ alignItems: "center", justifyContent: "center", }, + transparentView: { + flex: 1, + position: "absolute", + left: 0, + top: 0, + width: "100%", + height: "100%", + backgroundColor: "rgba(52, 52, 52, 0.8)", + zIndex: -1, + }, }); /** * @@ -35,10 +45,12 @@ const styles = StyleSheet.create({ export default function ImageSelector(props) { const image = props.image; const setImage = props.setImage; + function chooseCameraOrUpload() { + ; + } const addImage = async () => { let _image = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: - ImagePicker.MediaTypeOptions.Images /*Only allow image upload */, + mediaTypes: ImagePicker.MediaTypeOptions.Images /*Only allow image upload */, allowsEditing: true /*true= pull up an editing interface after image upload */, aspect: [1, 1] /*1:1 image ratio, so it will be a square */, quality: 1 /*highest quality image possible, on a scale of 0-1 we want 1 lol */, @@ -47,9 +59,7 @@ export default function ImageSelector(props) { }; return ( - {image && ( - - )} + {image && } {image ? "Edit" : "Upload"} Image diff --git a/src/components/Post/Post.js b/src/components/Post/Post.js index a264cf7..9207ebd 100644 --- a/src/components/Post/Post.js +++ b/src/components/Post/Post.js @@ -1,37 +1,30 @@ -import { - View, - Image, - Text, - StyleSheet, - Pressable, - TouchableOpacity, -} from "react-native"; +import { View, Image, Text, StyleSheet, Pressable, TouchableOpacity, ActivityIndicator } from "react-native"; import { useState, useEffect } from "react"; import { Storage } from "@aws-amplify/storage"; import Reactions from "../Reactions"; import { blueThemeColor, grayThemeColor } from "../../library/constants"; import ProfileMini from "../ProfileMini"; import { useNavigation } from "@react-navigation/native"; -import { - cacheImageFromAWS, - getCurrentUser, - getImageFromCache, -} from "../../crud/CacheOperations"; +import { getCurrentUser } from "../../crud/CacheOperations"; import { useNetInfo } from "@react-native-community/netinfo"; import NonCurrUserProfileModal from "../modals/NonCurrUserProfileModal.js/NonCurrUserProfileModal"; import Comment from "../Comment"; import { createComment, getComments } from "../../crud/CommentOperations"; import CustomButton from "../CustomButton/CustomButton"; import CustomTextInput from "../CustomTextInput/CustomTextInput"; -import { getCurrentAuthenticatedUser } from "../../library/GetAuthenticatedUser"; +import CachedImage from "../CachedImage/CachedImage"; +import Workout from "../Workout/Workout"; +import { getWorkoutById } from "../../crud/WorkoutOperations"; import { getAndObserveComments } from "../../crud/observeQueries/CommentObserveQueries"; - +import { getUriFromCache, cacheRemoteUri } from "../../crud/CacheOperations"; +import FastImage from "react-native-fast-image"; export default function Post(props) { const entry = props.entry; const username = entry.username; const refresh = props.refresh; const photoStr = entry.photo; + const workoutId = entry.postWorkoutId; const picName = photoStr.substring(photoStr.indexOf("/") + 1); const [picture, setPicture] = useState(null); const [pfp, setPfp] = useState(""); @@ -45,59 +38,19 @@ export default function Post(props) { const [shortCommentDisplay, setShortCommentDisplay] = useState(true); const [showCommentOption, setCommentOption] = useState(false); const [commentText, setCommentText] = useState(""); + const [hasWorkout, setHasWorkout] = useState(false); + const [workout, setWorkout] = useState(null); + const [uriIsSet, setUriIsSet] = useState(false); + const [imageUri, setImageUri] = useState(null); const handleBlowUp = () => { setBlowup(!blowup); }; let commentList = comments.map((val) => { - return ( - - ); + return ; }); - async function getPictures() { - // TODO retrieve post picture from the passed entry fileName - //const postPfp = await getImageFromCache(username, "pfp.png"); // console logs pic "pfp.png found for user x..." - const postPfp = entry.cachedPfp; - - if (postPfp !== "") { - setPfp(postPfp); - } - //const pic = entry.cachedPostPicture; - const pic = await getImageFromCache(username, picName); - if (pic !== "") { - setPicture(pic); - } else if (entry.shouldBeCached === true) { - console.log("Pic not in cache but it should be", entry.caption); - let picCached = await cacheImageFromAWS(username, picName); - //let picha = await Storage.get(photoStr); - setPicture(picCached); - } else { - console.log( - "Pic", - picName, - "for", - username, - "must be acquired using Storage.get" - ); - try { - let picFromAWS = await Storage.get(photoStr); - setPicture(picFromAWS); - } catch (e) { - console.log( - "Storage.get failed; connection unavailable to render", - picName - ); - } - } - } - async function onCommentSubmit() { setCommentOption(false); // Call CRUD to make new datastore object @@ -121,7 +74,7 @@ export default function Post(props) { async function handleUserClick(username) { try { - if (username === await getCurrentAuthenticatedUser()) { + if (username === (await getCurrentUser())) { navigation.navigate("Profile"); } else { setModalVisible(true); @@ -132,7 +85,7 @@ export default function Post(props) { } useEffect(() => { - getPictures(); + setImageFromCacheOrAWS(); const subscription = retrieveComments(); return () => { if (subscription && subscription.unsubscribe) subscription.unsubscribe(); @@ -155,17 +108,38 @@ export default function Post(props) { setReplies(replyMap); }, [allComments]); + useEffect(() => { + getWorkoutForPost(); + }, []); + + async function setImageFromCacheOrAWS() { + let uriFromCache = await getUriFromCache(username, picName); + if (uriFromCache === "") { + uriFromCache = await cacheRemoteUri(username, picName); + } + setImageUri(uriFromCache); + setUriIsSet(true); + } + + async function getWorkoutForPost() { + if (workoutId !== undefined && workoutId !== null) { + let workout = await getWorkoutById(workoutId); + setWorkout(workout); + setHasWorkout(true); + } + } return ( setModalVisible(true)} @@ -176,34 +150,29 @@ export default function Post(props) { {getTimeElapsed(entry.createdAt)} - - - {blowup && ( - - - Today's Workout - - - - {entry.caption} - + + {uriIsSet ? ( + + ) : ( + + )} + {blowup && hasWorkout && } {/*replace get time elapsed w/ actual on click utility*/} {/* Need to implement caption box as intended*/} {entry.caption} - + {showCommentOption && ( )} - {showCommentOption && ( - - )} + {showCommentOption && } {shortCommentDisplay ? commentList.slice(0, 2) : commentList} {comments.length > 2 && ( { + Toast.show({ + type: "success", + text1: "Welcome to GymBit!", + text2: "We're glad you're here 😁💪", + position: "bottom", + visibilityTime: 4000, + bottomOffset: 80, + }); + }; + + const showOnlineToast = (usr) => { + Toast.show({ + type: "success", + text1: "You are now online!", + text2: "Welcome back, " + usr + " 😁💪", + position: "bottom", + visibilityTime: 4000, + bottomOffset: 80, + }); + }; + const showWelcomeBackToast = (usr) => { + Toast.show({ + type: "success", + text1: "Welcome back, " + usr + " 💪", + //text2: "We're glad you're here 😁💪", + position: "bottom", + visibilityTime: 4000, + bottomOffset: 80, + }); + }; + + const delay = (ms) => new Promise((res) => setTimeout(res, ms)); + + const showNotConnectedToast = async () => { + setOfflineInitialCompleted(true); + Toast.show({ + type: "info", + text1: "You're not connected to the internet 😬", + position: "bottom", + visibilityTime: 3000, + bottomOffset: 80, + }); + await delay(4000); + Toast.show({ + type: "info", + text1: "You can still look around 👀", + text2: "And also create goals 💪", + position: "bottom", + visibilityTime: 3000, + bottomOffset: 80, + }); + }; + + async function offlineOperations() { + await fetchPostCache(); + } useEffect(() => { + setSwipeRefresh(true); // First thing done upon startup of the app if (postsInitialCompleted === false) { - fetchPostCache(); // will set postsInitialCompleted to true after completion + offlineOperations(); // will set postsInitialCompleted to true after completion } - if ( - networkConnection.isConnected === true && - postsInitialCompleted === true - ) { + if (networkConnection.isConnected) { //list.current.scrollToIndex({ index: 0 }); - cacheStuffFromAWS(); - } else { - // in case there is no conneciton, a swipe refresh should end with nothing happening + doOnlineOperations(); + } else if (postsInitialCompleted) { + // in case there is no connection, a swipe refresh should end with nothing happening // need to test when using app with no connection setSwipeRefresh(false); + if (offlineInitialCompleted === false) { + showNotConnectedToast(); + } } - console.log("PostList refreshed"); + //console.log("PostList refreshed"); }, [refresh, networkConnection]); return ( - } - refreshing={swipeRefresh} - onRefresh={() => { - setSwipeRefresh(true); - setRefresh(!refresh); - }} - keyExtractor={(item) => item.id} - /> + <> + } + extraData={refresh} + refreshing={swipeRefresh} + onRefresh={() => { + setRefresh(!refresh); + }} + keyExtractor={(item) => item.id} + /> + ); } diff --git a/src/components/ProfileMini/ProfileMini.js b/src/components/ProfileMini/ProfileMini.js index 9df02d9..8b87f2a 100644 --- a/src/components/ProfileMini/ProfileMini.js +++ b/src/components/ProfileMini/ProfileMini.js @@ -1,26 +1,42 @@ import { Image, StyleSheet, Pressable } from "react-native"; +import { useEffect, useState } from "react"; +import CachedImage from "../CachedImage/CachedImage"; +import { getUriFromCache, cacheRemoteUri } from "../../crud/CacheOperations"; +import FastImage from "react-native-fast-image"; const defaultProfile = require("../../../assets/icons/Gymbit_Icons_Black/Profile_Icon.png"); -const ProfileMini = ({ style, src, onClick, imageStyle }) => { +const ProfileMini = ({ style, onClick, imageStyle, username }) => { let containerStyles = { ...styles.container, ...style }; let imageStyles = { ...styles.image, ...imageStyle }; + let picName = "pfp.png"; + const [imageUri, setImageUri] = useState(null); + const [uriIsSet, setUriIsSet] = useState(false); + async function setImageFromCacheOrAWS() { + let uriFromCache = await getUriFromCache(username, picName); + if (uriFromCache === "") { + uriFromCache = await cacheRemoteUri(username, picName); + } + setImageUri(uriFromCache); + setUriIsSet(true); + } + useEffect(() => { + setImageFromCacheOrAWS(); + }); return ( - - {src && ( - + {uriIsSet && ( + + style={imageStyles} + resizeMode={FastImage.resizeMode.cover} + /> )} ); diff --git a/src/components/SuggestedFollower/SuggestedFollower.js b/src/components/SuggestedFollower/SuggestedFollower.js index ce924ba..23ad394 100644 --- a/src/components/SuggestedFollower/SuggestedFollower.js +++ b/src/components/SuggestedFollower/SuggestedFollower.js @@ -1,11 +1,4 @@ -import { - View, - Modal, - StyleSheet, - Pressable, - Text, - ScrollView, -} from "react-native"; +import { View, Modal, StyleSheet, Pressable, Text, ScrollView } from "react-native"; import React, { useState, useEffect } from "react"; import CustomButton from "../CustomButton"; @@ -14,34 +7,13 @@ import { blueThemeColor } from "../../library/constants"; import { getImageFromCache } from "../../crud/CacheOperations"; const SuggestedFollower = ({ username, addNewFollower }) => { - const [pfp, setPfp] = useState(""); - - useEffect(() => { - async function getPic() { - try { - let pfps3 = await getImageFromCache(username, "pfp.png"); - if (pfps3 === "") { - pfps3 = await Storage.get(username + "/pfp.png"); - } - setPfp(pfps3); - } catch (error) { - console.log("Error retrieving pfp in comment: " + error); - } - } - getPic(); - }, []); - return ( - + {username} - + ); }; diff --git a/src/components/Workout/Workout.js b/src/components/Workout/Workout.js new file mode 100644 index 0000000..18ba2c4 --- /dev/null +++ b/src/components/Workout/Workout.js @@ -0,0 +1,94 @@ +import { View, ScrollView, Text, StyleSheet } from "react-native"; +import { blueThemeColor } from "../../library/constants"; +import Exercise from "../Exercise/Exercise"; +export default function Workout({ workout, isAbsolute = false }) { + if (Array.isArray(workout) && workout.length > 0) { + workout = workout[0]; + } + let JsonWorkout = workout; + try { + JsonWorkout = JSON.parse(JsonWorkout); + } catch { + JsonWorkout = workout; + } + let JsonExercises = JsonWorkout.exercises; + try { + JsonExercises = JSON.parse(JsonExercises); + } catch { + JsonExercises = JsonWorkout.exercises; + } + let workoutName = JsonWorkout.workoutName; + return ( + + + {workoutName} + + + {JsonExercises.map((exercise, index) => ( + + ))} + + + ); +} +const styles = StyleSheet.create({ + blowupmain: { + width: "100%", + height: 400, + //position: this. + //height: 400, + //marginTop: 20, + //position: "absolute", + //right: 0, + backgroundColor: "rgba(200,212,225,0.7)", + borderRightWidth: 0, + borderLeftWidth: 0, + borderWidth: 2, + borderTopWidth: 3, + borderRightColor: "black", + marginBottom: 20, + }, + blowupmainAbsolute: { + width: "100%", + height: 400, + position: "absolute", + //height: 400, + //marginTop: 20, + //position: "absolute", + //right: 0, + backgroundColor: "rgba(200,212,225,0.7)", + borderRightWidth: 0, + borderLeftWidth: 0, + borderWidth: 2, + borderTopWidth: 3, + borderRightColor: "black", + marginBottom: 20, + }, + blowupheader: { + height: 50, + marginBottom: 10, + borderColor: "black", + color: blueThemeColor, + fontSize: 50, + fontWeight: "bold", + marginTop: 2, + textAlign: "center", + alignItems: "center", + borderBottomWidth: 3, + }, + blowupbody: { + fontSize: 21, + textAlign: "left", + paddingLeft: 20, + marginTop: 5, + }, + workoutName: { + color: blueThemeColor, + fontSize: 30, + fontWeight: "bold", + marginTop: 2, + marginLeft: 10, + //textAlign: "center", + //borderBottomWidth: 3, + }, +}); diff --git a/src/components/Workout/index.js b/src/components/Workout/index.js new file mode 100644 index 0000000..8187410 --- /dev/null +++ b/src/components/Workout/index.js @@ -0,0 +1 @@ +export { default } from "./Workout"; diff --git a/src/components/WorkoutSelection/WorkoutSelection.js b/src/components/WorkoutSelection/WorkoutSelection.js new file mode 100644 index 0000000..3ff6931 --- /dev/null +++ b/src/components/WorkoutSelection/WorkoutSelection.js @@ -0,0 +1,111 @@ +import { View, TouchableOpacity, StyleSheet, Text, ScrollView } from "react-native"; +import React, { useRef } from "react"; +import { useState, useEffect } from "react"; +import { getCurrentUser } from "../../crud/CacheOperations"; +import { getWorkouts } from "../../crud/WorkoutOperations"; +import { blueThemeColor } from "../../library/constants"; + +export default function WorkoutSelection({ + workoutSelection, + setWorkoutSelection, + refreshWorkout, + setShowCreateWorkout, + scrollToBottom, + setScrollToBottom, +}) { + const scrollviewRef = useRef(); + useEffect(() => { + getWorkoutList(); + + doStuff(); + }, [refreshWorkout]); + const [workouts, setWorkouts] = useState([]); + async function getWorkoutList() { + let username = await getCurrentUser(); + let workouts = await getWorkouts(username); + setWorkouts(workouts); + } + async function doStuff() { + if (scrollToBottom === true) { + //ScrollView.scrollToEnd + //setWorkoutSelection(workouts[workouts.length - 1]); + setWorkoutSelection(workouts[workouts.length - 1]); + scrollviewRef.current.scrollToEnd(); + setScrollToBottom(false); + } + } + function handleWorkoutSelectionPress(workout) { + setWorkoutSelection(workout); + } + function handleSelectedWorkoutPress() { + setWorkoutSelection(null); + } + return ( + + + What workout did you do today? + + + setShowCreateWorkout(true)} style={styles.workoutSelection}> + Create new workout + + {workouts.map((workout, index) => { + return ( + + {workout === workoutSelection ? ( + //console.log("THEY EQUAL EACH OTHER", workout); + // This will console.log successfully after creating a new workout, but won't return this. Will figure out later. + handleSelectedWorkoutPress(workout)} style={styles.workoutSelectionHighlighted}> + {workout.workoutName} + + ) : ( + handleWorkoutSelectionPress(workout)} style={styles.workoutSelection}> + {workout.workoutName} + + )} + + ); + })} + + + ); +} + +const styles = StyleSheet.create({ + workoutSelectionContainer: { + borderWidth: 3, + borderLeftWidth: 0, + alignItems: "center", + flex: 1, + }, + workoutMainContainer: { + alignItems: "center", + + width: "100%", + }, + + what: { + backgroundColor: "#2E8CFF", + height: 40, + alignItems: "center", + justifyContent: "center", + width: "100%", + }, + + workoutSelection: { + height: 50, + width: "100%", + alignItems: "center", + justifyContent: "center", + borderBottomWidth: 3, + }, + workoutSelectionHighlighted: { + backgroundColor: blueThemeColor, + //overlayColor: blueThemeColor, + height: 50, + width: "100%", + alignItems: "center", + justifyContent: "center", + borderBottomWidth: 3, + }, +}); diff --git a/src/components/WorkoutSelection/index.js b/src/components/WorkoutSelection/index.js new file mode 100644 index 0000000..b09f269 --- /dev/null +++ b/src/components/WorkoutSelection/index.js @@ -0,0 +1 @@ +export { default } from "./WorkoutSelection"; diff --git a/src/components/modals/AddFollowerModal/AddFollowerModal.js b/src/components/modals/AddFollowerModal/AddFollowerModal.js index 317de26..3559a37 100644 --- a/src/components/modals/AddFollowerModal/AddFollowerModal.js +++ b/src/components/modals/AddFollowerModal/AddFollowerModal.js @@ -1,11 +1,4 @@ -import { - View, - Modal, - StyleSheet, - Pressable, - Text, - ScrollView, -} from "react-native"; +import { View, Modal, StyleSheet, Pressable, Text, ScrollView } from "react-native"; import React, { useState, useEffect } from "react"; import { createFollower } from "../../../crud/FollowersOperations"; @@ -23,11 +16,7 @@ const AddFollowerModal = ({ modalVisible, setModalVisible }) => { const [suggestedUsers, setSuggestedUsers] = useState([]); const renderedSuggestedUsers = suggestedUsers.map((suggestedUser) => ( - + )); async function addNewFollower(desiredFollowValue) { @@ -77,17 +66,9 @@ const AddFollowerModal = ({ modalVisible, setModalVisible }) => { }, [addFriendValue]); return ( - - + closeModal}> + { style={{ width: "35%" }} > - {suggestedUsers.length === 0 && ( - No Suggested Users - )} + {suggestedUsers.length === 0 && No Suggested Users} {suggestedUsers.length !== 0 && ( - + {renderedSuggestedUsers} )} diff --git a/src/components/modals/CreateWorkoutModal/CreateWorkoutModal.js b/src/components/modals/CreateWorkoutModal/CreateWorkoutModal.js new file mode 100644 index 0000000..3b22145 --- /dev/null +++ b/src/components/modals/CreateWorkoutModal/CreateWorkoutModal.js @@ -0,0 +1,223 @@ +import { useEffect, useState } from "react"; +import { View, Image, Text, StyleSheet, Pressable, TouchableOpacity, Modal, TextInput, Button, ScrollView } from "react-native"; +import CustomButton from "../../CustomButton"; +import { Formik, Field, Form, ErrorMessage, FieldArray } from "formik"; +import { blueThemeColor, grayThemeColor } from "../../../library/constants"; +import { Toast } from "react-native-toast-message/lib/src/Toast"; +import { getCurrentUser } from "../../../crud/CacheOperations"; +import { createWorkout } from "../../../crud/WorkoutOperations"; +import Exercise from "../../Exercise/Exercise"; +export default function CreateWorkoutModal({ + modalVisible, + setModalVisible, + refreshWorkouts, + setRefreshWorkouts, + scrollToBottom = null, + setScrollToBottom = null, + setWorkoutSelection = null, +}) { + //const modalVisible = props.modalVisible; + //const setModalVisible = props.setModalVisible; + const [workoutTitle, setWorkoutTitle] = useState(""); + //const [setsList, addToSetsList] = useState([]); + const [exerciseList, setExerciseList] = useState([]); + const [exerciseName, setExerciseName] = useState(""); + const [exerciseNotes, setExerciseNotes] = useState(""); + const [buttonShown, setButtonShown] = useState(true); + const [addNewExercise, setAddNewExercise] = useState(false); + const [exerciseNameNotSet, setExerciseNameNotSet] = useState(false); + const closeModal = () => { + setModalVisible(false); + }; + + function handleButtonPress() { + setAddNewExercise(true); + setButtonShown(false); + } + function handleConfirmPress() { + if (exerciseName.length === 0) { + Toast.show({ + type: "error", + text1: "Please name the exercise!", + position: "bottom", + visibilityTime: 3000, + bottomOffset: 80, + }); + } else { + let exercise = { + exerciseName: exerciseName, + exerciseNotes: exerciseNotes, + }; + + setExerciseList([...new Set([...exerciseList, exercise])]); + setExerciseName(""); + setExerciseNotes(""); + setButtonShown(true); + setAddNewExercise(false); + } + } + async function createNewWorkout() { + let currUser = await getCurrentUser(); + let newWorkout = await createWorkout(currUser, workoutTitle, exerciseList); + if (scrollToBottom !== null) { + setScrollToBottom(true); + } + setWorkoutTitle(""); + setExerciseList([]); + setRefreshWorkouts(!refreshWorkouts); + setModalVisible(false); + } + + return ( + setModalVisible(false)}> + + + + + + + + {exerciseList.map((exercise, index) => ( + + ))} + {/*- Hello*/} + {addNewExercise && ( + + + + + + + + + + {exerciseName !== "" && exerciseNotes !== "" && ( + + )} + + )} + {buttonShown && } + + + {exerciseList.length > 0 && workoutTitle !== "" && ( + + )} + + + ); +} + +const styles = StyleSheet.create({ + exerciseNotes: { + marginLeft: 20, + }, + addExerciseContainer: { + //flex: 1, + minHeight: 100, + flexDirection: "column", + //backgroundColor: "#202124", + borderTopWidth: 5, + borderLeftWidth: 5, + borderRightWidth: 5, + borderBottomWidth: 5, + //alignItems: "center", + marginTop: 10, + alignSelf: "center", + width: "80%", + }, + exerciseContainer: { + //flex: 1, + //minHeight: 100, + flexDirection: "column", + //backgroundColor: "#202124", + //alignItems: "center", + //alignSelf: "center", + width: "80%", + }, + addExerciseNameContainer: { + // flexDirection: "row", + height: 30, + //marginBottom: 20, + //borderColor: "black", + //textAlign: "center", + borderBottomWidth: 3, + }, + exerciseNameContainer: { + height: 40, + }, + workoutName: { + textAlign: "center", + color: blueThemeColor, + fontSize: 30, + fontWeight: "bold", + marginTop: 2, + marginLeft: 10, + width: "100%", + //textAlign: "center", + //borderBottomWidth: 3, + }, + exerciseName: { + color: blueThemeColor, + fontSize: 20, + fontWeight: "bold", + marginTop: 2, + marginLeft: 10, + //textAlign: "center", + //borderBottomWidth: 3, + }, + centeredView: { + flex: 1, + //top: "50%", + justifyContent: "center", + alignItems: "center", + }, + transparentView: { + flex: 1, + position: "absolute", + left: 0, + top: 0, + width: "100%", + height: "100%", + backgroundColor: "rgba(52, 52, 52, 0.8)", + zIndex: -1, + }, + blowupmain: { + width: "100%", + height: 400, + //position: "absolute", + //height: 400, + //marginTop: 20, + //position: "absolute", + //right: 0, + backgroundColor: "rgba(200,212,225,0.7)", + borderRightWidth: 0, + borderLeftWidth: 0, + borderWidth: 2, + borderTopWidth: 3, + borderRightColor: "black", + //marginBottom: 20, + }, + blowupheader: { + height: 50, + marginBottom: 10, + borderColor: "black", + color: blueThemeColor, + fontSize: 50, + fontWeight: "bold", + width: "100%", + marginTop: 2, + textAlign: "center", + alignItems: "center", + borderBottomWidth: 3, + }, + blowupbody: { + fontSize: 21, + textAlign: "left", + paddingLeft: 20, + marginTop: 5, + }, +}); diff --git a/src/components/modals/CreateWorkoutModal/index.js b/src/components/modals/CreateWorkoutModal/index.js new file mode 100644 index 0000000..321d07d --- /dev/null +++ b/src/components/modals/CreateWorkoutModal/index.js @@ -0,0 +1 @@ +export { default } from "./CreateWorkoutModal"; diff --git a/src/components/modals/NonCurrUserProfileModal.js/NonCurrUserProfileModal.js b/src/components/modals/NonCurrUserProfileModal.js/NonCurrUserProfileModal.js index 4f47175..282666b 100644 --- a/src/components/modals/NonCurrUserProfileModal.js/NonCurrUserProfileModal.js +++ b/src/components/modals/NonCurrUserProfileModal.js/NonCurrUserProfileModal.js @@ -8,12 +8,7 @@ import { getFollowersList } from "../../../crud/FollowersOperations"; const imageSRC = require("../../../../assets/icons/Gymbit_Icons_Black/Back_Icon_Black.png"); -const NonCurrUserProfileModal = ({ - modalVisible, - setModalVisible, - username, - image, -}) => { +const NonCurrUserProfileModal = ({ modalVisible, setModalVisible, username, image }) => { const [user, setUser] = useState(""); const [followingCount, setFollowingCount] = useState(""); const [followersCount, setFollowersCount] = useState(""); @@ -50,12 +45,7 @@ const NonCurrUserProfileModal = ({ } return ( - + - - - @{user.username !== null ? user.username : ""} - - - - - Following - {followingCount} - - - Followers - {followersCount} + + @{username !== null ? username : ""} + + + Following + {followingCount} + + + Followers + {followersCount} + Bio @@ -124,8 +114,8 @@ const styles = StyleSheet.create({ height: 80, backgroundColor: "white", paddingBottom: 50, + alignSelf: "flex-start", paddingLeft: 10, - alignSelf: "flex-start" }, username: { paddingTop: 30, @@ -133,7 +123,7 @@ const styles = StyleSheet.create({ paddingLeft: 15, fontSize: 20, fontWeight: "bold", - color: "#2E8CFF" + color: "#2E8CFF", }, followercount: { fontSize: 20, @@ -164,7 +154,7 @@ const styles = StyleSheet.create({ minHeight: "auto", flexDirection: "column", alignItems: "center", - alignSelf: "flex-start" + alignSelf: "flex-start", }, followingText: { fontSize: 11, @@ -173,7 +163,7 @@ const styles = StyleSheet.create({ followingNumber: { fontSize: 20, fontWeight: "bold", - paddingTop: 10 + paddingTop: 10, }, bioText: { fontSize: 16, diff --git a/src/components/signoutbutton/SignOutButton.js b/src/components/signoutbutton/SignOutButton.js index 292d1a0..c737edf 100644 --- a/src/components/signoutbutton/SignOutButton.js +++ b/src/components/signoutbutton/SignOutButton.js @@ -9,6 +9,7 @@ import { } from "react-native"; import { Auth, Amplify, DataStore } from "aws-amplify"; import { deleteAllCache } from "../../crud/CacheOperations"; +import FastImage from "react-native-fast-image"; const SignOutButton = () => { const signOut = async () => { @@ -26,6 +27,8 @@ const SignOutButton = () => { }; async function signOutOps() { await deleteAllCache(); + await FastImage.clearDiskCache(); + await FastImage.clearMemoryCache(); signOut(); } diff --git a/src/crud/CacheOperations.js b/src/crud/CacheOperations.js index a6dacb2..d679904 100644 --- a/src/crud/CacheOperations.js +++ b/src/crud/CacheOperations.js @@ -5,10 +5,6 @@ import { getCurrentAuthenticatedUser } from "../library/GetAuthenticatedUser"; const cacheDirectory = FileSystem.cacheDirectory; -export async function logCache() { - let files = await getAllCachedFiles(); - console.log(files); -} export async function deleteCachedFile(file) { try { const cachedFile = cacheDirectory + file; @@ -72,17 +68,10 @@ export async function getCurrentUser() { return username; } catch (e) { console.log("Error: Could not retrieve username from cache nor from S3"); + return ""; } } -export async function getCacheLastModifiedUri(username, ending) { - return cacheDirectory + username + ending + "lastModified.txt"; -} - -export async function getCacheImageFileUri(username, ending) { - return cacheDirectory + username + ending; -} - export async function cacheLastModified(username, lastModifiedMessage) { const cacheLastModifiedUri = cacheDirectory + username + "pfplastModified.txt"; try { @@ -94,6 +83,32 @@ export async function cacheLastModified(username, lastModifiedMessage) { } } +export async function cacheRemoteUri(username, fileName) { + const cacheLastModifiedUri = cacheDirectory + username + fileName + "Uri.txt"; + let remoteUri = await Storage.get(username + "/" + fileName); + try { + let cachedRemoteUri = await FileSystem.writeAsStringAsync(cacheLastModifiedUri, remoteUri, { + encoding: "utf8", + }); + return remoteUri; + } catch (error) { + console.log("Error: Could not cache pfp uri", error); + return ""; + } +} +export async function getUriFromCache(username, fileName) { + const cacheLastModifiedUri = cacheDirectory + username + fileName + "Uri.txt"; + try { + let blah = await FileSystem.readAsStringAsync(cacheLastModifiedUri, { + encoding: "utf8", + }); + return blah; + } catch (error) { + console.log("Error: Could not get uri from cache", error); + return ""; + } +} + export async function getLastModifiedCache(username, ending) { const cacheLastModifiedUri = cacheDirectory + username + ending + "lastModified.txt"; try { @@ -102,7 +117,8 @@ export async function getLastModifiedCache(username, ending) { }); return lastModified; } catch (e) { - console.log("Could not find lasttModified for", username); + console.log("Could not find lastModified for", username); + return ""; } } @@ -126,7 +142,7 @@ export async function getCachedCurrUser() { return cachedUserString; } catch (e) { console.log("Error: Could not read who the current user is from cache", e); - return null; + return ""; } } @@ -153,36 +169,6 @@ export async function cachePosts(posts) { } } -export async function getLastModifiedAWS(username, file) { - let lastModified = null; - const myInit = { - queryStringParameters: { - username: username, // OPTIONAL - file: file, - }, - }; - await API.get("getLastModified", "/getLastModified", myInit) - .then((response) => { - lastModified = response; - }) - .catch((error) => { - console.log("Error: could not get last modified using API call" + error.response); - }); - return lastModified; -} - -export async function cachePostsThatShouldBeCached(posts) { - const cachedPostsUri = cacheDirectory + "postsCached.txt"; - try { - let postsString = posts.toString(); - let po = await FileSystem.writeAsStringAsync(cachedPostsUri, postsString, { - encoding: "utf8", - }); - } catch (error) { - console.log("Error: Could not cache posts that should be cached (for old cache deletion)"); - } -} - export async function getPostsThatShouldBeCached() { try { const cachedPostsUri = cacheDirectory + "postsCached.txt"; @@ -251,7 +237,33 @@ export async function getImageFromCache(username, ending) { } } -export async function cacheImageFromAWS(username, ending, addPng = false) { +export async function getImageFromAWS(username, ending) { + try { + const uriAWS = await Storage.get(username + "/" + ending); + return uriAWS; + } catch (e) { + console.log("Error: could not get image", ending, "for", username, "from aws", e); + return null; + } +} + +export async function cacheUriForImageFromAWS(username, ending) { + try { + const uriAWS = await Storage.get(username + "/" + ending); + const cacheFile = cacheDirectory + username + ending + "uri.txt"; + await cacheImage(uriAWS, cacheFile); + return uriAWS; + } catch (e) { + console.log("Error: could not get image", ending, "for", username, "from aws", e); + return null; + } +} + +export async function movePfpToCache(oldUri, username) { + const pfpCache = cacheDirectory + username + "pfp.png"; +} + +export async function cacheImageFromAWS(username, ending) { const uriAWS = await Storage.get(username + "/" + ending); //console.log(uriAWS); let cacheImageFileUri = cacheDirectory + username + ending; @@ -269,37 +281,16 @@ export async function cacheImageFromAWS(username, ending, addPng = false) { } export async function saveImageToAWS(fileName, blob) { - await Storage.put(fileName, blob); + try { + await Storage.put(fileName, blob); + return true; + } catch (e) { + console.log("Error: Failed to upload image", fileName, "to AWS"); + return false; + } } export async function updatePfpCache(username) { - const cachedImage = await getImageFromCache(username, "pfp.png"); - // we are assuming that if the image exists in client then it should exist in the backend as well - if (cachedImage !== "") { - const lastModifiedAWS = await getLastModifiedAWS(username, "pfp.png"); - const lastModifiedCache = await getLastModifiedCache(username, "pfp"); - if (lastModifiedCache !== null) { - if (lastModifiedAWS > lastModifiedCache) { - //lastModifiedAWS has a higher alphabetical order (newer) than lastModifiedCache - await cacheImageFromAWS(username, "pfp.png"); - await cacheLastModified(username, lastModifiedAWS); - } else if (lastModifiedCache < lastModifiedAWS) { - let fileName = username + "/pfp.png"; - saveImageToAWS(fileName, getCacheImageFileUri(username, "pfp.png")); - } else { - } - } else { - await cacheImageFromAWS(username, "pfp.png"); - await cacheLastModified(username, lastModifiedAWS); - } - } else { - console.log("Profile pic for", username, "not found in cache; checking if it is in the backend"); - const lastModifiedAWS = await getLastModifiedAWS(username, "pfp.png"); - if (lastModifiedAWS === "None" || lastModifiedAWS === null) { - return false; - } else { - let imageFromAWS = await cacheImageFromAWS(username, "pfp.png"); - await cacheLastModified(username, lastModifiedAWS); - } - } + let remoteUriAWS = await cacheRemoteUri(username, "pfp.png"); + return remoteUriAWS; } diff --git a/src/crud/GoalOperations.js b/src/crud/GoalOperations.js index a519e2e..f687571 100644 --- a/src/crud/GoalOperations.js +++ b/src/crud/GoalOperations.js @@ -56,8 +56,8 @@ export async function deleteGoal(goalID) { try { const goalToDelete = await DataStore.query(Goal, goalID); await DataStore.delete(goalToDelete); - console.log(`Successfully delete goal ${goalToDelete.id}`); + console.log(`Successfully deleted goal ${goalToDelete.id}`); } catch (error) { - console.error("Error saving goal", error); + console.error("Error deleting goal", error); } } diff --git a/src/crud/PostOperations.js b/src/crud/PostOperations.js index e9e07a0..5ee9d22 100644 --- a/src/crud/PostOperations.js +++ b/src/crud/PostOperations.js @@ -4,6 +4,7 @@ import { getCurrentUser } from "./CacheOperations"; import { DataStore, SortDirection } from "aws-amplify"; import { Post, Follows, User } from "../models"; import { getUserId } from "./UserOperations"; +import { getCurrentAuthenticatedUser } from "../library/GetAuthenticatedUser"; /** * Creates a post and saves the new post in the backend * @param {String} username @@ -11,20 +12,31 @@ import { getUserId } from "./UserOperations"; * @param {Image} profilePicture * @param {String} bio */ -export async function createPost(caption, photo, username) { +export async function createPost(caption, photo, username, workout) { try { const user = await getCurrentUser(); const userId = await getUserId(user); - - await DataStore.save( - new Post({ - caption: caption, - photo: photo, - username: username, - userID: userId, - }) - ); + if (workout === null) { + await DataStore.save( + new Post({ + caption: caption, + photo: photo, + username: username, + userID: userId, + }) + ); + } else { + await DataStore.save( + new Post({ + caption: caption, + photo: photo, + username: username, + userID: userId, + Workout: workout, + }) + ); + } console.log(`Post successfully created.`); } catch (error) { console.error("Error saving post", error); @@ -64,11 +76,21 @@ export async function getUsersFollowed(username) { export async function getPostsForMutualFeedFromAWS(username) { try { - const userId = await getUserId(username); - + setTimeout(() => (loop = false), 10000); + let loop = true; + let userId; + // TODO: Remove workaround + console.log("MY USERNAME::: ", username); + while (loop) { + userId = await getUserId(username); + console.log("IDIDIDID: ", userId); + + if (userId) loop = false; + } const usersFollowed = await DataStore.query(Follows, (uf) => uf.username.eq(username)); + console.log("USERS FOLLOWED"); + usersFollowed.forEach((val) => console.log(val)); const usersFollowedIDs = [userId]; - console.log(`Retrieved users followed for ${username}`); for (let i = 0; i < usersFollowed.length; i++) { @@ -82,8 +104,7 @@ export async function getPostsForMutualFeedFromAWS(username) { sort: (s) => s.createdAt(SortDirection.DESCENDING), }); for (let j = 0; j < postsToBeAdded.length; j++) { - if (dateIsInPast3Days(postsToBeAdded[j])) - posts.push(postsToBeAdded[j]); + if (dateIsInPast3Days(postsToBeAdded[j])) posts.push(postsToBeAdded[j]); } } @@ -108,20 +129,16 @@ export async function getPostsForMutualFeedFromAWS(username) { } function dateIsInPast3Days(post) { - const createdAt = post.createdAt; const difference = getTime(createdAt); - if (difference >= 3) - return false; - else - return true; - - } + if (difference >= 3) return false; + else return true; +} - function getTime(createdAt) { - var ans = ""; // the output +function getTime(createdAt) { + var ans = ""; // the output if (createdAt == undefined) { // Checks that createdAt exists // Will not exist when DataStore is not connected to remote @@ -136,19 +153,16 @@ function dateIsInPast3Days(post) { var minutesDifference = diff / (1000 * 60); var hoursDifference = Math.floor(minutesDifference / 60); var daysDifference = Math.floor(hoursDifference / 24); - - return Math.floor(daysDifference); - } - +} export async function getUserByPostId(postId) { - const post = await DataStore.query(Post, postId); - return post.username; + const post = await DataStore.query(Post, postId); + return post.username; } export async function getCreatedAt(postId) { const post = await DataStore.query(Post, postId); return String(post.createdAt); -} \ No newline at end of file +} diff --git a/src/crud/ReactionOperations.js b/src/crud/ReactionOperations.js index 9b44a99..345bb8e 100644 --- a/src/crud/ReactionOperations.js +++ b/src/crud/ReactionOperations.js @@ -8,7 +8,6 @@ import { getTimeElapsed } from "../library/getTimeElapsed"; export async function createReaction(username, reactionType, postID) { try { - console.log("POSTID: ", postID); const reaction = new Reaction({ postID: postID, username: username, @@ -23,9 +22,7 @@ export async function createReaction(username, reactionType, postID) { let time = getTimeElapsed(createdAt); let content = username + " reacted to your post from " + time; - if (postsUsername !== username) - await createNotification(postsUsername, date, content, username); - + if (postsUsername !== username) await createNotification(postsUsername, date, content, username); } catch (error) { console.error(`There was an error creating a reaction.`, error); } @@ -34,11 +31,7 @@ export async function createReaction(username, reactionType, postID) { export async function removeReaction(username, reactionType, postID) { try { const reactionToDelete = await DataStore.query(Reaction, (r) => - r.and((r) => [ - r.username.eq(username), - r.reactionType.eq(reactionType), - r.postID.eq(postID), - ]) + r.and((r) => [r.username.eq(username), r.reactionType.eq(reactionType), r.postID.eq(postID)]) ); if (reactionToDelete.length === 0) return; await DataStore.delete(reactionToDelete[0]); @@ -51,9 +44,7 @@ export async function removeReaction(username, reactionType, postID) { export async function getReactions(postID) { try { - const reactionList = await DataStore.query(Reaction, (r) => - r.postID.eq(postID) - ); + const reactionList = await DataStore.query(Reaction, (r) => r.postID.eq(postID)); return reactionList; } catch (error) { console.error("There was an error retrieving reaction list.", error); @@ -63,11 +54,7 @@ export async function getReactions(postID) { export async function getUserReactions(postID, username, reactionType) { try { const reactions = await DataStore.query(Reaction, (r) => - r.and((r) => [ - r.username.eq(username), - r.reactionType.eq(reactionType), - r.postID.eq(postID), - ]) + r.and((r) => [r.username.eq(username), r.reactionType.eq(reactionType), r.postID.eq(postID)]) ); return reactions; } catch (error) { diff --git a/src/crud/UserOperations.js b/src/crud/UserOperations.js index 62b9030..61ca3d6 100644 --- a/src/crud/UserOperations.js +++ b/src/crud/UserOperations.js @@ -2,6 +2,7 @@ import { DataStore, SortDirection } from "aws-amplify"; import { Post, User } from "../models"; import { Storage } from "aws-amplify"; import { getCurrentUser } from "./CacheOperations"; +import { ConsoleLogger } from "@aws-amplify/core"; /** * Creates a user and saves the new user in the backend @@ -190,9 +191,7 @@ export async function doesUserExist(username) { export async function doesUserExistLower(lowerUsername) { try { - const user = await DataStore.query(User, (u) => - u.lowerUsername.eq(lowerUsername) - ); + const user = await DataStore.query(User, (u) => u.lowerUsername.eq(lowerUsername)); if (user[0] === undefined) console.log(`This user does not exist.`); @@ -204,9 +203,7 @@ export async function doesUserExistLower(lowerUsername) { export async function getUserIdByLowerUsername(lowerUsername) { try { - const user = await DataStore.query(User, (u) => - u.lowerUsername.eq(lowerUsername) - ); + const user = await DataStore.query(User, (u) => u.lowerUsername.eq(lowerUsername)); if (!user || !user.length) return ""; console.log(`Successfully found actual username for ${lowerUsername}`); @@ -246,9 +243,7 @@ export async function togglePrivacy(username, privacy) { }) ); - console.log( - `Successfully changed ${username}'s privacy status to ${privacy}` - ); + console.log(`Successfully changed ${username}'s privacy status to ${privacy}`); } catch (error) { console.error(`Error changing ${username}'s privacy status to ${privacy}`); } @@ -261,9 +256,7 @@ export async function togglePrivacy(username, privacy) { */ export async function getUsersbyStartofUsername(username) { try { - const users = await DataStore.query(User, (u) => - u.username.beginsWith(username) - ); + const users = await DataStore.query(User, (u) => u.username.beginsWith(username)); return users; } catch (error) { console.error(`Error getting users by start of username.`, error); @@ -332,13 +325,9 @@ export async function getUsersPostTimes(username) { const posts = []; - const postList = await DataStore.query( - Post, - (p) => p.username.eq(username), - { - sort: (s) => s.createdAt(SortDirection.DESCENDING), - } - ); + const postList = await DataStore.query(Post, (p) => p.username.eq(username), { + sort: (s) => s.createdAt(SortDirection.DESCENDING), + }); for (let i = 0; i < postList.length; i++) { posts.push(postList[i].createdAt); @@ -419,19 +408,9 @@ export async function setLowerUsername(username) { const original = await DataStore.query(User, userId); - if ( - original.lowerUsername === null || - original.lowerUsername === undefined - ) { - await DataStore.save( - User.copyOf( - original, - (updated) => (updated.lowerUsername = lowerUsername) - ) - ); - console.log( - `Successfully set lowercase username of ${username} to ${lowerUsername}` - ); + if (original.lowerUsername === null || original.lowerUsername === undefined) { + await DataStore.save(User.copyOf(original, (updated) => (updated.lowerUsername = lowerUsername))); + console.log(`Successfully set lowercase username of ${username} to ${lowerUsername}`); } else { console.log("Lowercase username already set"); } diff --git a/src/crud/WorkoutOperations.js b/src/crud/WorkoutOperations.js new file mode 100644 index 0000000..7389ca1 --- /dev/null +++ b/src/crud/WorkoutOperations.js @@ -0,0 +1,58 @@ +import { DataStore } from "aws-amplify"; +import { Workout } from "../models"; +import { getUserId } from "./UserOperations"; + +export async function createWorkout(username, workoutName, exercises) { + try { + const userId = await getUserId(username); + let exercisesString = JSON.stringify(exercises); + const workout = new Workout({ + username: username, + workoutName: workoutName, + exercises: exercisesString, + userID: userId, + }); + await DataStore.save(workout); + console.log(`Workout ${workout.id} successfully created.`); + return workout; + } catch (error) { + console.error("Error saving workout", error); + return ""; + } +} + +export async function getWorkoutById(workoutId) { + try { + let workout = await DataStore.query(Workout, (w) => w.id.eq(workoutId)); + return workout; + } catch (e) { + console.error("Error retrieving the workout for the user", e); + } +} + +/** + * Returns all goals for any given user + * @param {String} username + * @returns goals + */ +export async function getWorkouts(username) { + try { + const userId = await getUserId(username); + const workouts = await DataStore.query(Workout, (w) => w.username.eq(username)); + console.log(`Successfully retrieved workouts for ${username}`); + + return workouts; + } catch (error) { + console.error(`Error retrieving workouts for ${username}`); + } +} + +export async function deleteWorkout(workoutId) { + try { + const workoutToDelete = await DataStore.query(Workout, workoutId); + await DataStore.delete(workoutToDelete); + console.log(`Successfully deleted workout ${workoutToDelete.id}`); + } catch (error) { + console.error("Error deleting workout", error); + } +} diff --git a/src/screens/CreatePost.js b/src/screens/CreatePost.js index caa24aa..94a1174 100644 --- a/src/screens/CreatePost.js +++ b/src/screens/CreatePost.js @@ -8,6 +8,10 @@ import { Auth } from "aws-amplify"; import { useNavigation } from "@react-navigation/native"; import getPictureFileName from "../library/getPictureFileName"; import { createPost } from "../crud/PostOperations"; +import { Toast } from "react-native-toast-message/lib/src/Toast"; +import { getCurrentUser } from "../crud/CacheOperations"; +import { getWorkouts } from "../crud/WorkoutOperations"; +import { blueThemeColor } from "../library/constants"; const styles = StyleSheet.create({ header: { @@ -59,60 +63,96 @@ export function CreatePost() { const navigation = useNavigation(); //const [username, setUsername] = useState("usernameNotFound"); Storage.configure(); // protected = you can write and read your posts, others can only read + + const showPostUploadedToast = () => { + Toast.show({ + type: "success", + text1: "Successfully uploaded your new post!", + text2: "Go check it out on your mutuals page 🔥", + position: "bottom", + visibilityTime: 6000, + }); + }; + const showPostNotUploadedToast = (usr) => { + // username; pass username as prop to all shits? + if (usr === "") { + usr = "friend"; + } + Toast.show({ + type: "error", + text1: "Uh oh, there was trouble uploading your post...", + text2: "Try again later. Sorry, " + usr + " 😔", + position: "bottom", + visibilityTime: 6000, + }); + }; async function savePost() { - await DataStore.start(); + //await DataStore.start(); + let username = await getCurrentUser(); try { // try catch just in case sending the image doesn't work - const { attributes } = await Auth.currentAuthenticatedUser(); - let username = attributes.preferred_username; + //const { attributes } = await getCurrentUser(); var fileName = username + "/" + getPictureFileName(); const response = await fetch(image); const blob = await response.blob(); await createPost(text, fileName, username); - Storage.put(fileName, blob); + await Storage.put(fileName, blob); + showPostUploadedToast(); } catch (error) { + showPostNotUploadedToast(username); console.error("Error uploading file", error); // TODO make a UI popup thing that lets the user know that their post wasn't uploaded (please try again later) } navigation.navigate("Mutuals"); } return ( - - - - - - - - - {workoutSelection.join(", ")} - - Post Gymbit - + <> + + + + + + + + + {workoutSelection.join(", ")} + + Post Gymbit + + - + ); } function WorkoutSelection(props) { + const [workouts, setWorkouts] = useState([]); + async function getWorkoutList() { + let username = await getCurrentUser(); + let workouts = await getWorkouts(username); + setWorkouts(workouts); + } + getWorkoutList(); const workoutSelection = props.workoutSelection; const setWorkoutSelection = props.setWorkoutSelection; - const updateFunction = (text) => { - setWorkoutSelection([...new Set([...workoutSelection, text])]); - }; return ( - What did you do today? + What workout did you do today? - updateFunction("Run")} style={styles.workoutSelection}> + {workouts.map((workout) => ( + setWorkoutSelection(workout)} style={styles.workoutSelection}> + {workout.workoutName} + + ))} + {/* updateFunction("Run")} style={styles.workoutSelection}> Run updateFunction("Leg Day")} style={styles.workoutSelection}> Leg Day - updateFunction("Back and Biceps")} style={styles.workoutSelection}> + updateFunction("Bacccccccck and Biceps")} style={styles.workoutSelection}> Back and Biceps updateFunction("Chest and Triceps")} style={styles.workoutSelection}> @@ -122,6 +162,7 @@ function WorkoutSelection(props) { Bike {workoutSelection.join(", ")} + */} ); diff --git a/src/screens/MutualScreen.js b/src/screens/MutualScreen.js index 4f979a3..f3288da 100644 --- a/src/screens/MutualScreen.js +++ b/src/screens/MutualScreen.js @@ -1,4 +1,4 @@ -import { View, Text} from "react-native"; +import { View, Text } from "react-native"; import { useState, useEffect } from "react"; import { useNavigation } from "@react-navigation/native"; import PostList from "../components/PostList"; @@ -6,8 +6,11 @@ import HomeHeader from "../components/HomeHeader/HomeHeader"; import { setLowerUsername } from "../crud/UserOperations"; import { getCurrentUser } from "../crud/CacheOperations"; -export function MutualScreen() { - const [refresh, setRefresh] = useState(true); +export function MutualScreen(props) { + //const [refresh, setRefresh] = useState(false); + const refresh = props.refresh; + const setRefresh = props.setRefresh; + const nav = useNavigation(); useEffect(() => { @@ -22,11 +25,12 @@ export function MutualScreen() { // await setLowerUsername(username); // } return ( - - - setRefresh(!refresh)} /> - - - + + setRefresh(!refresh)} /> + + ); } diff --git a/src/screens/ProfileScreen.js b/src/screens/ProfileScreen.js index 4ea494c..567596c 100644 --- a/src/screens/ProfileScreen.js +++ b/src/screens/ProfileScreen.js @@ -5,23 +5,8 @@ import { blueThemeColor, grayThemeColor } from "../library/constants"; import React from "react"; import { getFollowsList } from "../crud/FollowingOperations"; import { getFollowersList } from "../crud/FollowersOperations"; -import { - getBio, - updateCurrentStreak, - updateProfilePicture, - getWeeklyGoal, -} from "../crud/UserOperations"; -import { findUserByUsername } from "../crud/UserOperations"; -import { - getLastModifiedCache, - getLastModifiedAWS, - cacheLastModified, - getImageFromCache, - cacheImageFromAWS, - saveImageToAWS, - getCachedCurrUser, - getCurrentUser, -} from "../crud/CacheOperations"; +import { getBio, updateCurrentStreak, getWeeklyGoal } from "../crud/UserOperations"; +import { saveImageToAWS, getCurrentUser, cacheRemoteUri } from "../crud/CacheOperations"; import ProfileMini from "../components/ProfileMini"; import Bio from "../components/Bio"; import CustomButton from "../components/CustomButton"; @@ -34,39 +19,83 @@ import * as FileSystem from "expo-file-system"; import "react-native-url-polyfill/auto"; import "react-native-get-random-values"; import Header from "../components/Header"; +import { getCurrentAuthenticatedUser } from "../library/GetAuthenticatedUser"; +import { Toast } from "react-native-toast-message/lib/src/Toast"; +import { useNetInfo } from "@react-native-community/netinfo"; //Need to also create the buttons to be clickable and call different functions export function ProfileScreen(props) { const navigation = useNavigation(); + //const [refresh, setRefresh] = useState(false); + //const { refresh, setRefresh } = route.params; + const networkConnection = useNetInfo(); + const refresh = props.refresh; + const setRefresh = props.setRefresh; + const [usernameSet, setUsernameSet] = useState(false); const [username, setUsername] = useState(""); - const [followercount, setFollowerCount] = useState(""); - const [followingcount, setFollowingCount] = useState(""); + const [followercount, setFollowerCount] = useState(0); + const [followingcount, setFollowingCount] = useState(0); const [modalVisible, setModalVisible] = useState(false); const [showMakePfp, setShowMakePfp] = useState(false); - const [profilePic, setProfilePic] = useState(""); const [reload, setReload] = useState(false); const [streak, setStreak] = useState(0); const [showStreak, setShowStreak] = useState(false); + const [showPfpUploaded, setShowPfpUploaded] = useState(false); useEffect(() => { renderProfileInfo(); - getFollowersCount(username); - getFollowingCount(username); - }, [modalVisible, navigation]); + if (username !== "") { + getFollowersCount(username); + getFollowingCount(username); + } + }, [modalVisible, username]); + + const showPfpUploadedToast = (usr) => { + Toast.show({ + type: "success", + text1: "Successfully stored your new pfp!", + text2: "Lookin' good, " + usr + " 😎", + position: "bottom", + visibilityTime: 6000, + bottomOffset: 80, + }); + }; + const showPfpNotUploadedToast = (usr) => { + if (usr === "") { + usr = "friend"; + } + Toast.show({ + type: "error", + text1: "Oops, there was an issue uploading your new pfp...", + text2: "Try again later. Sorry, " + usr + " 😔", + position: "bottom", + visibilityTime: 6000, + bottomOffset: 80, + }); + }; + + const showPfpCantChangeToast = () => { + Toast.show({ + type: "error", + text1: "No Network connection detected.", + text2: "Can't change profile picture.", + position: "bottom", + visibilityTime: 4000, + bottomOffset: 80, + }); + }; async function renderProfileInfo() { let username = await getCurrentUser(); setUsername(username); - const cachedImage = await getImageFromCache(username, "pfp.png"); - setProfilePic(cachedImage); - let currStreak = await updateCurrentStreak(username); + /*let currStreak = await updateCurrentStreak(username); setStreak(currStreak); - console.log(streak); if (streak > 0) { setShowStreak(true); } else { setShowStreak(false); - } + }*/ + setUsernameSet(true); } async function getFollowingCount(username) { @@ -79,10 +108,16 @@ export function ProfileScreen(props) { setFollowerCount(followersList.length); } + function handleProfileImageClick() { + if (networkConnection.isConnected) { + addProfileImage(); + } else { + showPfpCantChangeToast(); + } + } const addProfileImage = async () => { let _image = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: - ImagePicker.MediaTypeOptions.Images /*Only allow image upload */, + mediaTypes: ImagePicker.MediaTypeOptions.Images /*Only allow image upload */, allowsEditing: true /*true= pull up an editing interface after image upload */, aspect: [1, 1] /*1:1 image ratio, so it will be a square */, quality: 1 /*highest quality image possible, on a scale of 0-1 we want 1 lol */, @@ -93,19 +128,18 @@ export function ProfileScreen(props) { const response = await fetch(_image.uri); const blob = await response.blob(); const fileName = username + "/pfp.png"; - //updateProfilePicture(username, fileName); - await saveImageToAWS(fileName, blob); - let lastModified = await getLastModifiedAWS(username, "pfp.png"); - cacheLastModified(username, lastModified); - let path = await cacheImageFromAWS(username, "pfp.png"); - if (path !== "") { - setProfilePic(path); + let pfpUploaded = await saveImageToAWS(fileName, blob); + await cacheRemoteUri(username, "pfp.png"); + setRefresh(!refresh); + if (pfpUploaded === true) { + showPfpUploadedToast(username); + } else { + showPfpNotUploadedToast(username); } setShowMakePfp(false); } catch (error) { console.log("Error uploading image to S3", error); } - //updateProfilePicture(username,image); }; return ( @@ -113,37 +147,17 @@ export function ProfileScreen(props) {
- - - - {showStreak ? ( + + + + {usernameSet && showStreak && ( - + {streak} - ) : ( - )} - addProfileImage()} src={profilePic} /> + handleProfileImageClick()} username={username} refresh={refresh} setRefresh={setRefresh} /> + @{username} Following - - navigation.navigate("Followers", { isFollowerPage: true }) - } - > + navigation.navigate("Followers", { isFollowerPage: true })}> {followingcount} Followers - - navigation.navigate("Followers", { isFollowerPage: false }) - } - > + navigation.navigate("Followers", { isFollowerPage: false })}> {followercount} setModalVisible(true)}> Bio - + {/*@{username}*/}
- - ""} - > - Delete old cache - Toggle privacy - - Your current weekly workout goal is {goal}. Change goal bellow - + Your current weekly workout goal is {goal}. Change goal below - + - - Change weekly goal - + Change weekly goal ); diff --git a/src/screens/WorkoutsScreen.js b/src/screens/WorkoutsScreen.js new file mode 100644 index 0000000..292bd1c --- /dev/null +++ b/src/screens/WorkoutsScreen.js @@ -0,0 +1,71 @@ +import { useEffect, useState } from "react"; +import { View, Image, Text, StyleSheet, Pressable, TouchableOpacity, ScrollView } from "react-native"; +import CustomButton from "../components/CustomButton"; +import { blueThemeColor, grayThemeColor } from "../library/constants"; +import CreateWorkoutModal from "../components/modals/CreateWorkoutModal"; +import { getWorkouts } from "../crud/WorkoutOperations"; +import { getCurrentUser } from "../crud/CacheOperations"; +import Workout from "../components/Workout/Workout"; +import Header from "../components/Header"; + +export function WorkoutsScreen() { + const [modalVisible, setModalVisible] = useState(false); + const [workouts, setWorkouts] = useState([]); + const [refreshWorkouts, setRefreshWorkouts] = useState(false); + + async function getWorkoutsForScreen() { + let currUser = await getCurrentUser(); + let ejercicios = await getWorkouts(currUser); + setWorkouts(ejercicios); + } + useEffect(() => { + getWorkoutsForScreen(); + }, [refreshWorkouts]); + return ( + <> + +
+ + + + + setModalVisible(true)} + /> + + + {workouts.map((workout, index) => ( + + ))} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: "white", + display: "flex", + flexDirection: "column", + height: "100%", + alignItems: "center", + }, + stickyHeader: { + width: "100%", + marginBottom: "5%", + //marginTop: "20%", + display: "flex", + flexDirection: "column", + alignItems: "center", + paddingBottom: 5, + }, +});