From abf7d7ff36cc104aa3c12c588d4f8a363707d527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Perttu=20L=C3=A4hteenlahti?= Date: Sat, 22 Aug 2020 15:18:57 +0300 Subject: [PATCH] Migrate Nyxo to Github --- .eslintrc.js | 62 + .gitattributes | 1 + .gitignore | 128 + .graphqlconfig.yml | 18 + .prettierrc.js | 8 + .watchmanconfig | 1 + README.md | 41 + .../push-notification-ios.ts | 7 + __mocks__/@sentry/react-native.ts | 5 + __mocks__/appcenter-analytics.ts | 6 + __mocks__/appcenter-push.ts | 6 + __mocks__/aws-amplify.ts | 5 + __mocks__/chroma-js.ts | 17 + __mocks__/i18n-js.ts | 17 + __mocks__/moment.ts | 5 + __mocks__/prop-types.ts | 5 + __mocks__/react-native-app-auth.ts | 6 + __mocks__/react-native-code-push.ts | 8 + __mocks__/react-native-firebase.ts | 28 + __mocks__/react-native-gesture-handler.ts | 13 + __mocks__/react-native-get-random-values.ts | 3 + __mocks__/react-native-healthkit.ts | 14 + __mocks__/react-native-iap.ts | 6 + __mocks__/react-native-intercom.ts | 6 + __mocks__/react-native-iphone-x-helper.ts | 4 + __mocks__/react-native-localize.ts | 44 + __mocks__/react-native-purchases.ts | 31 + __mocks__/react-native-reanimated.ts | 3 + __mocks__/react-native-splash-screen.ts | 5 + __mocks__/react-native-svg.ts | 61 + __mocks__/react-native.ts | 47 + __mocks__/react-redux.ts | 6 + amplify/.config/project-config.json | 17 + android/Gemfile | 6 + android/Gemfile.lock | 181 + android/app/.classpath | 6 + android/app/_BUCK | 55 + android/app/build.gradle | 271 + android/app/build_defs.bzl | 19 + android/app/debug/AndroidManifest.xml | 8 + .../java/fi/nyxo/app/ReactNativeFlipper.java | 66 + android/app/proguard-rules.pro | 26 + android/app/src/main/AndroidManifest.xml | 86 + .../main/java/fi/nyxo/app/MainActivity.java | 37 + .../java/fi/nyxo/app/MainApplication.java | 117 + .../fi/nyxo/app/MainMessagingService.java | 33 + .../nyxo/app/generated/BasePackageList.java | 16 + android/build.gradle | 53 + android/gradle.properties | 28 + android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + android/gradlew | 172 + android/gradlew.bat | 84 + android/settings.gradle | 28 + assets/appIcons/fitbit-app-icon.png | Bin 0 -> 34015 bytes assets/appIcons/google-fit-icon.png | Bin 0 -> 26794 bytes assets/appIcons/oura.jpg | Bin 0 -> 10413 bytes assets/appIcons/withings-icon.png | Bin 0 -> 28102 bytes assets/fonts/Domine-Bold.ttf | Bin 0 -> 140156 bytes assets/fonts/Domine-Regular.ttf | Bin 0 -> 131968 bytes assets/fonts/FontAwesome.ttf | Bin 0 -> 31044 bytes assets/fonts/Montserrat-Black.ttf | Bin 0 -> 257064 bytes assets/fonts/Montserrat-BlackItalic.ttf | Bin 0 -> 261232 bytes assets/fonts/Montserrat-Bold.ttf | Bin 0 -> 244036 bytes assets/fonts/Montserrat-BoldItalic.ttf | Bin 0 -> 249124 bytes assets/fonts/Montserrat-ExtraBold.ttf | Bin 0 -> 244372 bytes assets/fonts/Montserrat-ExtraBoldItalic.ttf | Bin 0 -> 249268 bytes assets/fonts/Montserrat-ExtraLight.ttf | Bin 0 -> 241632 bytes assets/fonts/Montserrat-ExtraLightItalic.ttf | Bin 0 -> 245664 bytes assets/fonts/Montserrat-Italic.ttf | Bin 0 -> 248656 bytes assets/fonts/Montserrat-Light.ttf | Bin 0 -> 241580 bytes assets/fonts/Montserrat-LightItalic.ttf | Bin 0 -> 245776 bytes assets/fonts/Montserrat-Medium.ttf | Bin 0 -> 242692 bytes assets/fonts/Montserrat-MediumItalic.ttf | Bin 0 -> 247540 bytes assets/fonts/Montserrat-Regular.ttf | Bin 0 -> 245276 bytes assets/fonts/Montserrat-SemiBold.ttf | Bin 0 -> 243324 bytes assets/fonts/Montserrat-SemiBoldItalic.ttf | Bin 0 -> 248684 bytes assets/fonts/Montserrat-Thin.ttf | Bin 0 -> 240952 bytes assets/fonts/Montserrat-ThinItalic.ttf | Bin 0 -> 244872 bytes assets/healthkitIcon.png | Bin 0 -> 4146 bytes assets/profilePictures/eeva.png | Bin 0 -> 566146 bytes assets/profilePictures/perttu.jpg | Bin 0 -> 22981 bytes assets/profilePictures/pietari.png | Bin 0 -> 1217599 bytes assets/source-images/SourceImages.ts | 8 + assets/source-images/fitbit.png | Bin 0 -> 34015 bytes assets/source-images/garmin.png | Bin 0 -> 268632 bytes assets/source-images/suunto.png | Bin 0 -> 3154911 bytes assets/source-images/withings.jpg | Bin 0 -> 21377 bytes assets/svgs.tsx | 795 + assets/terveystalo-logo.svg | 23 + assets/texts/rating.ts | 25 + babel.config.js | 33 + docs/CHANGELOG | 22 + docs/Docs.md | 12 + docs/Habits.md | 80 + docs/Notifications.md | 26 + getContentfulEnvironment.js | 13 + index.js | 20 + ios/Gemfile | 3 + ios/Gemfile.lock | 179 + ios/GoogleService-Info.plist | 38 + ios/LaunchScreen.xib | 43 + ios/Nyxo.xcodeproj/project.pbxproj | 1682 ++ .../xcshareddata/xcschemes/Nyxo.xcscheme | 140 + ios/Nyxo.xcworkspace/contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 10 + ios/Nyxo/AppDelegate.h | 14 + ios/Nyxo/AppDelegate.m | 198 + ios/Nyxo/Base.lproj/LaunchScreen.xib | 42 + .../AppIcon.appiconset/Contents.json | 149 + .../AppIcon.appiconset/Icon-1.png | Bin 0 -> 109298 bytes .../AppIcon.appiconset/Icon.png | Bin 0 -> 346382 bytes .../AppIcon.appiconset/icon_20pt@2x.png | Bin 0 -> 2283 bytes .../AppIcon.appiconset/icon_20pt@3x.png | Bin 0 -> 3911 bytes .../AppIcon.appiconset/icon_29pt.png | Bin 0 -> 1424 bytes .../AppIcon.appiconset/icon_29pt@2x.png | Bin 0 -> 3732 bytes .../AppIcon.appiconset/icon_29pt@3x.png | Bin 0 -> 6703 bytes .../AppIcon.appiconset/icon_40pt@2x.png | Bin 0 -> 5827 bytes .../AppIcon.appiconset/icon_40pt@3x.png | Bin 0 -> 10706 bytes .../AppIcon.appiconset/icon_60pt@2x.png | Bin 0 -> 10706 bytes .../AppIcon.appiconset/icon_60pt@3x.png | Bin 0 -> 19826 bytes ios/Nyxo/Images.xcassets/Contents.json | 6 + .../Launch.launchimage/Contents.json | 158 + .../Launch.launchimage/Retina HD 4.7.png | Bin 0 -> 152924 bytes .../Launch.launchimage/iPhone XS Max.png | Bin 0 -> 262387 bytes .../Launch.launchimage/iPhone XS.png | Bin 0 -> 246028 bytes ios/Nyxo/Info.plist | 134 + ios/Nyxo/Nyxo.entitlements | 27 + ios/Nyxo/fi.lproj/LaunchScreen.strings | 6 + ios/Nyxo/main.m | 16 + ios/NyxoTests/Info.plist | 24 + ios/NyxoTests/NyxoTests.m | 68 + ios/Podfile | 118 + ios/Podfile.lock | 949 + ios/Shared/CommandStatus.swift | 87 + ios/Shared/Nyxo Watch-Bridging-Header.h | 4 + ios/Shared/Nyxo-Bridging-Header.h | 4 + jest-setup.js | 46 + jest.config.js | 36 + metro.config.js | 20 + package.json | 266 + patches/react-native+0.62.2.patch | 115 + react-native.config.js | 9 + rn-cli.config.js | 8 + src/API.ts | 1513 ++ src/App.tsx | 78 + src/Hooks/UseAppState.ts | 22 + src/Hooks/UseBackgroundFetch.ts | 33 + src/Hooks/UseInterval.ts | 20 + src/Hooks/UseNotificationEventHandlers.ts | 51 + src/Hooks/UseOnMount.ts | 7 + src/Hooks/UseOnUpdate.ts | 23 + src/Hooks/useLinking.tsx | 95 + src/Types/ChallengeState.ts | 20 + src/Types/CoachingContentState.ts | 67 + src/Types/CoachingNotificationState.ts | 10 + src/Types/CoachingProfile.ts | 9 + src/Types/CoachingState.ts | 43 + src/Types/GetState.ts | 3 + src/Types/Microtask.ts | 15 + src/Types/ModalState.ts | 7 + src/Types/NetworkState.ts | 4 + src/Types/NotificationState.ts | 48 + src/Types/OnboardingState.ts | 4 + src/Types/ReduxActions.ts | 17 + src/Types/Sleep/Fitbit.ts | 48 + src/Types/Sleep/Oura.ts | 34 + src/Types/Sleep/Withings.ts | 28 + src/Types/SleepClockState.ts | 34 + src/Types/Sleepdata.ts | 71 + src/Types/State.ts | 68 + src/Types/State/AuthState.ts | 8 + src/Types/State/ManualDataState.ts | 5 + src/Types/State/Periods.ts | 23 + src/Types/State/SleepDataSourceState.ts | 14 + src/Types/State/api-state.ts | 58 + src/Types/State/days-state.ts | 7 + src/Types/State/habit-state.ts | 42 + src/Types/State/insight-state.ts | 8 + src/Types/State/linking-state.ts | 4 + src/Types/SubscriptionState.ts | 21 + src/Types/TrackingState.ts | 9 + src/Types/UserState.ts | 15 + src/Types/generated/contentful.d.ts | 488 + src/Types/navigation/navigation.ts | 24 + src/actions/Cloud/Sleep.ts | 92 + src/actions/Cloud/User.ts | 25 + .../CoachingNotificationActions.ts | 34 + src/actions/IntercomActions.ts | 45 + src/actions/MicrotaskActions.ts | 0 src/actions/NotificationActions.ts | 380 + src/actions/RefreshActions.ts | 24 + src/actions/StartupActions.ts | 73 + src/actions/api-actions/fitbit-actions.ts | 213 + src/actions/api-actions/garmin-actions.ts | 58 + src/actions/api-actions/google-fit-actions.ts | 279 + src/actions/api-actions/oura-actions.ts | 180 + src/actions/api-actions/suunto-actions.ts | 54 + src/actions/api-actions/withings-actions.ts | 222 + src/actions/auth/auth-actions.ts | 279 + .../calendar-actions/calendar-actions.ts | 50 + src/actions/challenges/challenge-actions.ts | 14 + src/actions/coaching/coaching-actions.ts | 267 + .../coaching/coaching-to-cloud-actions.ts | 4 + src/actions/coaching/content-actions.ts | 193 + src/actions/habit/habit-actions.spec.ts | 281 + src/actions/habit/habit-actions.ts | 466 + src/actions/iOS/SleepDataActions.ts | 42 + .../insight-actions/insight-actions.ts | 96 + src/actions/linking/linking-actions.ts | 137 + .../manual-sleep/manual-sleep-actions.spec.ts | 29 + .../manual-sleep/manual-sleep-actions.ts | 122 + src/actions/modal/modal-actions.spec.ts | 33 + src/actions/modal/modal-actions.ts | 21 + src/actions/onboarding/onboarding-actions.ts | 10 + src/actions/shared.ts | 1 + .../revoke-previous-source.ts | 35 + .../sleep-source-actions.ts | 87 + src/actions/sleep/health-kit-actions.ts | 149 + src/actions/sleep/sleep-data-actions.ts | 258 + src/actions/sleep/sleep-to-cloud-actions.ts | 151 + .../subscription/subscription-actions.ts | 155 + src/actions/user/user-actions.ts | 81 + .../AnimatedFastImage/AnimatedFastImage.tsx | 6 + src/components/AnimatedSvgPath.tsx | 136 + .../AnimationComponents/AnimateDisplay.tsx | 141 + src/components/AuthSpecific/Disclaimer.tsx | 44 + src/components/BottomInfo.tsx | 12 + .../BottomTabSheet/BottomActionSheet.tsx | 22 + .../BottomActionSheetContent.tsx | 15 + .../BottomActionSheetHeader.tsx | 13 + src/components/Buttons/BackToAppButton.tsx | 40 + src/components/Buttons/BottomButton.tsx | 59 + src/components/Buttons/GoBack.tsx | 56 + src/components/Buttons/IconButton.tsx | 32 + src/components/Buttons/LinkingButton.tsx | 69 + src/components/Buttons/LoginButton.tsx | 16 + src/components/Buttons/PrimaryButton.tsx | 64 + src/components/Buttons/RatingButton.tsx | 67 + src/components/Buttons/ScalingButton.tsx | 95 + src/components/Buttons/SecondaryButton.tsx | 53 + src/components/Buttons/TerveystaloButton.tsx | 22 + src/components/Buttons/TextButton.tsx | 43 + src/components/Buttons/backButton.tsx | 55 + src/components/Card.tsx | 23 + src/components/Challenge/ChallengeItem.tsx | 60 + src/components/Charts/Axis.tsx | 80 + src/components/Charts/HeartRateChart.tsx | 245 + src/components/Charts/ProfileChart.tsx | 53 + src/components/Charts/SleepScoreGraph.tsx | 145 + .../Charts/SleepTimeChart/BottomInfo.tsx | 18 + .../Charts/SleepTimeChart/DayInfo.tsx | 68 + .../Charts/SleepTimeChart/SleepBars.tsx | 60 + .../SleepTimeChart/SleepTimeChartAverage.tsx | 51 + .../Charts/SleepTimeChart/XTicks.tsx | 54 + .../Charts/SleepTimeChart/YTicks.tsx | 48 + src/components/Charts/SleepTimesChart.tsx | 272 + src/components/Charts/sleepTimeChart.tsx | 162 + src/components/ChronotypeTest/Chronotype.tsx | 241 + .../ChronotypeTest/ChronotypeBox.tsx | 19 + src/components/ChronotypeTest/TestEnd.tsx | 24 + src/components/ChronotypeTest/TestStart.tsx | 50 + .../CoachingMonthCard/CoachingMonthCard.tsx | 67 + src/components/CoachingMonthCard/index.tsx | 1 + src/components/CoachingSpecific/Authors.tsx | 54 + .../CoachingSpecific/BuyCoachingButton.tsx | 134 + .../CoachingSpecific/CoachingHeader.tsx | 20 + .../CoachingSpecific/CoachingNotStarted.tsx | 48 + .../CoachingSectionHeader.tsx | 28 + src/components/CoachingSpecific/Copyright.tsx | 26 + .../CoachingSpecific/IntroduceCoaching.tsx | 37 + .../CoachingSpecific/RefreshCoaching.tsx | 42 + .../CoachingSpecific/StartCoaching.tsx | 100 + src/components/CoachingSpecific/TopHeader.tsx | 90 + .../CoachingSpecific/Week.Cover.tsx | 73 + src/components/CoachingSpecific/WeekCard.tsx | 168 + .../CoachingSpecific/WeekCardTitle.tsx | 70 + .../CoachingSpecific/WeekCarousel.tsx | 84 + .../CoachingSpecific/WeekCompleted.tsx | 41 + src/components/CoachingSpecific/WeekIntro.tsx | 102 + .../CoachingSpecific/WeekSummary.tsx | 101 + .../CoachingSpecific/WeekViewHeader.tsx | 74 + src/components/CurrentCoaching.tsx | 27 + src/components/DayStrip.tsx | 126 + src/components/DetailView/SampleRow.tsx | 95 + src/components/ElegantAnimation.tsx | 47 + src/components/EmptyState.tsx | 39 + src/components/HabitCard/ActionComplete.tsx | 63 + src/components/HabitCard/ExampleHabit.tsx | 155 + src/components/HabitCard/HabitCard.tsx | 222 + src/components/HabitCard/HabitCardManage.tsx | 141 + src/components/HabitCard/TopRow.tsx | 71 + src/components/HabitList/HabitList.tsx | 129 + src/components/Header.tsx | 44 + .../IAPComponents/PerkList.spec.tsx | 10 + src/components/IAPComponents/PerkList.tsx | 58 + .../SubscriptionItem.spec.tsx... | 20 + .../IAPComponents/SubscriptionItem.tsx | 120 + .../__snapshots__/PerkList.spec.tsx.snap | 3 + src/components/InfoRow.tsx | 44 + src/components/Lesson/ExtraInfo.tsx | 34 + src/components/Lesson/LessonContent.tsx | 30 + src/components/Lesson/LessonCover.tsx | 75 + src/components/Lesson/RateLesson.tsx | 80 + .../LessonComponents/AuthorCard.tsx | 54 + .../LessonComponents/ExampleHabitSection.tsx | 65 + .../LessonComponents/LargeAuthorCard.tsx | 59 + .../LessonComponents/LessonListItem.tsx | 233 + .../LessonComponents/ReadingTime.tsx | 67 + .../LessonComponents/SectionFooter.tsx | 128 + .../LessonComponents/SectionHeader.tsx | 36 + src/components/LessonComponents/Separator.tsx | 16 + src/components/LessonComponents/Tags.tsx | 52 + src/components/LoadingAnimation.tsx | 154 + .../MainScreenSpecific/ClockCarousel.tsx | 144 + .../MainScreenSpecific/EditNightHeader.tsx | 85 + .../MainScreenSpecific/EnablePushCheck.tsx | 35 + .../MainScreenSpecific/Explanations.tsx | 84 + .../MainScreenSpecific/HelpInfo.tsx | 29 + .../MainScreenSpecific/InitializeSources.tsx | 84 + .../MainScreenSpecific/SomethingWrong.tsx | 15 + .../MainScreenSpecific/TodayView.tsx | 26 + .../MicrotaskComponents/AddMicrotask.tsx | 50 + .../MicrotaskComponents/HabitPageHeader.tsx | 16 + .../MicrotaskComponents/MicrotaskProgress.tsx | 19 + .../MicrotaskComponents/NoMicrotasks.tsx | 15 + src/components/MicrotaskRow.tsx | 186 + .../MySleepScore/MySleepScoreBadge.tsx | 50 + .../MySleepScore/SleepScoreSegment.tsx | 73 + .../NotificationCenter/NotificationCard.tsx | 88 + .../NotificationCenterLink.tsx | 65 + src/components/Primitives/Primitives.tsx | 230 + src/components/ProfileSpecific/Userinfo.tsx | 25 + src/components/RatingModal.tsx | 122 + src/components/RichText.tsx | 292 + src/components/ScrollView/InView.tsx | 97 + .../SettingsSpecific/CodeDisclaimer.tsx | 45 + .../IntercomProfilePictures.tsx | 42 + .../SettingsSpecific/LinkModule.tsx | 186 + .../SettingsSpecific/NotificationRow.tsx | 34 + src/components/SettingsSpecific/SourceRow.tsx | 109 + .../SettingsSpecific/Sources/AddSources.tsx | 80 + .../SettingsSpecific/Sources/EnableSource.tsx | 103 + .../SettingsSpecific/Sources/GoogleFit.tsx | 46 + .../SettingsSpecific/Sources/LinkSource.tsx | 38 + .../__tests__/SettingRow.spec.tsx | 19 + .../__tests__/VersionInformation.test.tsx | 22 + .../__snapshots__/SettingRow.spec.tsx.snap | 3 + .../VersionInformation.test.tsx.snap | 3 + .../SettingsSpecific/settingRow.tsx | 82 + .../SettingsSpecific/versionInformation.tsx | 56 + src/components/Signup/SignupBottomButton.tsx | 27 + src/components/Skeletons/SkeletonContent.tsx | 94 + src/components/SleepTarget/Overlays.tsx | 25 + src/components/SleepTarget/Scale.tsx | 82 + src/components/SleepTarget/Separator.tsx | 30 + src/components/SleepTarget/SleepTarget.tsx | 224 + src/components/SleepTarget/StartModal.tsx | 56 + src/components/SvgIcon.tsx | 73 + src/components/Switch/Switch.tsx | 41 + src/components/TabBarIcon.tsx | 65 + src/components/TabBarLabel.tsx | 32 + src/components/TextField.tsx | 135 + .../TextIndicator/TextLengthIndicator.tsx | 49 + src/components/Timeline/Timeline.tsx | 243 + src/components/TinyCard.tsx | 69 + src/components/TopInfo.tsx | 89 + src/components/TranslatedText.tsx | 33 + src/components/__tests__/Card.test.tsx | 13 + src/components/__tests__/IconBold.test.tsx | 13 + src/components/__tests__/SvgIcon.test.tsx | 18 + src/components/__tests__/TopInfo.test.tsx | 80 + .../__tests__/TranslatedText.test.tsx | 17 + .../__snapshots__/Card.test.tsx.snap | 3 + .../__snapshots__/IconBold.test.tsx.snap | 29 + .../__snapshots__/SvgIcon.test.tsx.snap | 29 + .../TranslatedText.test.tsx.snap | 3 + src/components/animationContainer.tsx | 29 + src/components/iconBold.tsx | 17 + src/components/iconRegular.tsx | 34 + src/components/modals/AskAboutDataModal.tsx | 83 + .../modals/AskAboutDataModal/GoogleFit.tsx | 45 + .../modals/AskAboutDataModal/HealthKit.tsx | 45 + .../AskAboutDataModal/PushNotification.tsx | 50 + .../modals/AskAboutDataModal/SelectSource.tsx | 84 + src/components/modals/CloseModalButton.tsx | 47 + src/components/modals/ExplanationsModal.tsx | 199 + .../modals/HabitModal/EditHabitModal.tsx | 130 + .../HabitModal/HabitModalFieldSection.tsx | 82 + .../modals/HabitModal/HabitModalStreak.tsx | 97 + .../HabitModal/HabitModalTimeSection.tsx | 37 + .../modals/HabitModal/HabitModalTopInfo.tsx | 86 + .../modals/HabitModal/HabitModalTopRow.tsx | 74 + .../modals/HabitModal/NewHabitModal.tsx | 131 + .../HabitModal/SetTimePeriodButtons.tsx | 103 + .../MergeHabitsModal/MergeHabitsModal.tsx | 126 + .../modals/MergeHabitsModal/index.tsx | 0 src/components/modals/MySleepScoreModal.tsx | 155 + src/components/modals/setSleepGoal.tsx | 56 + src/components/scpath.tsx | 86 + src/components/sleepClock/CircularSlider.tsx | 295 + src/components/sleepClock/ClockEmpty.tsx | 30 + .../sleepClock/CoachingProgressToday.tsx | 35 + src/components/sleepClock/CurrentTime.tsx | 25 + src/components/sleepClock/Cursor.tsx | 128 + src/components/sleepClock/CurvedActions.tsx | 100 + .../sleepClock/CurvedEditButton.tsx | 73 + src/components/sleepClock/Date.tsx | 45 + src/components/sleepClock/EditableArc.tsx | 114 + .../sleepClock/FallAsleepWindow.tsx | 105 + src/components/sleepClock/InfoButton.tsx | 37 + src/components/sleepClock/MinuteSticks.tsx | 40 + src/components/sleepClock/NightRating.tsx | 56 + src/components/sleepClock/NoDataInfo.tsx | 78 + src/components/sleepClock/SleepArc.tsx | 53 + src/components/sleepClock/SleepTime.tsx | 137 + src/components/sleepClock/SleepTimesArc.tsx | 89 + src/components/sleepClock/Slider.tsx | 148 + src/components/sleepClock/TimePath.tsx | 36 + src/components/sleepClock/TimerText.tsx | 51 + src/components/sleepClock/TrackerName.tsx | 30 + src/components/sleepClock/clockTimes.tsx | 56 + src/components/sleepclock.tsx | 160 + src/components/sources/FitbitSection.tsx | 77 + src/components/sources/GoogleFitSection.tsx | 123 + src/components/sources/HealthKitSection.tsx | 98 + src/components/sources/OuraSection.tsx | 80 + src/components/sources/WithingsSection.tsx | 84 + .../subscriptions/SubscriptionCard.tsx | 121 + src/config/Amplify.ts | 8 + src/config/AppNavigation.tsx | 136 + src/config/Config.ts | 92 + src/config/NavigationHelper.ts | 7 + src/config/PushNotifications.ts | 87 + src/config/Validation.ts | 33 + src/config/i18n.ts | 56 + src/config/routes/AuthNavigator.tsx | 38 + src/config/routes/IntroductionNavigator.tsx | 14 + src/config/routes/JournalNavigator.tsx | 39 + src/config/routes/RootNavigator.tsx | 51 + src/config/routes/Routes.ts | 32 + src/config/routes/TabNavigator.tsx | 77 + src/config/routes/coachingNavigator.tsx | 26 + src/config/routes/profileNavigator.tsx | 19 + src/config/routes/settingsNavigator.tsx | 57 + src/graphql/custom/mutations.ts | 7 + src/graphql/custom/queries.ts | 138 + src/graphql/mutations.ts | 324 + src/graphql/queries.ts | 267 + src/graphql/subscriptions.ts | 324 + src/helpers/Dimensions.ts | 11 + src/helpers/Fonts.ts | 34 + src/helpers/GetPathFromState.tsx | 285 + src/helpers/KeyExtractor.ts | 3 + src/helpers/KeyboardEvents.ts | 46 + src/helpers/Measure.tsx | 15 + src/helpers/SleepScoreCalculators.ts | 139 + src/helpers/animated.tsx | 143 + src/helpers/geometry.ts | 107 + src/helpers/habits.ts | 143 + src/helpers/rating.ts | 41 + src/helpers/reading-time.ts | 13 + src/helpers/serializeTransform.ts | 54 + src/helpers/sleep.ts | 52 + src/helpers/sleep/fitbit-helper.spec.ts | 14 + src/helpers/sleep/fitbit-helper.ts | 41 + src/helpers/sleep/google-fit-helper.ts | 55 + src/helpers/sleep/oura-helper.ts | 132 + src/helpers/sleep/sleep-data-helper.spec.ts | 61 + src/helpers/sleep/sleep-data-helper.ts | 214 + src/helpers/sleep/withings-helper.ts | 55 + src/helpers/snapshot.tsx | 11 + src/helpers/time.ts | 205 + src/mockData/fitbit.ts | 342 + src/screens/Auth/ConfirmUser.tsx | 65 + src/screens/Auth/ForgotPasswordScreen.tsx | 102 + src/screens/Auth/Login.tsx | 150 + src/screens/Auth/RecoverPassword.tsx | 0 src/screens/Auth/RegisterScreen.tsx | 150 + src/screens/Introduction/Introduction.tsx | 413 + .../Introduction/Mockups/HealthKit.tsx | 53 + .../Introduction/Mockups/Notification.tsx | 102 + .../Introduction/Mockups/SleepBetter.tsx | 92 + src/screens/Introduction/Mockups/iPhone.tsx | 263 + src/screens/Introduction/Slide.tsx | 37 + src/screens/Shared/HabitView.tsx | 68 + src/screens/Terveystalo/Welcome.tsx | 125 + src/screens/Welcome/Welcome.tsx | 133 + src/screens/coaching/CoachingView.tsx | 59 + src/screens/coaching/LessonView.tsx | 201 + src/screens/coaching/Lessons.tsx | 123 + src/screens/coaching/MicroTasks.tsx | 12 + src/screens/coaching/PurchaseView.tsx | 158 + src/screens/coaching/WeekView.tsx | 66 + src/screens/coaching/challenges.tsx | 41 + src/screens/main/DetailView.tsx | 227 + src/screens/main/LegendView.tsx | 8 + src/screens/main/NotificationCenter.tsx | 54 + src/screens/main/components/LastUpdated.tsx | 57 + .../main/components/batteryInformation.tsx | 68 + src/screens/main/components/dayTitle.tsx | 119 + src/screens/main/main.tsx | 85 + src/screens/profile/BedStatsView.tsx | 55 + src/screens/profile/ChallengeView.tsx | 22 + src/screens/profile/LoginOrRegister.tsx | 30 + src/screens/profile/SleepStatsView.tsx | 60 + src/screens/profile/achievement.tsx | 37 + src/screens/profile/profile.tsx | 155 + src/screens/settings/CloudSettings.tsx | 100 + src/screens/settings/CoachingSettings.tsx | 75 + src/screens/settings/DevelopmentMenu.tsx | 51 + src/screens/settings/ManageSubscription.tsx | 131 + src/screens/settings/Notifications.tsx | 113 + src/screens/settings/SourceSettings.tsx | 46 + src/screens/settings/settings.tsx | 229 + src/store/CustomAuthStorage.ts | 73 + src/store/InitialStates/SleepClock.ts | 38 + src/store/InitialStates/days.ts | 6 + src/store/Reducers/CoachingProfileReducer.ts | 33 + src/store/Reducers/NotificationReducer.ts | 163 + src/store/Reducers/TrackingReducer.ts | 31 + .../Reducers/api-reducer/api-reducer.spec.ts | 51 + src/store/Reducers/api-reducer/api-reducer.ts | 122 + .../auth-reducer/auth-reducer.spec.ts | 89 + .../Reducers/auth-reducer/auth-reducer.ts | 73 + .../calendar-reducer/calendar-reducer.ts | 58 + .../Reducers/challenges/challenge-reducer.ts | 43 + .../coaching-reducer/coaching-reducer.ts | 161 + .../content-reducer/content-reducer.ts | 94 + .../Reducers/habit-reducer/habit-reducer.ts | 79 + .../insight-reducer/insight-reducer.ts | 40 + .../journal-view/journal-view-reducer.ts | 67 + src/store/Reducers/linking/linking-reducer.ts | 40 + .../manual-sleep/manual-sleep-reducer.ts | 34 + .../Reducers/modal/modal-reducer.spec.ts | 34 + src/store/Reducers/modal/modal-reducer.ts | 48 + .../coaching-notification-reducer.spec.ts | 88 + .../coaching-notifications-reducer.ts | 44 + .../onboarding/onboard-reducer.spec.ts | 19 + .../Reducers/onboarding/onboarding-reducer.ts | 28 + .../sleep-source-reducer.ts | 40 + .../sleep-store/local-sleep-reducer.ts | 0 .../sleep-store/sleep-store-reducer.ts | 31 + .../Reducers/sleep/health-kit-reducer.ts | 44 + src/store/Reducers/sleepclockReducer.ts | 119 + .../subscription/subscription-reducer.spec.ts | 19 + .../subscription/subscription-reducer.ts | 62 + src/store/Reducers/user/user-reducer.spec.ts | 19 + src/store/Reducers/user/user-reducer.ts | 75 + src/store/Selectors/ChallengeSelectors.ts | 9 + src/store/Selectors/ManualDataSelectors.ts | 20 + src/store/Selectors/MicrotaskSelectors.ts | 86 + src/store/Selectors/ModalSelectors.ts | 30 + src/store/Selectors/NotificationSelectors.ts | 57 + src/store/Selectors/OnboardingSelectors.ts | 15 + src/store/Selectors/SleepDataSelectors.ts | 224 + src/store/Selectors/SmartActionsSelectors.ts | 28 + src/store/Selectors/TrackingSelectors.ts | 10 + src/store/Selectors/UserSelectors.ts | 55 + .../Selectors/api-selectors/api-selectors.ts | 57 + .../auth-selectors/auth-selectors.ts | 14 + .../coaching-selectors/coaching-selectors.ts | 231 + .../Selectors/coaching-selectors/index.ts | 1 + .../content-selectors/content-selectors.ts | 36 + .../habit-selectors/habit-selectors.spec.ts | 180 + .../habit-selectors/habit-selectors.ts | 83 + .../health-kit-selectors.ts | 10 + .../Selectors/insight-selectors/Insights.ts | 41 + .../Selectors/linking-selectors/index.ts | 14 + .../notification-selectors.ts | 24 + .../sleep-source-selectors.ts | 74 + .../SubscriptionSelectors.ts | 24 + src/store/index.ts | 100 + src/styles/colors.ts | 73 + src/styles/styled-components.ts | 13 + src/styles/styled.d.ts | 16 + src/styles/themes.ts | 92 + src/translations/en.json | 667 + src/translations/fi.json | 661 + .../segmented-control.d.ts | 1 + src/typings/Initials.d.ts | 1 + src/typings/aws-exports.d.ts | 2 + src/typings/react-navigation.d.ts | 47 + src/typings/state/coaching-state.ts | 43 + src/typings/state/health-kit-state.ts | 7 + src/typings/state/sleep-source-state.ts | 23 + src/typings/svg.t.ts | 7 + tsconfig.jest.json | 7 + tsconfig.json | 29 + yarn.lock | 15500 ++++++++++++++++ 591 files changed, 59264 insertions(+) create mode 100644 .eslintrc.js create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .graphqlconfig.yml create mode 100644 .prettierrc.js create mode 100644 .watchmanconfig create mode 100644 README.md create mode 100644 __mocks__/@react-native-community/push-notification-ios.ts create mode 100644 __mocks__/@sentry/react-native.ts create mode 100644 __mocks__/appcenter-analytics.ts create mode 100644 __mocks__/appcenter-push.ts create mode 100644 __mocks__/aws-amplify.ts create mode 100644 __mocks__/chroma-js.ts create mode 100644 __mocks__/i18n-js.ts create mode 100644 __mocks__/moment.ts create mode 100644 __mocks__/prop-types.ts create mode 100644 __mocks__/react-native-app-auth.ts create mode 100644 __mocks__/react-native-code-push.ts create mode 100644 __mocks__/react-native-firebase.ts create mode 100644 __mocks__/react-native-gesture-handler.ts create mode 100644 __mocks__/react-native-get-random-values.ts create mode 100644 __mocks__/react-native-healthkit.ts create mode 100644 __mocks__/react-native-iap.ts create mode 100644 __mocks__/react-native-intercom.ts create mode 100644 __mocks__/react-native-iphone-x-helper.ts create mode 100644 __mocks__/react-native-localize.ts create mode 100644 __mocks__/react-native-purchases.ts create mode 100644 __mocks__/react-native-reanimated.ts create mode 100644 __mocks__/react-native-splash-screen.ts create mode 100644 __mocks__/react-native-svg.ts create mode 100644 __mocks__/react-native.ts create mode 100644 __mocks__/react-redux.ts create mode 100644 amplify/.config/project-config.json create mode 100644 android/Gemfile create mode 100644 android/Gemfile.lock create mode 100644 android/app/.classpath create mode 100644 android/app/_BUCK create mode 100644 android/app/build.gradle create mode 100644 android/app/build_defs.bzl create mode 100644 android/app/debug/AndroidManifest.xml create mode 100644 android/app/debug/java/fi/nyxo/app/ReactNativeFlipper.java create mode 100644 android/app/proguard-rules.pro create mode 100644 android/app/src/main/AndroidManifest.xml create mode 100644 android/app/src/main/java/fi/nyxo/app/MainActivity.java create mode 100644 android/app/src/main/java/fi/nyxo/app/MainApplication.java create mode 100644 android/app/src/main/java/fi/nyxo/app/MainMessagingService.java create mode 100644 android/app/src/main/java/fi/nyxo/app/generated/BasePackageList.java create mode 100644 android/build.gradle create mode 100644 android/gradle.properties create mode 100644 android/gradle/wrapper/gradle-wrapper.jar create mode 100644 android/gradle/wrapper/gradle-wrapper.properties create mode 100755 android/gradlew create mode 100644 android/gradlew.bat create mode 100644 android/settings.gradle create mode 100755 assets/appIcons/fitbit-app-icon.png create mode 100644 assets/appIcons/google-fit-icon.png create mode 100644 assets/appIcons/oura.jpg create mode 100644 assets/appIcons/withings-icon.png create mode 100755 assets/fonts/Domine-Bold.ttf create mode 100755 assets/fonts/Domine-Regular.ttf create mode 100644 assets/fonts/FontAwesome.ttf create mode 100755 assets/fonts/Montserrat-Black.ttf create mode 100755 assets/fonts/Montserrat-BlackItalic.ttf create mode 100755 assets/fonts/Montserrat-Bold.ttf create mode 100755 assets/fonts/Montserrat-BoldItalic.ttf create mode 100755 assets/fonts/Montserrat-ExtraBold.ttf create mode 100755 assets/fonts/Montserrat-ExtraBoldItalic.ttf create mode 100755 assets/fonts/Montserrat-ExtraLight.ttf create mode 100755 assets/fonts/Montserrat-ExtraLightItalic.ttf create mode 100755 assets/fonts/Montserrat-Italic.ttf create mode 100755 assets/fonts/Montserrat-Light.ttf create mode 100755 assets/fonts/Montserrat-LightItalic.ttf create mode 100755 assets/fonts/Montserrat-Medium.ttf create mode 100755 assets/fonts/Montserrat-MediumItalic.ttf create mode 100755 assets/fonts/Montserrat-Regular.ttf create mode 100755 assets/fonts/Montserrat-SemiBold.ttf create mode 100755 assets/fonts/Montserrat-SemiBoldItalic.ttf create mode 100755 assets/fonts/Montserrat-Thin.ttf create mode 100755 assets/fonts/Montserrat-ThinItalic.ttf create mode 100644 assets/healthkitIcon.png create mode 100644 assets/profilePictures/eeva.png create mode 100644 assets/profilePictures/perttu.jpg create mode 100644 assets/profilePictures/pietari.png create mode 100644 assets/source-images/SourceImages.ts create mode 100755 assets/source-images/fitbit.png create mode 100755 assets/source-images/garmin.png create mode 100644 assets/source-images/suunto.png create mode 100644 assets/source-images/withings.jpg create mode 100644 assets/svgs.tsx create mode 100644 assets/terveystalo-logo.svg create mode 100644 assets/texts/rating.ts create mode 100644 babel.config.js create mode 100644 docs/CHANGELOG create mode 100644 docs/Docs.md create mode 100644 docs/Habits.md create mode 100644 docs/Notifications.md create mode 100644 getContentfulEnvironment.js create mode 100644 index.js create mode 100644 ios/Gemfile create mode 100644 ios/Gemfile.lock create mode 100644 ios/GoogleService-Info.plist create mode 100644 ios/LaunchScreen.xib create mode 100644 ios/Nyxo.xcodeproj/project.pbxproj create mode 100644 ios/Nyxo.xcodeproj/xcshareddata/xcschemes/Nyxo.xcscheme create mode 100644 ios/Nyxo.xcworkspace/contents.xcworkspacedata create mode 100644 ios/Nyxo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 ios/Nyxo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 ios/Nyxo/AppDelegate.h create mode 100644 ios/Nyxo/AppDelegate.m create mode 100644 ios/Nyxo/Base.lproj/LaunchScreen.xib create mode 100755 ios/Nyxo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/Icon-1.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/Icon.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_20pt@2x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_20pt@3x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_29pt.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_29pt@2x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_29pt@3x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_40pt@2x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_40pt@3x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_60pt@2x.png create mode 100644 ios/Nyxo/Images.xcassets/AppIcon.appiconset/icon_60pt@3x.png create mode 100644 ios/Nyxo/Images.xcassets/Contents.json create mode 100644 ios/Nyxo/Images.xcassets/Launch.launchimage/Contents.json create mode 100644 ios/Nyxo/Images.xcassets/Launch.launchimage/Retina HD 4.7.png create mode 100644 ios/Nyxo/Images.xcassets/Launch.launchimage/iPhone XS Max.png create mode 100644 ios/Nyxo/Images.xcassets/Launch.launchimage/iPhone XS.png create mode 100644 ios/Nyxo/Info.plist create mode 100644 ios/Nyxo/Nyxo.entitlements create mode 100644 ios/Nyxo/fi.lproj/LaunchScreen.strings create mode 100644 ios/Nyxo/main.m create mode 100644 ios/NyxoTests/Info.plist create mode 100644 ios/NyxoTests/NyxoTests.m create mode 100644 ios/Podfile create mode 100644 ios/Podfile.lock create mode 100644 ios/Shared/CommandStatus.swift create mode 100644 ios/Shared/Nyxo Watch-Bridging-Header.h create mode 100644 ios/Shared/Nyxo-Bridging-Header.h create mode 100644 jest-setup.js create mode 100644 jest.config.js create mode 100644 metro.config.js create mode 100644 package.json create mode 100644 patches/react-native+0.62.2.patch create mode 100644 react-native.config.js create mode 100644 rn-cli.config.js create mode 100644 src/API.ts create mode 100644 src/App.tsx create mode 100644 src/Hooks/UseAppState.ts create mode 100644 src/Hooks/UseBackgroundFetch.ts create mode 100644 src/Hooks/UseInterval.ts create mode 100644 src/Hooks/UseNotificationEventHandlers.ts create mode 100644 src/Hooks/UseOnMount.ts create mode 100644 src/Hooks/UseOnUpdate.ts create mode 100644 src/Hooks/useLinking.tsx create mode 100644 src/Types/ChallengeState.ts create mode 100644 src/Types/CoachingContentState.ts create mode 100644 src/Types/CoachingNotificationState.ts create mode 100644 src/Types/CoachingProfile.ts create mode 100644 src/Types/CoachingState.ts create mode 100644 src/Types/GetState.ts create mode 100644 src/Types/Microtask.ts create mode 100644 src/Types/ModalState.ts create mode 100644 src/Types/NetworkState.ts create mode 100644 src/Types/NotificationState.ts create mode 100644 src/Types/OnboardingState.ts create mode 100644 src/Types/ReduxActions.ts create mode 100644 src/Types/Sleep/Fitbit.ts create mode 100644 src/Types/Sleep/Oura.ts create mode 100644 src/Types/Sleep/Withings.ts create mode 100644 src/Types/SleepClockState.ts create mode 100644 src/Types/Sleepdata.ts create mode 100644 src/Types/State.ts create mode 100644 src/Types/State/AuthState.ts create mode 100644 src/Types/State/ManualDataState.ts create mode 100644 src/Types/State/Periods.ts create mode 100644 src/Types/State/SleepDataSourceState.ts create mode 100644 src/Types/State/api-state.ts create mode 100644 src/Types/State/days-state.ts create mode 100644 src/Types/State/habit-state.ts create mode 100644 src/Types/State/insight-state.ts create mode 100644 src/Types/State/linking-state.ts create mode 100644 src/Types/SubscriptionState.ts create mode 100644 src/Types/TrackingState.ts create mode 100644 src/Types/UserState.ts create mode 100644 src/Types/generated/contentful.d.ts create mode 100644 src/Types/navigation/navigation.ts create mode 100644 src/actions/Cloud/Sleep.ts create mode 100644 src/actions/Cloud/User.ts create mode 100644 src/actions/CoachingNotification/CoachingNotificationActions.ts create mode 100644 src/actions/IntercomActions.ts create mode 100644 src/actions/MicrotaskActions.ts create mode 100644 src/actions/NotificationActions.ts create mode 100644 src/actions/RefreshActions.ts create mode 100644 src/actions/StartupActions.ts create mode 100644 src/actions/api-actions/fitbit-actions.ts create mode 100644 src/actions/api-actions/garmin-actions.ts create mode 100644 src/actions/api-actions/google-fit-actions.ts create mode 100644 src/actions/api-actions/oura-actions.ts create mode 100644 src/actions/api-actions/suunto-actions.ts create mode 100644 src/actions/api-actions/withings-actions.ts create mode 100644 src/actions/auth/auth-actions.ts create mode 100644 src/actions/calendar-actions/calendar-actions.ts create mode 100644 src/actions/challenges/challenge-actions.ts create mode 100644 src/actions/coaching/coaching-actions.ts create mode 100644 src/actions/coaching/coaching-to-cloud-actions.ts create mode 100644 src/actions/coaching/content-actions.ts create mode 100644 src/actions/habit/habit-actions.spec.ts create mode 100644 src/actions/habit/habit-actions.ts create mode 100644 src/actions/iOS/SleepDataActions.ts create mode 100644 src/actions/insight-actions/insight-actions.ts create mode 100644 src/actions/linking/linking-actions.ts create mode 100644 src/actions/manual-sleep/manual-sleep-actions.spec.ts create mode 100644 src/actions/manual-sleep/manual-sleep-actions.ts create mode 100644 src/actions/modal/modal-actions.spec.ts create mode 100644 src/actions/modal/modal-actions.ts create mode 100644 src/actions/onboarding/onboarding-actions.ts create mode 100644 src/actions/shared.ts create mode 100644 src/actions/sleep-source-actions/revoke-previous-source.ts create mode 100644 src/actions/sleep-source-actions/sleep-source-actions.ts create mode 100644 src/actions/sleep/health-kit-actions.ts create mode 100644 src/actions/sleep/sleep-data-actions.ts create mode 100644 src/actions/sleep/sleep-to-cloud-actions.ts create mode 100644 src/actions/subscription/subscription-actions.ts create mode 100644 src/actions/user/user-actions.ts create mode 100644 src/components/AnimatedFastImage/AnimatedFastImage.tsx create mode 100644 src/components/AnimatedSvgPath.tsx create mode 100644 src/components/AnimationComponents/AnimateDisplay.tsx create mode 100644 src/components/AuthSpecific/Disclaimer.tsx create mode 100644 src/components/BottomInfo.tsx create mode 100644 src/components/BottomTabSheet/BottomActionSheet.tsx create mode 100644 src/components/BottomTabSheet/BottomActionSheetContent.tsx create mode 100644 src/components/BottomTabSheet/BottomActionSheetHeader.tsx create mode 100644 src/components/Buttons/BackToAppButton.tsx create mode 100644 src/components/Buttons/BottomButton.tsx create mode 100644 src/components/Buttons/GoBack.tsx create mode 100644 src/components/Buttons/IconButton.tsx create mode 100644 src/components/Buttons/LinkingButton.tsx create mode 100644 src/components/Buttons/LoginButton.tsx create mode 100644 src/components/Buttons/PrimaryButton.tsx create mode 100644 src/components/Buttons/RatingButton.tsx create mode 100644 src/components/Buttons/ScalingButton.tsx create mode 100644 src/components/Buttons/SecondaryButton.tsx create mode 100644 src/components/Buttons/TerveystaloButton.tsx create mode 100644 src/components/Buttons/TextButton.tsx create mode 100644 src/components/Buttons/backButton.tsx create mode 100644 src/components/Card.tsx create mode 100644 src/components/Challenge/ChallengeItem.tsx create mode 100644 src/components/Charts/Axis.tsx create mode 100644 src/components/Charts/HeartRateChart.tsx create mode 100644 src/components/Charts/ProfileChart.tsx create mode 100644 src/components/Charts/SleepScoreGraph.tsx create mode 100644 src/components/Charts/SleepTimeChart/BottomInfo.tsx create mode 100644 src/components/Charts/SleepTimeChart/DayInfo.tsx create mode 100644 src/components/Charts/SleepTimeChart/SleepBars.tsx create mode 100644 src/components/Charts/SleepTimeChart/SleepTimeChartAverage.tsx create mode 100644 src/components/Charts/SleepTimeChart/XTicks.tsx create mode 100644 src/components/Charts/SleepTimeChart/YTicks.tsx create mode 100644 src/components/Charts/SleepTimesChart.tsx create mode 100644 src/components/Charts/sleepTimeChart.tsx create mode 100644 src/components/ChronotypeTest/Chronotype.tsx create mode 100644 src/components/ChronotypeTest/ChronotypeBox.tsx create mode 100644 src/components/ChronotypeTest/TestEnd.tsx create mode 100644 src/components/ChronotypeTest/TestStart.tsx create mode 100644 src/components/CoachingMonthCard/CoachingMonthCard.tsx create mode 100644 src/components/CoachingMonthCard/index.tsx create mode 100644 src/components/CoachingSpecific/Authors.tsx create mode 100644 src/components/CoachingSpecific/BuyCoachingButton.tsx create mode 100644 src/components/CoachingSpecific/CoachingHeader.tsx create mode 100644 src/components/CoachingSpecific/CoachingNotStarted.tsx create mode 100644 src/components/CoachingSpecific/CoachingSectionHeader.tsx create mode 100644 src/components/CoachingSpecific/Copyright.tsx create mode 100644 src/components/CoachingSpecific/IntroduceCoaching.tsx create mode 100644 src/components/CoachingSpecific/RefreshCoaching.tsx create mode 100644 src/components/CoachingSpecific/StartCoaching.tsx create mode 100644 src/components/CoachingSpecific/TopHeader.tsx create mode 100644 src/components/CoachingSpecific/Week.Cover.tsx create mode 100644 src/components/CoachingSpecific/WeekCard.tsx create mode 100644 src/components/CoachingSpecific/WeekCardTitle.tsx create mode 100644 src/components/CoachingSpecific/WeekCarousel.tsx create mode 100644 src/components/CoachingSpecific/WeekCompleted.tsx create mode 100644 src/components/CoachingSpecific/WeekIntro.tsx create mode 100644 src/components/CoachingSpecific/WeekSummary.tsx create mode 100644 src/components/CoachingSpecific/WeekViewHeader.tsx create mode 100644 src/components/CurrentCoaching.tsx create mode 100644 src/components/DayStrip.tsx create mode 100644 src/components/DetailView/SampleRow.tsx create mode 100644 src/components/ElegantAnimation.tsx create mode 100644 src/components/EmptyState.tsx create mode 100644 src/components/HabitCard/ActionComplete.tsx create mode 100644 src/components/HabitCard/ExampleHabit.tsx create mode 100644 src/components/HabitCard/HabitCard.tsx create mode 100644 src/components/HabitCard/HabitCardManage.tsx create mode 100644 src/components/HabitCard/TopRow.tsx create mode 100644 src/components/HabitList/HabitList.tsx create mode 100644 src/components/Header.tsx create mode 100644 src/components/IAPComponents/PerkList.spec.tsx create mode 100644 src/components/IAPComponents/PerkList.tsx create mode 100644 src/components/IAPComponents/SubscriptionItem.spec.tsx... create mode 100644 src/components/IAPComponents/SubscriptionItem.tsx create mode 100644 src/components/IAPComponents/__snapshots__/PerkList.spec.tsx.snap create mode 100644 src/components/InfoRow.tsx create mode 100644 src/components/Lesson/ExtraInfo.tsx create mode 100644 src/components/Lesson/LessonContent.tsx create mode 100644 src/components/Lesson/LessonCover.tsx create mode 100644 src/components/Lesson/RateLesson.tsx create mode 100644 src/components/LessonComponents/AuthorCard.tsx create mode 100644 src/components/LessonComponents/ExampleHabitSection.tsx create mode 100644 src/components/LessonComponents/LargeAuthorCard.tsx create mode 100644 src/components/LessonComponents/LessonListItem.tsx create mode 100644 src/components/LessonComponents/ReadingTime.tsx create mode 100644 src/components/LessonComponents/SectionFooter.tsx create mode 100644 src/components/LessonComponents/SectionHeader.tsx create mode 100644 src/components/LessonComponents/Separator.tsx create mode 100644 src/components/LessonComponents/Tags.tsx create mode 100644 src/components/LoadingAnimation.tsx create mode 100644 src/components/MainScreenSpecific/ClockCarousel.tsx create mode 100644 src/components/MainScreenSpecific/EditNightHeader.tsx create mode 100644 src/components/MainScreenSpecific/EnablePushCheck.tsx create mode 100644 src/components/MainScreenSpecific/Explanations.tsx create mode 100644 src/components/MainScreenSpecific/HelpInfo.tsx create mode 100644 src/components/MainScreenSpecific/InitializeSources.tsx create mode 100644 src/components/MainScreenSpecific/SomethingWrong.tsx create mode 100644 src/components/MainScreenSpecific/TodayView.tsx create mode 100644 src/components/MicrotaskComponents/AddMicrotask.tsx create mode 100644 src/components/MicrotaskComponents/HabitPageHeader.tsx create mode 100644 src/components/MicrotaskComponents/MicrotaskProgress.tsx create mode 100644 src/components/MicrotaskComponents/NoMicrotasks.tsx create mode 100644 src/components/MicrotaskRow.tsx create mode 100644 src/components/MySleepScore/MySleepScoreBadge.tsx create mode 100644 src/components/MySleepScore/SleepScoreSegment.tsx create mode 100644 src/components/NotificationCenter/NotificationCard.tsx create mode 100644 src/components/NotificationCenter/NotificationCenterLink.tsx create mode 100644 src/components/Primitives/Primitives.tsx create mode 100644 src/components/ProfileSpecific/Userinfo.tsx create mode 100644 src/components/RatingModal.tsx create mode 100644 src/components/RichText.tsx create mode 100644 src/components/ScrollView/InView.tsx create mode 100644 src/components/SettingsSpecific/CodeDisclaimer.tsx create mode 100644 src/components/SettingsSpecific/IntercomProfilePictures.tsx create mode 100644 src/components/SettingsSpecific/LinkModule.tsx create mode 100644 src/components/SettingsSpecific/NotificationRow.tsx create mode 100644 src/components/SettingsSpecific/SourceRow.tsx create mode 100644 src/components/SettingsSpecific/Sources/AddSources.tsx create mode 100644 src/components/SettingsSpecific/Sources/EnableSource.tsx create mode 100644 src/components/SettingsSpecific/Sources/GoogleFit.tsx create mode 100644 src/components/SettingsSpecific/Sources/LinkSource.tsx create mode 100644 src/components/SettingsSpecific/__tests__/SettingRow.spec.tsx create mode 100644 src/components/SettingsSpecific/__tests__/VersionInformation.test.tsx create mode 100644 src/components/SettingsSpecific/__tests__/__snapshots__/SettingRow.spec.tsx.snap create mode 100644 src/components/SettingsSpecific/__tests__/__snapshots__/VersionInformation.test.tsx.snap create mode 100644 src/components/SettingsSpecific/settingRow.tsx create mode 100644 src/components/SettingsSpecific/versionInformation.tsx create mode 100644 src/components/Signup/SignupBottomButton.tsx create mode 100644 src/components/Skeletons/SkeletonContent.tsx create mode 100644 src/components/SleepTarget/Overlays.tsx create mode 100644 src/components/SleepTarget/Scale.tsx create mode 100644 src/components/SleepTarget/Separator.tsx create mode 100644 src/components/SleepTarget/SleepTarget.tsx create mode 100644 src/components/SleepTarget/StartModal.tsx create mode 100644 src/components/SvgIcon.tsx create mode 100644 src/components/Switch/Switch.tsx create mode 100644 src/components/TabBarIcon.tsx create mode 100644 src/components/TabBarLabel.tsx create mode 100644 src/components/TextField.tsx create mode 100644 src/components/TextIndicator/TextLengthIndicator.tsx create mode 100644 src/components/Timeline/Timeline.tsx create mode 100644 src/components/TinyCard.tsx create mode 100644 src/components/TopInfo.tsx create mode 100644 src/components/TranslatedText.tsx create mode 100644 src/components/__tests__/Card.test.tsx create mode 100644 src/components/__tests__/IconBold.test.tsx create mode 100644 src/components/__tests__/SvgIcon.test.tsx create mode 100644 src/components/__tests__/TopInfo.test.tsx create mode 100644 src/components/__tests__/TranslatedText.test.tsx create mode 100644 src/components/__tests__/__snapshots__/Card.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/IconBold.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/SvgIcon.test.tsx.snap create mode 100644 src/components/__tests__/__snapshots__/TranslatedText.test.tsx.snap create mode 100644 src/components/animationContainer.tsx create mode 100644 src/components/iconBold.tsx create mode 100644 src/components/iconRegular.tsx create mode 100644 src/components/modals/AskAboutDataModal.tsx create mode 100644 src/components/modals/AskAboutDataModal/GoogleFit.tsx create mode 100644 src/components/modals/AskAboutDataModal/HealthKit.tsx create mode 100644 src/components/modals/AskAboutDataModal/PushNotification.tsx create mode 100644 src/components/modals/AskAboutDataModal/SelectSource.tsx create mode 100644 src/components/modals/CloseModalButton.tsx create mode 100644 src/components/modals/ExplanationsModal.tsx create mode 100644 src/components/modals/HabitModal/EditHabitModal.tsx create mode 100644 src/components/modals/HabitModal/HabitModalFieldSection.tsx create mode 100644 src/components/modals/HabitModal/HabitModalStreak.tsx create mode 100644 src/components/modals/HabitModal/HabitModalTimeSection.tsx create mode 100644 src/components/modals/HabitModal/HabitModalTopInfo.tsx create mode 100644 src/components/modals/HabitModal/HabitModalTopRow.tsx create mode 100644 src/components/modals/HabitModal/NewHabitModal.tsx create mode 100644 src/components/modals/HabitModal/SetTimePeriodButtons.tsx create mode 100644 src/components/modals/MergeHabitsModal/MergeHabitsModal.tsx create mode 100644 src/components/modals/MergeHabitsModal/index.tsx create mode 100644 src/components/modals/MySleepScoreModal.tsx create mode 100644 src/components/modals/setSleepGoal.tsx create mode 100644 src/components/scpath.tsx create mode 100644 src/components/sleepClock/CircularSlider.tsx create mode 100644 src/components/sleepClock/ClockEmpty.tsx create mode 100644 src/components/sleepClock/CoachingProgressToday.tsx create mode 100644 src/components/sleepClock/CurrentTime.tsx create mode 100644 src/components/sleepClock/Cursor.tsx create mode 100644 src/components/sleepClock/CurvedActions.tsx create mode 100644 src/components/sleepClock/CurvedEditButton.tsx create mode 100644 src/components/sleepClock/Date.tsx create mode 100644 src/components/sleepClock/EditableArc.tsx create mode 100644 src/components/sleepClock/FallAsleepWindow.tsx create mode 100644 src/components/sleepClock/InfoButton.tsx create mode 100644 src/components/sleepClock/MinuteSticks.tsx create mode 100644 src/components/sleepClock/NightRating.tsx create mode 100644 src/components/sleepClock/NoDataInfo.tsx create mode 100644 src/components/sleepClock/SleepArc.tsx create mode 100644 src/components/sleepClock/SleepTime.tsx create mode 100644 src/components/sleepClock/SleepTimesArc.tsx create mode 100644 src/components/sleepClock/Slider.tsx create mode 100644 src/components/sleepClock/TimePath.tsx create mode 100644 src/components/sleepClock/TimerText.tsx create mode 100644 src/components/sleepClock/TrackerName.tsx create mode 100644 src/components/sleepClock/clockTimes.tsx create mode 100644 src/components/sleepclock.tsx create mode 100644 src/components/sources/FitbitSection.tsx create mode 100644 src/components/sources/GoogleFitSection.tsx create mode 100644 src/components/sources/HealthKitSection.tsx create mode 100644 src/components/sources/OuraSection.tsx create mode 100644 src/components/sources/WithingsSection.tsx create mode 100644 src/components/subscriptions/SubscriptionCard.tsx create mode 100644 src/config/Amplify.ts create mode 100644 src/config/AppNavigation.tsx create mode 100644 src/config/Config.ts create mode 100644 src/config/NavigationHelper.ts create mode 100644 src/config/PushNotifications.ts create mode 100644 src/config/Validation.ts create mode 100644 src/config/i18n.ts create mode 100644 src/config/routes/AuthNavigator.tsx create mode 100644 src/config/routes/IntroductionNavigator.tsx create mode 100644 src/config/routes/JournalNavigator.tsx create mode 100644 src/config/routes/RootNavigator.tsx create mode 100644 src/config/routes/Routes.ts create mode 100644 src/config/routes/TabNavigator.tsx create mode 100644 src/config/routes/coachingNavigator.tsx create mode 100644 src/config/routes/profileNavigator.tsx create mode 100644 src/config/routes/settingsNavigator.tsx create mode 100644 src/graphql/custom/mutations.ts create mode 100644 src/graphql/custom/queries.ts create mode 100644 src/graphql/mutations.ts create mode 100644 src/graphql/queries.ts create mode 100644 src/graphql/subscriptions.ts create mode 100644 src/helpers/Dimensions.ts create mode 100644 src/helpers/Fonts.ts create mode 100644 src/helpers/GetPathFromState.tsx create mode 100644 src/helpers/KeyExtractor.ts create mode 100644 src/helpers/KeyboardEvents.ts create mode 100644 src/helpers/Measure.tsx create mode 100644 src/helpers/SleepScoreCalculators.ts create mode 100644 src/helpers/animated.tsx create mode 100644 src/helpers/geometry.ts create mode 100644 src/helpers/habits.ts create mode 100644 src/helpers/rating.ts create mode 100644 src/helpers/reading-time.ts create mode 100644 src/helpers/serializeTransform.ts create mode 100644 src/helpers/sleep.ts create mode 100644 src/helpers/sleep/fitbit-helper.spec.ts create mode 100644 src/helpers/sleep/fitbit-helper.ts create mode 100644 src/helpers/sleep/google-fit-helper.ts create mode 100644 src/helpers/sleep/oura-helper.ts create mode 100644 src/helpers/sleep/sleep-data-helper.spec.ts create mode 100644 src/helpers/sleep/sleep-data-helper.ts create mode 100644 src/helpers/sleep/withings-helper.ts create mode 100644 src/helpers/snapshot.tsx create mode 100644 src/helpers/time.ts create mode 100644 src/mockData/fitbit.ts create mode 100644 src/screens/Auth/ConfirmUser.tsx create mode 100644 src/screens/Auth/ForgotPasswordScreen.tsx create mode 100644 src/screens/Auth/Login.tsx create mode 100644 src/screens/Auth/RecoverPassword.tsx create mode 100644 src/screens/Auth/RegisterScreen.tsx create mode 100644 src/screens/Introduction/Introduction.tsx create mode 100644 src/screens/Introduction/Mockups/HealthKit.tsx create mode 100644 src/screens/Introduction/Mockups/Notification.tsx create mode 100644 src/screens/Introduction/Mockups/SleepBetter.tsx create mode 100644 src/screens/Introduction/Mockups/iPhone.tsx create mode 100644 src/screens/Introduction/Slide.tsx create mode 100644 src/screens/Shared/HabitView.tsx create mode 100644 src/screens/Terveystalo/Welcome.tsx create mode 100644 src/screens/Welcome/Welcome.tsx create mode 100644 src/screens/coaching/CoachingView.tsx create mode 100644 src/screens/coaching/LessonView.tsx create mode 100644 src/screens/coaching/Lessons.tsx create mode 100644 src/screens/coaching/MicroTasks.tsx create mode 100644 src/screens/coaching/PurchaseView.tsx create mode 100644 src/screens/coaching/WeekView.tsx create mode 100644 src/screens/coaching/challenges.tsx create mode 100644 src/screens/main/DetailView.tsx create mode 100644 src/screens/main/LegendView.tsx create mode 100644 src/screens/main/NotificationCenter.tsx create mode 100644 src/screens/main/components/LastUpdated.tsx create mode 100644 src/screens/main/components/batteryInformation.tsx create mode 100644 src/screens/main/components/dayTitle.tsx create mode 100644 src/screens/main/main.tsx create mode 100644 src/screens/profile/BedStatsView.tsx create mode 100644 src/screens/profile/ChallengeView.tsx create mode 100644 src/screens/profile/LoginOrRegister.tsx create mode 100644 src/screens/profile/SleepStatsView.tsx create mode 100644 src/screens/profile/achievement.tsx create mode 100644 src/screens/profile/profile.tsx create mode 100644 src/screens/settings/CloudSettings.tsx create mode 100644 src/screens/settings/CoachingSettings.tsx create mode 100644 src/screens/settings/DevelopmentMenu.tsx create mode 100644 src/screens/settings/ManageSubscription.tsx create mode 100644 src/screens/settings/Notifications.tsx create mode 100644 src/screens/settings/SourceSettings.tsx create mode 100644 src/screens/settings/settings.tsx create mode 100644 src/store/CustomAuthStorage.ts create mode 100644 src/store/InitialStates/SleepClock.ts create mode 100644 src/store/InitialStates/days.ts create mode 100644 src/store/Reducers/CoachingProfileReducer.ts create mode 100644 src/store/Reducers/NotificationReducer.ts create mode 100644 src/store/Reducers/TrackingReducer.ts create mode 100644 src/store/Reducers/api-reducer/api-reducer.spec.ts create mode 100644 src/store/Reducers/api-reducer/api-reducer.ts create mode 100644 src/store/Reducers/auth-reducer/auth-reducer.spec.ts create mode 100644 src/store/Reducers/auth-reducer/auth-reducer.ts create mode 100644 src/store/Reducers/calendar-reducer/calendar-reducer.ts create mode 100644 src/store/Reducers/challenges/challenge-reducer.ts create mode 100644 src/store/Reducers/coaching-reducer/coaching-reducer.ts create mode 100644 src/store/Reducers/content-reducer/content-reducer.ts create mode 100644 src/store/Reducers/habit-reducer/habit-reducer.ts create mode 100644 src/store/Reducers/insight-reducer/insight-reducer.ts create mode 100644 src/store/Reducers/journal-view/journal-view-reducer.ts create mode 100644 src/store/Reducers/linking/linking-reducer.ts create mode 100644 src/store/Reducers/manual-sleep/manual-sleep-reducer.ts create mode 100644 src/store/Reducers/modal/modal-reducer.spec.ts create mode 100644 src/store/Reducers/modal/modal-reducer.ts create mode 100644 src/store/Reducers/notifications/coaching-notification-reducer.spec.ts create mode 100644 src/store/Reducers/notifications/coaching-notifications-reducer.ts create mode 100644 src/store/Reducers/onboarding/onboard-reducer.spec.ts create mode 100644 src/store/Reducers/onboarding/onboarding-reducer.ts create mode 100644 src/store/Reducers/sleep-source-reducer/sleep-source-reducer.ts create mode 100644 src/store/Reducers/sleep-store/local-sleep-reducer.ts create mode 100644 src/store/Reducers/sleep-store/sleep-store-reducer.ts create mode 100644 src/store/Reducers/sleep/health-kit-reducer.ts create mode 100644 src/store/Reducers/sleepclockReducer.ts create mode 100644 src/store/Reducers/subscription/subscription-reducer.spec.ts create mode 100644 src/store/Reducers/subscription/subscription-reducer.ts create mode 100644 src/store/Reducers/user/user-reducer.spec.ts create mode 100644 src/store/Reducers/user/user-reducer.ts create mode 100644 src/store/Selectors/ChallengeSelectors.ts create mode 100644 src/store/Selectors/ManualDataSelectors.ts create mode 100644 src/store/Selectors/MicrotaskSelectors.ts create mode 100644 src/store/Selectors/ModalSelectors.ts create mode 100644 src/store/Selectors/NotificationSelectors.ts create mode 100644 src/store/Selectors/OnboardingSelectors.ts create mode 100644 src/store/Selectors/SleepDataSelectors.ts create mode 100644 src/store/Selectors/SmartActionsSelectors.ts create mode 100644 src/store/Selectors/TrackingSelectors.ts create mode 100644 src/store/Selectors/UserSelectors.ts create mode 100644 src/store/Selectors/api-selectors/api-selectors.ts create mode 100644 src/store/Selectors/auth-selectors/auth-selectors.ts create mode 100644 src/store/Selectors/coaching-selectors/coaching-selectors.ts create mode 100644 src/store/Selectors/coaching-selectors/index.ts create mode 100644 src/store/Selectors/content-selectors/content-selectors.ts create mode 100644 src/store/Selectors/habit-selectors/habit-selectors.spec.ts create mode 100644 src/store/Selectors/habit-selectors/habit-selectors.ts create mode 100644 src/store/Selectors/health-kit-selectors/health-kit-selectors.ts create mode 100644 src/store/Selectors/insight-selectors/Insights.ts create mode 100644 src/store/Selectors/linking-selectors/index.ts create mode 100644 src/store/Selectors/notification-selectors/notification-selectors.ts create mode 100644 src/store/Selectors/sleep-source-selectors/sleep-source-selectors.ts create mode 100644 src/store/Selectors/subscription-selectors/SubscriptionSelectors.ts create mode 100644 src/store/index.ts create mode 100644 src/styles/colors.ts create mode 100644 src/styles/styled-components.ts create mode 100644 src/styles/styled.d.ts create mode 100644 src/styles/themes.ts create mode 100644 src/translations/en.json create mode 100644 src/translations/fi.json create mode 100644 src/typings/@react-native-community/segmented-control.d.ts create mode 100644 src/typings/Initials.d.ts create mode 100644 src/typings/aws-exports.d.ts create mode 100644 src/typings/react-navigation.d.ts create mode 100644 src/typings/state/coaching-state.ts create mode 100644 src/typings/state/health-kit-state.ts create mode 100644 src/typings/state/sleep-source-state.ts create mode 100644 src/typings/svg.t.ts create mode 100644 tsconfig.jest.json create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..1ae6dfb --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,62 @@ +module.exports = { + parser: '@typescript-eslint/parser', + env: { + browser: true, + es6: true, + jest: true, + node: true, + 'react-native/react-native': true + }, + extends: [ + 'plugin:react/recommended', + 'airbnb', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'prettier' + ], + plugins: ['react', 'react-native', '@typescript-eslint', 'prettier'], + ignorePatterns: ['node_modules/'], + parserOptions: { + ecmaFeatures: { + jsx: true + } + }, + rules: { + semi: [2, 'never'], + 'comma-dangle': 'off', + 'max-len': ['error', { ignoreComments: true, code: 120, ignoreStrings: true }], + 'prettier/prettier': ['error'], + 'import/no-unresolved': 'off', + 'import/prefer-default-export': 'off', + 'import/extensions': 'off', + 'no-use-before-define': 'off', + 'import/no-extraneous-dependencies': 'off', // FIXME: exclude test files + 'react/prop-types': 'off', + 'react/jsx-filename-extension': 'off', + 'react/jsx-one-expression-per-line': 'off', + 'react/jsx-props-no-spreading': 'off', + 'react-native/no-unused-styles': 'error', + 'react-native/split-platform-components': 'error', + 'react/jsx-closing-bracket-location': 'after-props', + 'react-native/no-inline-styles': 'error', + 'react-native/no-color-literals': 'error', + 'react/jsx-closing-bracket-location': 'off', + 'react/require-default-props': 'off', + 'react-native/no-raw-text': 'off', // This does not currently work with styled components + 'react-native/no-single-element-style-arrays': 'error', + '@typescript-eslint/explicit-function-return-type': 'off', + + '@typescript-eslint/member-delimiter-style': ['error', { multiline: { delimiter: 'none' } }], + 'react/jsx-wrap-multilines': ['error', { declaration: false, assignment: false }] + }, + settings: { + 'import/resolver': { + 'babel-module': {} + }, + react: { + version: 'detect' + } + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d42ff18 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4914b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,128 @@ +# 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 +ios/builds/ +ios/build/ +ios/Vendor +ios/Pods +ios/sentry.properties +ios/Intercom.framework +ios/fastlane/ +ios/GoogleService-Info +ios/AppCenter-Config.plist + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +android/app/src/main/res/raw/ +raw +android/keystores/ +android/app/src/main/res +android/fastlane +android/app/src/main/assets/ +android/app/src/main/resources/ +android/app/client_secret.json +android/fastlane/ + + +# fastlane specific +fastlane/report.xml + + +# deliver temporary files +fastlane/Preview.html + +# snapshot generated screenshots +fastlane/screenshots + +# scan temporary files +fastlane/test_output + +# Fastlane builds +builds/* + +# node.js +# +node_modules/ +.jest/ +npm-debug.log +yarn-error.log +coverage + +# BUCK +buck-out/ +\.buckd/ +*.keystore +!debug.keystore + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +*/fastlane/report.xml +*/fastlane/Preview.html +*/fastlane/screenshots + +# Bundle artifact +*.jsbundle + +# CocoaPods +ios/Pods/ + +#amplify +amplify/\#current-cloud-backend +amplify/.config/local-* +amplify/mock-data +amplify/backend/amplify-meta.json +amplify/backend/awscloudformation +amplify/team-provider-info.json +build/ +dist/ +aws-exports.js +awsconfiguration.json +amplifyconfiguration.json +amplify-gradle-config.json +amplifyxc.config +amplify/backend + +.secrets +.env +sentry.properties +android/.project +android/debug.keystore +android/.settings/org.eclipse.buildship.core.prefs +ios/Nyxo/GoogleService-Info.plist +android/app/google-services.json +android/app/.settings/org.eclipse.jdt.core.prefs +android/app/.settings/org.eclipse.buildship.core.prefs +ios/Nyxo/AppCenter-Config.plist +rnuc.xcconfig +android/app/.project diff --git a/.graphqlconfig.yml b/.graphqlconfig.yml new file mode 100644 index 0000000..c614e45 --- /dev/null +++ b/.graphqlconfig.yml @@ -0,0 +1,18 @@ +projects: + nyxoDev: + schemaPath: amplify/backend/api/nyxoDev/build/schema.graphql + includes: + - src/graphql/**/*.ts + excludes: + - ./amplify/** + extensions: + amplify: + codeGenTarget: typescript + generatedFileName: src/API.ts + docsFilePath: src/graphql + region: eu-central-1 + apiId: null + maxDepth: 2 +extensions: + amplify: + version: 3 diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..3f7a5b4 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,8 @@ +module.exports = { + trailingComma: 'none', + tabWidth: 2, + singleQuote: true, + printWidth: 80, + semi: false, + jsxBracketSameLine: true +} diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2e92df --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Nyxo App + +[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) + +## + +## Getting started + +_Clone repository_ + +```shell +git clone +cd nyxo-app +yarn +``` + +### Setting up enviroment variables + +Nyxo configurations keys are placed in config.ts file, which then references the requirement enviroment variables from local `.env`file. + +## Troubleshooting + +#### main.jsbundle missing + +Run command `react-native bundle --entry-file index.js --platform ios --dev=false --bundle-output ios/main.jsbundle --assets-dest ios` for iOS +Run command `react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/` for Android + +## When you get a weird Xcode error about undefined symbols + +If you see something like this: + +`Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_RCTReconnectingWebSocket", referenced from: objc-class-ref in libReact.a(RCTPackagerConnection.o) ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)` + +Delete your Derived data + +## Resetting bundlers etc. + +1. Clear watchman watches: `watchman watch-del-all`. +2. Delete the `node_modules` folder: `rm -rf node_modules && npm install`. +3. Reset Metro Bundler cache: `rm -rf /tmp/metro-bundler-cache-*` or `npm start -- --reset-cache`. +4. Remove haste cache: `rm -rf /tmp/haste-map-react-native-packager-*`. diff --git a/__mocks__/@react-native-community/push-notification-ios.ts b/__mocks__/@react-native-community/push-notification-ios.ts new file mode 100644 index 0000000..01f9cd5 --- /dev/null +++ b/__mocks__/@react-native-community/push-notification-ios.ts @@ -0,0 +1,7 @@ +jest.mock('@react-native-community/push-notification-ios', () => ({ + configure: jest.fn(), + onRegister: jest.fn(), + onNotification: jest.fn(), + addEventListener: jest.fn(), + requestPermissions: jest.fn() +})) diff --git a/__mocks__/@sentry/react-native.ts b/__mocks__/@sentry/react-native.ts new file mode 100644 index 0000000..394b242 --- /dev/null +++ b/__mocks__/@sentry/react-native.ts @@ -0,0 +1,5 @@ +jest.mock('@sentry/react-native', () => ({ + setTagsContext: jest.fn(), + setExtraContext: jest.fn(), + captureBreadcrumb: jest.fn() +})) diff --git a/__mocks__/appcenter-analytics.ts b/__mocks__/appcenter-analytics.ts new file mode 100644 index 0000000..585e4cc --- /dev/null +++ b/__mocks__/appcenter-analytics.ts @@ -0,0 +1,6 @@ +jest.mock('appcenter-analytics', () => ({ + trackEvent: jest.fn(), + removeEventListener: jest.fn(), + requestPermissions: jest.fn(), + configure: jest.fn() +})) diff --git a/__mocks__/appcenter-push.ts b/__mocks__/appcenter-push.ts new file mode 100644 index 0000000..43a147f --- /dev/null +++ b/__mocks__/appcenter-push.ts @@ -0,0 +1,6 @@ +jest.mock('appcenter-push', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + requestPermissions: jest.fn(), + configure: jest.fn() +})) diff --git a/__mocks__/aws-amplify.ts b/__mocks__/aws-amplify.ts new file mode 100644 index 0000000..624d01f --- /dev/null +++ b/__mocks__/aws-amplify.ts @@ -0,0 +1,5 @@ +export const Auth = { + currentSession: jest.fn(() => Promise.resolve()), + signIn: jest.fn(() => Promise.resolve()), + signOut: jest.fn(() => Promise.resolve()) +} diff --git a/__mocks__/chroma-js.ts b/__mocks__/chroma-js.ts new file mode 100644 index 0000000..4df3a48 --- /dev/null +++ b/__mocks__/chroma-js.ts @@ -0,0 +1,17 @@ +// jest.mock('chroma-js', () => ({ +// default: () => {}, +// })); + +// jest.mock('chroma-js', () => ({ +// addEventListener: jest.fn(), +// removeEventListener: jest.fn(), +// requestPermissions: jest.fn(), +// default: jest.fn(), +// hex: jest.fn(), +// alpha: jest.fn(), +// })); + +// @ts-ignore +const chroma = require('chroma-js').default + +module.exports = chroma diff --git a/__mocks__/i18n-js.ts b/__mocks__/i18n-js.ts new file mode 100644 index 0000000..9a246be --- /dev/null +++ b/__mocks__/i18n-js.ts @@ -0,0 +1,17 @@ +// jest.mock('i18n-js', () => ({ +// I18n: { +// locale: {}, +// fallbacks: true, +// translations: {}, +// currentLocale: () => {}, +// }, +// })); + +// jest.mock('i18n-js', () => ({ +// currentLocale: jest.fn(() => 'en'), +// })); + +const I18n = require('i18n-js') + +jest.genMockFromModule('i18n-js') +module.exports = I18n diff --git a/__mocks__/moment.ts b/__mocks__/moment.ts new file mode 100644 index 0000000..b52ee32 --- /dev/null +++ b/__mocks__/moment.ts @@ -0,0 +1,5 @@ +const moment = jest.requireActual('moment') + +export default (timestamp: string | 0 = 0) => { + return moment(timestamp) +} diff --git a/__mocks__/prop-types.ts b/__mocks__/prop-types.ts new file mode 100644 index 0000000..b999b1c --- /dev/null +++ b/__mocks__/prop-types.ts @@ -0,0 +1,5 @@ +jest.mock('prop-types', () => ({ + PropTypes: { + node: {} + } +})) diff --git a/__mocks__/react-native-app-auth.ts b/__mocks__/react-native-app-auth.ts new file mode 100644 index 0000000..1e26378 --- /dev/null +++ b/__mocks__/react-native-app-auth.ts @@ -0,0 +1,6 @@ +jest.mock('react-native-app-auth', () => ({ + authorize: jest.fn(), + register: jest.fn(), + revoke: jest.fn(), + refresh: jest.fn() +})) diff --git a/__mocks__/react-native-code-push.ts b/__mocks__/react-native-code-push.ts new file mode 100644 index 0000000..7e023c3 --- /dev/null +++ b/__mocks__/react-native-code-push.ts @@ -0,0 +1,8 @@ +const codePush = { + InstallMode: { ON_NEXT_RESTART: 'ON_APP_RESTART' }, + CheckFrequency: { ON_APP_RESUME: 'ON_APP_RESUME' } +} + +const cb = (_: any) => (app: any) => app +Object.assign(cb, codePush) +export default cb diff --git a/__mocks__/react-native-firebase.ts b/__mocks__/react-native-firebase.ts new file mode 100644 index 0000000..ac020ad --- /dev/null +++ b/__mocks__/react-native-firebase.ts @@ -0,0 +1,28 @@ +const firebase = { + messaging: jest.fn(() => ({ + hasPermission: jest.fn(() => Promise.resolve(true)), + subscribeToTopic: jest.fn(), + unsubscribeFromTopic: jest.fn(), + requestPermission: jest.fn(() => Promise.resolve(true)), + getToken: jest.fn(() => Promise.resolve('myMockToken')), + onTokenRefresh: jest.fn(() => Promise.resolve('myMockToken')) + })), + notifications: jest.fn(() => ({ + onNotification: jest.fn(), + onNotificationDisplayed: jest.fn(), + android: { + createChannel: jest.fn() + } + })) +} + +firebase.notifications.Android = { + Channel: jest.fn(() => ({ + setDescription: jest.fn() + })), + Importance: { + Max: {} + } +} + +export default firebase diff --git a/__mocks__/react-native-gesture-handler.ts b/__mocks__/react-native-gesture-handler.ts new file mode 100644 index 0000000..bc0f196 --- /dev/null +++ b/__mocks__/react-native-gesture-handler.ts @@ -0,0 +1,13 @@ +jest.mock('NativeModules', () => ({ + UIManager: { + RCTView: () => {} + }, + RNGestureHandlerModule: { + attachGestureHandler: jest.fn(), + createGestureHandler: jest.fn(), + dropGestureHandler: jest.fn(), + updateGestureHandler: jest.fn(), + State: {}, + Directions: {} + } +})) diff --git a/__mocks__/react-native-get-random-values.ts b/__mocks__/react-native-get-random-values.ts new file mode 100644 index 0000000..51d672d --- /dev/null +++ b/__mocks__/react-native-get-random-values.ts @@ -0,0 +1,3 @@ +jest.mock('react-native-get-random-values', () => ({ + RNGetRandomValues: jest.fn() +})) diff --git a/__mocks__/react-native-healthkit.ts b/__mocks__/react-native-healthkit.ts new file mode 100644 index 0000000..bca6997 --- /dev/null +++ b/__mocks__/react-native-healthkit.ts @@ -0,0 +1,14 @@ +import { AppleHealthKit } from 'react-native-healthkit' + +jest.mock('react-native-healthkit', () => ({ + Constants: { + Permissions: {} + }, + AppleHealthKit: { + Constants: { + Permissions: {} + } + } +})) + +export default AppleHealthKit diff --git a/__mocks__/react-native-iap.ts b/__mocks__/react-native-iap.ts new file mode 100644 index 0000000..c94b422 --- /dev/null +++ b/__mocks__/react-native-iap.ts @@ -0,0 +1,6 @@ +jest.mock('react-native-iap', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + requestPermissions: jest.fn(), + configure: jest.fn() +})) diff --git a/__mocks__/react-native-intercom.ts b/__mocks__/react-native-intercom.ts new file mode 100644 index 0000000..092e7df --- /dev/null +++ b/__mocks__/react-native-intercom.ts @@ -0,0 +1,6 @@ +jest.mock('react-native-intercom', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + requestPermissions: jest.fn(), + configure: jest.fn() +})) diff --git a/__mocks__/react-native-iphone-x-helper.ts b/__mocks__/react-native-iphone-x-helper.ts new file mode 100644 index 0000000..73676f7 --- /dev/null +++ b/__mocks__/react-native-iphone-x-helper.ts @@ -0,0 +1,4 @@ +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + isIphoneX: () => true +})) diff --git a/__mocks__/react-native-localize.ts b/__mocks__/react-native-localize.ts new file mode 100644 index 0000000..f0c9315 --- /dev/null +++ b/__mocks__/react-native-localize.ts @@ -0,0 +1,44 @@ +// __mocks__/react-native-localize.js + +const getLocales = () => [ + // you can choose / add the locales you want + { countryCode: 'US', languageTag: 'en-US', languageCode: 'en', isRTL: false }, + { countryCode: 'FR', languageTag: 'fr-FR', languageCode: 'fr', isRTL: false } +] + +// use a provided translation, or return undefined to test your fallback +const findBestAvailableLanguage = () => ({ + languageTag: 'en-US', + isRTL: false +}) + +const getNumberFormatSettings = () => ({ + decimalSeparator: '.', + groupingSeparator: ',' +}) + +const getCalendar = () => 'gregorian' // or "japanese", "buddhist" +const getCountry = () => 'US' // the country code you want +const getCurrencies = () => ['USD', 'EUR'] // can be empty array +const getTemperatureUnit = () => 'celsius' // or "fahrenheit" +const getTimeZone = () => 'Europe/Paris' // the timezone you want +const uses24HourClock = () => true +const usesMetricSystem = () => true + +const addEventListener = jest.fn() +const removeEventListener = jest.fn() + +export { + findBestAvailableLanguage, + getLocales, + getNumberFormatSettings, + getCalendar, + getCountry, + getCurrencies, + getTemperatureUnit, + getTimeZone, + uses24HourClock, + usesMetricSystem, + addEventListener, + removeEventListener +} diff --git a/__mocks__/react-native-purchases.ts b/__mocks__/react-native-purchases.ts new file mode 100644 index 0000000..5855eb8 --- /dev/null +++ b/__mocks__/react-native-purchases.ts @@ -0,0 +1,31 @@ +jest.mock('react-native-purchases', () => ({ + setupPurchases: jest.fn(), + setAllowSharingStoreAccount: jest.fn(), + addAttributionData: jest.fn(), + getOfferings: jest.fn(), + getProductInfo: jest.fn(), + makePurchase: jest.fn(), + restoreTransactions: jest.fn(), + getAppUserID: jest.fn(), + createAlias: jest.fn(), + identify: jest.fn(), + setDebugLogsEnabled: jest.fn(), + getPurchaserInfo: jest.fn(), + reset: jest.fn(), + syncPurchases: jest.fn(), + setFinishTransactions: jest.fn(), + purchaseProduct: jest.fn(), + purchasePackage: jest.fn(), + isAnonymous: jest.fn(), + makeDeferredPurchase: jest.fn(), + checkTrialOrIntroductoryPriceEligibility: jest.fn(), + purchaseDiscountedPackage: jest.fn(), + purchaseDiscountedProduct: jest.fn(), + getPaymentDiscount: jest.fn(), + invalidatePurchaserInfoCache: jest.fn(), + setAttributes: jest.fn(), + setEmail: jest.fn(), + setPhoneNumber: jest.fn(), + setDisplayName: jest.fn(), + setPushToken: jest.fn() +})) diff --git a/__mocks__/react-native-reanimated.ts b/__mocks__/react-native-reanimated.ts new file mode 100644 index 0000000..aaba6be --- /dev/null +++ b/__mocks__/react-native-reanimated.ts @@ -0,0 +1,3 @@ +jest.mock('react-native-reanimated', () => + require('react-native-reanimated/mock') +) diff --git a/__mocks__/react-native-splash-screen.ts b/__mocks__/react-native-splash-screen.ts new file mode 100644 index 0000000..a2bdb52 --- /dev/null +++ b/__mocks__/react-native-splash-screen.ts @@ -0,0 +1,5 @@ +// __mocks__/react-native-splash-screen.ts +export default { + show: jest.fn().mockImplementation(() => {}), + hide: jest.fn().mockImplementation(() => {}) +} diff --git a/__mocks__/react-native-svg.ts b/__mocks__/react-native-svg.ts new file mode 100644 index 0000000..ed1f6ec --- /dev/null +++ b/__mocks__/react-native-svg.ts @@ -0,0 +1,61 @@ +// https://github.com/FormidableLabs/react-native-svg-mock +import * as React from 'react' + +const createComponent = function (name: string) { + return class extends React.Component { + // overwrite the displayName, since this is a class created dynamically + static displayName = name + + render() { + return React.createElement(name, this.props, this.props.children) + } + } +} + +// Mock all react-native-svg exports +// from https://github.com/magicismight/react-native-svg/blob/master/index.js +const Svg = createComponent('Svg') +const Circle = createComponent('Circle') +const Ellipse = createComponent('Ellipse') +const G = createComponent('G') +const Text = createComponent('Text') +const TextPath = createComponent('TextPath') +const TSpan = createComponent('TSpan') +const Path = createComponent('Path') +const Polygon = createComponent('Polygon') +const Polyline = createComponent('Polyline') +const Line = createComponent('Line') +const Rect = createComponent('Rect') +const Use = createComponent('Use') +const Image = createComponent('Image') +const Symbol = createComponent('Symbol') +const Defs = createComponent('Defs') +const LinearGradient = createComponent('LinearGradient') +const RadialGradient = createComponent('RadialGradient') +const Stop = createComponent('Stop') +const ClipPath = createComponent('ClipPath') + +export { + Svg, + Circle, + Ellipse, + G, + Text, + TextPath, + TSpan, + Path, + Polygon, + Polyline, + Line, + Rect, + Use, + Image, + Symbol, + Defs, + LinearGradient, + RadialGradient, + Stop, + ClipPath +} + +export default Svg diff --git a/__mocks__/react-native.ts b/__mocks__/react-native.ts new file mode 100644 index 0000000..5f1c6b4 --- /dev/null +++ b/__mocks__/react-native.ts @@ -0,0 +1,47 @@ +jest.mock('react-native', () => ({ + StyleSheet: { + hairlineWidth: 1, + create: () => ({}), + flatten(arr: any) { + return arr.reduce((res: any, item: any) => Object.assign(res, item), {}) + } + }, + Platform: { + OS: jest.fn(() => 'android'), + version: jest.fn(() => 25) + }, + Dimensions: { + get: () => { + return { width: 100, height: 200 } + } + }, + I18nManager: { + isRTL: false + }, + NativeModules: { + RNDocumentPicker: () => {}, + RNSentry: () => jest.fn() + }, + + Easing: { + bezier: () => {} + }, + View: () => 'View', + ViewPropTypes: { + propTypes: { + style: {} + } + }, + Text: () => 'Text', + TouchableNativeFeedback: () => 'TouchableNativeFeedback', + TouchableOpacity: () => 'TouchableOpacity', + + TouchableWithoutFeedback: () => 'TouchableWithoutFeedback', + Animated: { + View: () => 'Animated.View', + interpolate: jest.fn(), + Value: jest.fn().mockImplementation(() => { + return { interpolate: jest.fn() } + }) + } +})) diff --git a/__mocks__/react-redux.ts b/__mocks__/react-redux.ts new file mode 100644 index 0000000..092e7df --- /dev/null +++ b/__mocks__/react-redux.ts @@ -0,0 +1,6 @@ +jest.mock('react-native-intercom', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + requestPermissions: jest.fn(), + configure: jest.fn() +})) diff --git a/amplify/.config/project-config.json b/amplify/.config/project-config.json new file mode 100644 index 0000000..4e397ac --- /dev/null +++ b/amplify/.config/project-config.json @@ -0,0 +1,17 @@ +{ + "providers": [ + "awscloudformation" + ], + "projectName": "Nyxo-Cloud", + "version": "3.0", + "frontend": "javascript", + "javascript": { + "framework": "react-native", + "config": { + "SourceDir": "/", + "DistributionDir": "/", + "BuildCommand": "npm run-script build", + "StartCommand": "" + } + } +} \ No newline at end of file diff --git a/android/Gemfile b/android/Gemfile new file mode 100644 index 0000000..cdd3a6b --- /dev/null +++ b/android/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gem "fastlane" + +plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') +eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/android/Gemfile.lock b/android/Gemfile.lock new file mode 100644 index 0000000..bb42eb9 --- /dev/null +++ b/android/Gemfile.lock @@ -0,0 +1,181 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.2) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + atomos (0.1.3) + aws-eventstream (1.1.0) + aws-partitions (1.332.0) + aws-sdk-core (3.100.0) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.239.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1.0) + aws-sdk-kms (1.34.1) + aws-sdk-core (~> 3, >= 3.99.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.69.0) + aws-sdk-core (~> 3, >= 3.99.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.1) + aws-sigv4 (1.2.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.3) + claide (1.0.3) + colored (1.2) + colored2 (3.1.2) + commander-fastlane (4.4.6) + highline (~> 1.7.2) + declarative (0.0.10) + declarative-option (0.1.0) + digest-crc (0.5.1) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.5) + emoji_regex (1.0.1) + excon (0.75.0) + faraday (1.0.1) + multipart-post (>= 1.2, < 3) + faraday-cookie_jar (0.0.6) + faraday (>= 0.7.4) + http-cookie (~> 1.0.0) + faraday_middleware (1.0.0) + faraday (~> 1.0) + fastimage (2.1.7) + fastlane (2.149.1) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.3, < 3.0.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.2, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander-fastlane (>= 4.4.6, < 5.0.0) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 2.0) + excon (>= 0.71.0, < 1.0.0) + faraday (>= 0.17, < 2.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (>= 0.13.1, < 2.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.37.0, < 0.39.0) + google-cloud-storage (>= 1.15.0, < 2.0.0) + highline (>= 1.7.2, < 2.0.0) + json (< 3.0.0) + jwt (~> 2.1.0) + mini_magick (>= 4.9.4, < 5.0.0) + multi_xml (~> 0.5) + multipart-post (~> 2.0.0) + plist (>= 3.1.0, < 4.0.0) + public_suffix (~> 2.0.0) + rubyzip (>= 1.3.0, < 2.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-increment_version_code (0.4.3) + gh_inspector (1.1.3) + google-api-client (0.38.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 0.9) + httpclient (>= 2.8.1, < 3.0) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + signet (~> 0.12) + google-cloud-core (1.5.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.3.2) + faraday (>= 0.17.3, < 2.0) + google-cloud-errors (1.0.1) + google-cloud-storage (1.26.2) + addressable (~> 2.5) + digest-crc (~> 0.4) + google-api-client (~> 0.33) + google-cloud-core (~> 1.2) + googleauth (~> 0.9) + mini_mime (~> 1.0) + googleauth (0.13.0) + faraday (>= 0.17.3, < 2.0) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (~> 0.14) + highline (1.7.10) + http-cookie (1.0.3) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.4.0) + json (2.3.0) + jwt (2.1.0) + memoist (0.16.2) + mini_magick (4.10.1) + mini_mime (1.0.2) + multi_json (1.14.1) + multi_xml (0.6.0) + multipart-post (2.0.0) + nanaimo (0.2.6) + naturally (2.2.0) + os (1.1.0) + plist (3.5.0) + public_suffix (2.0.5) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rouge (2.0.7) + rubyzip (1.3.0) + security (0.1.3) + signet (0.14.0) + addressable (~> 2.3) + faraday (>= 0.17.3, < 2.0) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + slack-notifier (2.3.2) + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + tty-cursor (0.7.1) + tty-screen (0.8.0) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.7) + unicode-display_width (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.16.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.2.6) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.0) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane + fastlane-plugin-increment_version_code + +BUNDLED WITH + 2.1.4 diff --git a/android/app/.classpath b/android/app/.classpath new file mode 100644 index 0000000..32d6691 --- /dev/null +++ b/android/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/app/_BUCK b/android/app/_BUCK new file mode 100644 index 0000000..473c1dc --- /dev/null +++ b/android/app/_BUCK @@ -0,0 +1,55 @@ +# To learn about Buck see [Docs](https://buckbuild.com/). +# To run your application with Buck: +# - install Buck +# - `npm start` - to start the packager +# - `cd android` +# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` +# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck +# - `buck install -r android/app` - compile, install and run application +# + +load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") + +lib_deps = [] + +create_aar_targets(glob(["libs/*.aar"])) + +create_jar_targets(glob(["libs/*.jar"])) + +android_library( + name = "all-libs", + exported_deps = lib_deps, +) + +android_library( + name = "app-code", + srcs = glob([ + "src/main/java/**/*.java", + ]), + deps = [ + ":all-libs", + ":build_config", + ":res", + ], +) + +android_build_config( + name = "build_config", + package = "fi.nyxo.app", +) + +android_resource( + name = "res", + package = "fi.nyxo.app", + res = "src/main/res", +) + +android_binary( + name = "app", + keystore = "//android/keystores:debug", + manifest = "src/main/AndroidManifest.xml", + package_type = "debug", + deps = [ + ":app-code", + ], +) diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..fcef3c8 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,271 @@ +apply plugin: "com.android.application" +apply from: '../../node_modules/react-native-unimodules/gradle.groovy' +import com.android.build.OutputFile + +// Load keystore +def keystorePropertiesFile = rootProject.file("keystores/release.keystore.properties"); +def keystoreProperties = new Properties() +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "../../node_modules/react-native/react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation + * entryFile: "index.android.js", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // whether to disable dev mode in custom build variants (by default only disabled in release) + * // for example: to disable dev mode in the staging build type (if configured) + * devDisabledInStaging: true, + * // The configuration property can be in the following formats + * // 'devDisabledIn${productFlavor}${buildType}' + * // 'devDisabledIn${buildType}' + * + * // the root of your project, i.e. where "package.json" lives + * root: "../../", + * + * // where to put the JS bundle asset in debug mode + * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", + * + * // where to put the JS bundle asset in release mode + * jsBundleDirRelease: "$buildDir/intermediates/assets/release", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in debug mode + * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in release mode + * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", + * + * // by default the gradle tasks are skipped if none of the JS files or assets change; this means + * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to + * // date; if you have any other folders that you want to ignore for performance reasons (gradle + * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ + * // for example, you might want to remove it from here. + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"], + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] + * ] + */ + +project.ext.react = [ + entryFile: "index.js", + enableHermes: true, + + bundleInDebug: project.hasProperty("bundleInDebug") ? project.getProperty("bundleInDebug") : false, + + // If you use build variants it has to be like this - put your own names in there + bundleInRelease: project.hasProperty("bundleInRelease") ? project.getProperty("bundleInRelease") : false +] +apply from: "../../node_modules/react-native/react.gradle" +apply from: "../../node_modules/react-native-ultimate-config/android/rnuc.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore. + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +/** + * Whether to enable the Hermes VM. + * + * This should be set on project.ext.react and mirrored here. If it is not set + * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode + * and the benefits of using Hermes will therefore be sharply reduced. + */ +def enableHermes = project.ext.react.get("enableHermes", true); + + + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + defaultConfig { + applicationId "fi.nyxo.app" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 53 + versionName "1.4.0" + multiDexEnabled true + manifestPlaceholders = [ + appAuthRedirectScheme: 'fi.nyxo.app' + ] + } + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include "armeabi-v7a", "x86", "arm64-v8a" + } + } + signingConfigs { + debug { + storeFile file(keystoreProperties['NYXO_UPLOAD_STORE_FILE']) + storePassword keystoreProperties['NYXO_UPLOAD_STORE_PASSWORD'] + keyAlias keystoreProperties['MYAPP_RELEASE_KEY_ALIAS'] + keyPassword keystoreProperties['NYXO_UPLOAD_KEY_ALIAS'] + } + release { + storeFile file(keystoreProperties['NYXO_UPLOAD_STORE_FILE']) + storePassword keystoreProperties['NYXO_UPLOAD_STORE_PASSWORD'] + keyAlias keystoreProperties['MYAPP_RELEASE_KEY_ALIAS'] + keyPassword keystoreProperties['NYXO_UPLOAD_KEY_ALIAS'] + } + } + buildTypes { + debug { + buildConfigField "String", "CODEPUSH_KEY", '"Y26psKSBIfzb2ta6JgrEC_ZXlxeIHJ4jvmmMB"' + signingConfig signingConfigs.debug + } + release { + buildConfigField "String", "CODEPUSH_KEY", '"Y26psKSBIfzb2ta6JgrEC_ZXlxeIHJ4jvmmMB"' + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + signingConfig signingConfigs.release + + } + } + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits + def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + } + } + } + + packagingOptions { + pickFirst "lib/armeabi-v7a/libc++_shared.so" + pickFirst "lib/arm64-v8a/libc++_shared.so" + pickFirst "lib/x86/libc++_shared.so" + pickFirst "lib/x86_64/libc++_shared.so" + } +} + +dependencies { + // implementation "org.webkit:android-jsc:r241213" + // implementation project(':amazon-cognito-identity-js') + // implementation project(':react-native-screens') + implementation fileTree(dir: "libs", include: ["*.jar"]) + addUnimodulesDependencies([exclude: ['expo-face-detector']]) + + implementation fileTree(dir: "libs", include: ["*.jar"]) + // implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.appcompat:appcompat:1.1.0-rc01' + implementation "com.facebook.react:react-native:+" // From node_modules + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + implementation project(':react-native-background-fetch') + implementation project(':appcenter') + implementation project(':appcenter-analytics') + implementation project(':appcenter-crashes') + implementation 'com.google.firebase:firebase-core:17.0.0' + implementation project(':react-native-firebase') + implementation 'com.google.firebase:firebase-messaging:9.2.1' + implementation 'io.intercom.android:intercom-sdk-base:5.+' + implementation ("com.google.android.gms:play-services-fitness:+") + implementation ("com.google.android.gms:play-services-auth:+") + implementation project(':react-native-google-fit') + implementation project(':@sentry') + implementation (project(':react-native-google-fit'), { + exclude group: "com.google.android.gms" + }) + implementation "com.google.firebase:firebase-messaging:18.0.0" + implementation 'me.leolin:ShortcutBadger:1.1.21@aar' // <-- Add this line if you wish to use badge on Android + + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { + exclude group:'com.facebook.fbjni' + } + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group:'com.facebook.flipper' + } + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { + exclude group:'com.facebook.flipper' + } + + + // required if your app is in the Google Play Store (tip: avoid using bundled play services libs) + implementation 'com.google.firebase:firebase-appindexing:19.0.0' // App indexing + implementation 'com.google.android.gms:play-services-ads:16+' // GAID matching + + + if (enableHermes) { + def hermesPath = "../../node_modules/hermes-engine/android/"; + debugImplementation files(hermesPath + "hermes-debug.aar") + releaseImplementation files(hermesPath + "hermes-release.aar") + } else { + implementation jscFlavor + } +} + +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' +} +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) +apply plugin: 'com.google.gms.google-services' +com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true // takes care of bug between Codepush and Firebase + diff --git a/android/app/build_defs.bzl b/android/app/build_defs.bzl new file mode 100644 index 0000000..fff270f --- /dev/null +++ b/android/app/build_defs.bzl @@ -0,0 +1,19 @@ +"""Helper definitions to glob .aar and .jar targets""" + +def create_aar_targets(aarfiles): + for aarfile in aarfiles: + name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] + lib_deps.append(":" + name) + android_prebuilt_aar( + name = name, + aar = aarfile, + ) + +def create_jar_targets(jarfiles): + for jarfile in jarfiles: + name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] + lib_deps.append(":" + name) + prebuilt_jar( + name = name, + binary_jar = jarfile, + ) diff --git a/android/app/debug/AndroidManifest.xml b/android/app/debug/AndroidManifest.xml new file mode 100644 index 0000000..7feb33d --- /dev/null +++ b/android/app/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/debug/java/fi/nyxo/app/ReactNativeFlipper.java b/android/app/debug/java/fi/nyxo/app/ReactNativeFlipper.java new file mode 100644 index 0000000..011978c --- /dev/null +++ b/android/app/debug/java/fi/nyxo/app/ReactNativeFlipper.java @@ -0,0 +1,66 @@ +package fi.nyxo.app; + +import android.content.Context; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.flipper.plugins.react.ReactFlipperPlugin; +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.network.NetworkingModule; +import okhttp3.OkHttpClient; + +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (FlipperUtils.shouldEnableFlipper(context)) { + final FlipperClient client = AndroidFlipperClient.getInstance(context); + + client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); + client.addPlugin(new ReactFlipperPlugin()); + client.addPlugin(new DatabasesFlipperPlugin(context)); + client.addPlugin(new SharedPreferencesFlipperPlugin(context)); + client.addPlugin(CrashReporterPlugin.getInstance()); + + NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); + NetworkingModule.setCustomClientBuilder( + new NetworkingModule.CustomClientBuilder() { + @Override + public void apply(OkHttpClient.Builder builder) { + builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); + } + }); + client.addPlugin(networkFlipperPlugin); + client.start(); + + // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized + // Hence we run if after all native modules have been initialized + ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); + if (reactContext == null) { + reactInstanceManager.addReactInstanceEventListener( + new ReactInstanceManager.ReactInstanceEventListener() { + @Override + public void onReactContextInitialized(ReactContext reactContext) { + reactInstanceManager.removeReactInstanceEventListener(this); + reactContext.runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + client.addPlugin(new FrescoFlipperPlugin()); + } + }); + } + }); + } else { + client.addPlugin(new FrescoFlipperPlugin()); + } + } + } +} \ No newline at end of file diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..f8378ee --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,26 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +-keep public class com.dylanvann.fastimage.* {*;} +-keep public class com.dylanvann.fastimage.** {*;} +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..51908f6 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/java/fi/nyxo/app/MainActivity.java b/android/app/src/main/java/fi/nyxo/app/MainActivity.java new file mode 100644 index 0000000..b6fab5c --- /dev/null +++ b/android/app/src/main/java/fi/nyxo/app/MainActivity.java @@ -0,0 +1,37 @@ +package fi.nyxo.app; + +import android.os.Bundle; +import com.facebook.react.ReactFragmentActivity; +import org.devio.rn.splashscreen.SplashScreen; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.ReactRootView; +import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; + +public class MainActivity extends ReactFragmentActivity { + + /** + * Returns the name of the main component registered from JavaScript. This is + * used to schedule rendering of the component. + */ + + @Override + protected void onCreate(Bundle savedInstanceState) { + SplashScreen.show(this); // here + super.onCreate(null); + } + + @Override + protected String getMainComponentName() { + return "Nyxo"; + } + + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new ReactActivityDelegate(this, getMainComponentName()) { + @Override + protected ReactRootView createRootView() { + return new RNGestureHandlerEnabledRootView(MainActivity.this); + } + }; + } +} diff --git a/android/app/src/main/java/fi/nyxo/app/MainApplication.java b/android/app/src/main/java/fi/nyxo/app/MainApplication.java new file mode 100644 index 0000000..d6ab0a2 --- /dev/null +++ b/android/app/src/main/java/fi/nyxo/app/MainApplication.java @@ -0,0 +1,117 @@ +package fi.nyxo.app; + +import android.app.Application; + +import com.facebook.react.PackageList; +import android.content.Context; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.soloader.SoLoader; +import fi.nyxo.app.generated.BasePackageList; +import io.sentry.RNSentryPackage; + +import org.unimodules.adapters.react.ModuleRegistryAdapter; +import org.unimodules.adapters.react.ReactModuleRegistryProvider; +import org.unimodules.core.interfaces.SingletonModule; +import fi.nyxo.app.R; +import com.reactnative.googlefit.GoogleFitPackage; +import io.intercom.android.sdk.Intercom; +import io.invertase.firebase.RNFirebasePackage; +import io.invertase.firebase.auth.RNFirebaseAuthPackage; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Arrays; +import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; +import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage; +import com.reactnativeultimateconfig.UltimateConfigModule; + +public class MainApplication extends Application implements ReactApplication { + private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider( + new BasePackageList().getPackageList(), Arrays.asList()); + + private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { + + @Override + public boolean getUseDeveloperSupport() { + // return true; + return BuildConfig.DEBUG; + // return BuildConfig.DEBUG; THERES something wrong here + } + + @Override + protected List getPackages() { + + List unimodules = Arrays.asList(new ModuleRegistryAdapter(mModuleRegistryProvider)); + + @SuppressWarnings("UnnecessaryLocalVariable") + List packages = new PackageList(this).getPackages(); + // packages.add(new CodePush("Y26psKSBIfzb2ta6JgrEC_ZXlxeIHJ4jvmmMB", + // getApplicationContext(), BuildConfig.DEBUG)); + // packages.add(new RNBackgroundFetchPackage()); + packages.add(new GoogleFitPackage(BuildConfig.APPLICATION_ID)); + packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider)); + packages.add(new RNFirebaseMessagingPackage()); // <-- Add this line + packages.add(new RNFirebaseNotificationsPackage()); // <-- Add this line + // packages.add(new RNSentryPackage()); + + // packages.add(new GFPackage()); + // packages.addAll(unimodules); + + // packages.add(new IntercomPackage()); + // Packages that cannot be autolinked yet can be added manually here, for + // example: Y26psKSBIfzb2ta6JgrEC_ZXlxeIHJ4jvmmMB + // packages.add(new MyReactNativePackage()); + return packages; + + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + UltimateConfigModule.setBuildConfig(BuildConfig.class); + SoLoader.init(this, /* native exopackage */ false); + Intercom.initialize(this, BuildConfig.INTERCOM_KEY_ANDROID, BuildConfig.INTERCOM_ID); + initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + + } + + /** + * Loads Flipper in React Native templates. + * + * @param context + */ + private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (BuildConfig.DEBUG) { + try { + /* + * We use reflection here to pick up the class that initializes Flipper, since + * Flipper library is not available in release mode + */ + Class aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper"); + aClass.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class).invoke(null, context, + reactInstanceManager); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } +} diff --git a/android/app/src/main/java/fi/nyxo/app/MainMessagingService.java b/android/app/src/main/java/fi/nyxo/app/MainMessagingService.java new file mode 100644 index 0000000..dfb8d3d --- /dev/null +++ b/android/app/src/main/java/fi/nyxo/app/MainMessagingService.java @@ -0,0 +1,33 @@ +package fi.nyxo.app; + +import io.invertase.firebase.messaging.*; +import android.content.Intent; +import android.content.Context; +import io.intercom.android.sdk.push.IntercomPushClient; +import io.invertase.firebase.messaging.RNFirebaseMessagingService; +import com.google.firebase.messaging.RemoteMessage; +import android.util.Log; +import java.util.Map; + +public class MainMessagingService extends RNFirebaseMessagingService { + private static final String TAG = "MainMessagingService"; + private final IntercomPushClient intercomPushClient = new IntercomPushClient(); + + @Override + public void onNewToken(String refreshedToken) { + intercomPushClient.sendTokenToIntercom(getApplication(), refreshedToken); + // DO HOST LOGIC HERE + } + + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + Map message = remoteMessage.getData(); + + if (intercomPushClient.isIntercomPush(message)) { + Log.d(TAG, "Intercom message received"); + intercomPushClient.handlePush(getApplication(), message); + } else { + super.onMessageReceived(remoteMessage); + } + } +} diff --git a/android/app/src/main/java/fi/nyxo/app/generated/BasePackageList.java b/android/app/src/main/java/fi/nyxo/app/generated/BasePackageList.java new file mode 100644 index 0000000..5f05954 --- /dev/null +++ b/android/app/src/main/java/fi/nyxo/app/generated/BasePackageList.java @@ -0,0 +1,16 @@ +package fi.nyxo.app.generated; + +import java.util.Arrays; +import java.util.List; +import org.unimodules.core.interfaces.Package; + +public class BasePackageList { + public List getPackageList() { + return Arrays.asList( + new expo.modules.constants.ConstantsPackage(), + new expo.modules.filesystem.FileSystemPackage(), + new expo.modules.imageloader.ImageLoaderPackage(), + new expo.modules.permissions.PermissionsPackage() + ); + } +} diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..d3644da --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,53 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "28.0.3" + minSdkVersion = 21 + compileSdkVersion = 29 + targetSdkVersion = 28 + supportLibVersion = "28.0.0" + } + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.google.gms:google-services:4.2.0' + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + mavenLocal() + google() + jcenter() + maven { url 'https://www.jitpack.io' } + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "$rootDir/../node_modules/react-native/android" + } + + maven { + // Android JSC is installed from npm + url("$rootDir/../node_modules/jsc-android/dist") + } + maven { url "https://maven.google.com" } + maven { + // Local Maven repo containing AARs with JSC library built for Android + url "$rootDir/../node_modules/jsc-android/dist" + } + maven { + url "$rootDir/../node_modules/react-native-background-fetch/android/libs" + } + } +} + + +wrapper { + gradleVersion = '4.7' + distributionUrl = distributionUrl.replace("bin", "all") +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..7c4e2ca --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,28 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + +# Version of flipper SDK to use with React Native +FLIPPER_VERSION=0.33.1 \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..01b8bf6b1f99cad9213fc495b33ad5bbab8efd20 GIT binary patch literal 54329 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

<5G2M1WZP5 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