diff --git a/android/.project b/android/.project new file mode 100644 index 00000000..e2c3953d --- /dev/null +++ b/android/.project @@ -0,0 +1,17 @@ + + + devhub + Project devhub created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 00000000..226c8b48 --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +#Wed Dec 13 00:16:04 BRST 2017 +connection.project.dir= diff --git a/android/app/.classpath b/android/app/.classpath new file mode 100644 index 00000000..c93a0ddb --- /dev/null +++ b/android/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/app/.project b/android/app/.project new file mode 100644 index 00000000..ac485d7c --- /dev/null +++ b/android/app/.project @@ -0,0 +1,23 @@ + + + app + Project app created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/android/app/.settings/org.eclipse.buildship.core.prefs b/android/app/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 00000000..c82c70a2 --- /dev/null +++ b/android/app/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +#Wed Dec 13 00:16:04 BRST 2017 +connection.project.dir=.. diff --git a/android/app/build.gradle b/android/app/build.gradle index ec801946..48a497d9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -137,6 +137,8 @@ android { } dependencies { + compile project(':react-native-gesture-handler') + compile project(':react-native-vector-icons') compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" // From node_modules diff --git a/android/app/src/main/assets/fonts/MaterialIcons.ttf b/android/app/src/main/assets/fonts/MaterialIcons.ttf new file mode 100644 index 00000000..7015564a Binary files /dev/null and b/android/app/src/main/assets/fonts/MaterialIcons.ttf differ diff --git a/android/app/src/main/assets/fonts/Octicons.ttf b/android/app/src/main/assets/fonts/Octicons.ttf new file mode 100644 index 00000000..09e2b2d7 Binary files /dev/null and b/android/app/src/main/assets/fonts/Octicons.ttf differ diff --git a/android/app/src/main/java/com/devhub/MainActivity.java b/android/app/src/main/java/com/devhub/MainActivity.java index f5ea2e75..1264c082 100644 --- a/android/app/src/main/java/com/devhub/MainActivity.java +++ b/android/app/src/main/java/com/devhub/MainActivity.java @@ -1,6 +1,9 @@ package com.devhub; import com.facebook.react.ReactActivity; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.ReactRootView; +import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; public class MainActivity extends ReactActivity { @@ -12,4 +15,14 @@ public class MainActivity extends ReactActivity { protected String getMainComponentName() { return "devhub"; } + + @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/com/devhub/MainApplication.java b/android/app/src/main/java/com/devhub/MainApplication.java index 8b63b51b..ca17e287 100644 --- a/android/app/src/main/java/com/devhub/MainApplication.java +++ b/android/app/src/main/java/com/devhub/MainApplication.java @@ -3,6 +3,8 @@ package com.devhub; import android.app.Application; import com.facebook.react.ReactApplication; +import com.swmansion.gesturehandler.react.RNGestureHandlerPackage; +import com.oblador.vectoricons.VectorIconsPackage; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; @@ -22,7 +24,9 @@ public class MainApplication extends Application implements ReactApplication { @Override protected List getPackages() { return Arrays.asList( - new MainReactPackage() + new MainReactPackage(), + new RNGestureHandlerPackage(), + new VectorIconsPackage() ); } diff --git a/android/settings.gradle b/android/settings.gradle index 21c2ce3a..6a1901f3 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,3 +1,7 @@ rootProject.name = 'devhub' +include ':react-native-gesture-handler' +project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android') +include ':react-native-vector-icons' +project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') include ':app' diff --git a/index.js b/index.js index 4f753ce4..e6a938a6 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,13 @@ +import React from 'react' import { AppRegistry } from 'react-native' +if (process.env.NODE_ENV !== 'production') { + const { whyDidYouUpdate } = require('why-did-you-update') + whyDidYouUpdate(React, { + exclude: /^Icon|Swipeable/, + }) +} + import App from './src' AppRegistry.registerComponent('devhub', () => App) diff --git a/ios/devhub.xcodeproj/project.pbxproj b/ios/devhub.xcodeproj/project.pbxproj index bdddb3c4..17be48b5 100644 --- a/ios/devhub.xcodeproj/project.pbxproj +++ b/ios/devhub.xcodeproj/project.pbxproj @@ -25,7 +25,7 @@ 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */; }; + 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; }; 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; }; 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; }; @@ -34,9 +34,13 @@ 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; }; 2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; }; 2DCD954D1E0B4F2C00145EB5 /* devhubTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* devhubTests.m */; }; + 2EAFF5C21FE0CEA9000A9A11 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2EAFF59C1FE0CEA9000A9A11 /* MaterialIcons.ttf */; }; 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; + 7FC9F95B44E64398A3976B78 /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8888F60F6C304A58BF18E9E8 /* libRNVectorIcons.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; }; + C2619E3179B6481FA20E5CEB /* libRNGestureHandler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B5DF78792708477FB2343101 /* libRNGestureHandler.a */; }; + F104E1DDC29047C7B18F01E9 /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FA6EFEAAAEB7487F9CC33B59 /* Octicons.ttf */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -110,6 +114,83 @@ remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7; remoteInfo = "devhub-tvOS"; }; + 2EAFEE9B1FDDD3E9000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = ADD01A681E09402E00F6D226; + remoteInfo = "RCTBlob-tvOS"; + }; + 2EAFEEAD1FDDD3E9000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3DBE0D001F3B181A0099AA32; + remoteInfo = fishhook; + }; + 2EAFEEAF1FDDD3E9000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32; + remoteInfo = "fishhook-tvOS"; + }; + 2EAFEEB41FDDD3EA000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B6BF65C496E44E78BF211275 /* RNVectorIcons.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5DBEB1501B18CEA900B34395; + remoteInfo = RNVectorIcons; + }; + 2EAFF54B1FE0AC4F000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7; + remoteInfo = "third-party"; + }; + 2EAFF54D1FE0AC4F000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D383D3C1EBD27B6005632C8; + remoteInfo = "third-party-tvOS"; + }; + 2EAFF54F1FE0AC4F000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 139D7E881E25C6D100323FB7; + remoteInfo = "double-conversion"; + }; + 2EAFF5511FE0AC4F000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D383D621EBD27B9005632C8; + remoteInfo = "double-conversion-tvOS"; + }; + 2EAFF5531FE0AC4F000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 9936F3131F5F2E4B0010BF04; + remoteInfo = privatedata; + }; + 2EAFF5551FE0AC4F000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04; + remoteInfo = "privatedata-tvOS"; + }; + 2EAFF58C1FE0C469000A9A11 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1FD65CD116F747ACA2D47E1F /* RNGestureHandler.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RNGestureHandler; + }; 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; @@ -258,12 +339,28 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = devhub/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = devhub/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 1A78E8CA2AB84F5DB5771FD1 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = ""; }; + 1FD65CD116F747ACA2D47E1F /* RNGestureHandler.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNGestureHandler.xcodeproj; path = "../node_modules/react-native-gesture-handler/ios/RNGestureHandler.xcodeproj"; sourceTree = ""; }; 2D02E47B1E0B4A5D006451C7 /* devhub-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "devhub-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D02E4901E0B4A5D006451C7 /* devhub-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "devhub-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2EAFF59C1FE0CEA9000A9A11 /* MaterialIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = ""; }; + 486C758B88E34A52BFB2C474 /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = ""; }; 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; + 5FDB82E9A6994D928FA8EF88 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = ""; }; + 6BA6B80F6E304DB6AB2249A6 /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; + 7D47CCDFA76944C0897F14BE /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; + 862BDE7B078E4A57943ED526 /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = ""; }; + 8888F60F6C304A58BF18E9E8 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; }; + A78BCCD8D80D432B8BE119EB /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = ""; }; ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = ""; }; + B5DF78792708477FB2343101 /* libRNGestureHandler.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNGestureHandler.a; sourceTree = ""; }; + B6BF65C496E44E78BF211275 /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = ""; }; + F035D9E85FA74D8CBFBDAE1B /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = ""; }; + F1AA246742BC4C2A8C9988F3 /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = ""; }; + F8A11CE8BDF64CB988CDD71E /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = ""; }; + FA6EFEAAAEB7487F9CC33B59 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -292,6 +389,8 @@ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + 7FC9F95B44E64398A3976B78 /* libRNVectorIcons.a in Frameworks */, + C2619E3179B6481FA20E5CEB /* libRNGestureHandler.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -300,7 +399,7 @@ buildActionMask = 2147483647; files = ( 2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */, - 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */, + 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */, 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */, 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */, 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */, @@ -393,6 +492,8 @@ children = ( 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */, + 2EAFEEAE1FDDD3E9000A9A11 /* libfishhook.a */, + 2EAFEEB01FDDD3E9000A9A11 /* libfishhook-tvOS.a */, ); name = Products; sourceTree = ""; @@ -422,7 +523,37 @@ 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */, 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */, 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */, - 3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */, + 2EAFF54C1FE0AC4F000A9A11 /* libthird-party.a */, + 2EAFF54E1FE0AC4F000A9A11 /* libthird-party.a */, + 2EAFF5501FE0AC4F000A9A11 /* libdouble-conversion.a */, + 2EAFF5521FE0AC4F000A9A11 /* libdouble-conversion.a */, + 2EAFF5541FE0AC4F000A9A11 /* libprivatedata.a */, + 2EAFF5561FE0AC4F000A9A11 /* libprivatedata-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 2EAFEE951FDDD3E8000A9A11 /* Recovered References */ = { + isa = PBXGroup; + children = ( + 8888F60F6C304A58BF18E9E8 /* libRNVectorIcons.a */, + B5DF78792708477FB2343101 /* libRNGestureHandler.a */, + ); + name = "Recovered References"; + sourceTree = ""; + }; + 2EAFEEB11FDDD3EA000A9A11 /* Products */ = { + isa = PBXGroup; + children = ( + 2EAFEEB51FDDD3EA000A9A11 /* libRNVectorIcons.a */, + ); + name = Products; + sourceTree = ""; + }; + 2EAFF5891FE0C469000A9A11 /* Products */ = { + isa = PBXGroup; + children = ( + 2EAFF58D1FE0C469000A9A11 /* libRNGestureHandler.a */, ); name = Products; sourceTree = ""; @@ -431,7 +562,7 @@ isa = PBXGroup; children = ( 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */, - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */, + 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */, ); name = Products; sourceTree = ""; @@ -460,6 +591,8 @@ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, + B6BF65C496E44E78BF211275 /* RNVectorIcons.xcodeproj */, + 1FD65CD116F747ACA2D47E1F /* RNGestureHandler.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -476,10 +609,13 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 2EAFF59C1FE0CEA9000A9A11 /* MaterialIcons.ttf */, 13B07FAE1A68108700A75B9A /* devhub */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* devhubTests */, 83CBBA001A601CBA00E9B192 /* Products */, + 8960E566DB794015B585073C /* Resources */, + 2EAFEE951FDDD3E8000A9A11 /* Recovered References */, ); indentWidth = 2; sourceTree = ""; @@ -497,10 +633,29 @@ name = Products; sourceTree = ""; }; + 8960E566DB794015B585073C /* Resources */ = { + isa = PBXGroup; + children = ( + 7D47CCDFA76944C0897F14BE /* Entypo.ttf */, + A78BCCD8D80D432B8BE119EB /* EvilIcons.ttf */, + F1AA246742BC4C2A8C9988F3 /* Feather.ttf */, + 6BA6B80F6E304DB6AB2249A6 /* FontAwesome.ttf */, + F8A11CE8BDF64CB988CDD71E /* Foundation.ttf */, + 5FDB82E9A6994D928FA8EF88 /* Ionicons.ttf */, + 862BDE7B078E4A57943ED526 /* MaterialCommunityIcons.ttf */, + 486C758B88E34A52BFB2C474 /* MaterialIcons.ttf */, + FA6EFEAAAEB7487F9CC33B59 /* Octicons.ttf */, + F035D9E85FA74D8CBFBDAE1B /* SimpleLineIcons.ttf */, + 1A78E8CA2AB84F5DB5771FD1 /* Zocial.ttf */, + ); + name = Resources; + sourceTree = ""; + }; ADBDB9201DFEBF0600ED6528 /* Products */ = { isa = PBXGroup; children = ( ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */, + 2EAFEE9C1FDDD3E9000A9A11 /* libRCTBlob-tvOS.a */, ); name = Products; sourceTree = ""; @@ -586,13 +741,16 @@ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 610; ORGANIZATIONNAME = Facebook; TargetAttributes = { 00E356ED1AD99517003FC87E = { CreatedOnToolsVersion = 6.2; TestTargetID = 13B07F861A680F5B00A75B9A; }; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = JNXGJS86YQ; + }; 2D02E47A1E0B4A5D006451C7 = { CreatedOnToolsVersion = 8.2.1; ProvisioningStyle = Automatic; @@ -664,6 +822,14 @@ ProductGroup = 146834001AC3E56700842450 /* Products */; ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; }, + { + ProductGroup = 2EAFF5891FE0C469000A9A11 /* Products */; + ProjectRef = 1FD65CD116F747ACA2D47E1F /* RNGestureHandler.xcodeproj */; + }, + { + ProductGroup = 2EAFEEB11FDDD3EA000A9A11 /* Products */; + ProjectRef = B6BF65C496E44E78BF211275 /* RNVectorIcons.xcodeproj */; + }, ); projectRoot = ""; targets = ( @@ -732,6 +898,83 @@ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 2EAFEE9C1FDDD3E9000A9A11 /* libRCTBlob-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTBlob-tvOS.a"; + remoteRef = 2EAFEE9B1FDDD3E9000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFEEAE1FDDD3E9000A9A11 /* libfishhook.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libfishhook.a; + remoteRef = 2EAFEEAD1FDDD3E9000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFEEB01FDDD3E9000A9A11 /* libfishhook-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libfishhook-tvOS.a"; + remoteRef = 2EAFEEAF1FDDD3E9000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFEEB51FDDD3EA000A9A11 /* libRNVectorIcons.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNVectorIcons.a; + remoteRef = 2EAFEEB41FDDD3EA000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF54C1FE0AC4F000A9A11 /* libthird-party.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libthird-party.a"; + remoteRef = 2EAFF54B1FE0AC4F000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF54E1FE0AC4F000A9A11 /* libthird-party.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libthird-party.a"; + remoteRef = 2EAFF54D1FE0AC4F000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF5501FE0AC4F000A9A11 /* libdouble-conversion.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libdouble-conversion.a"; + remoteRef = 2EAFF54F1FE0AC4F000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF5521FE0AC4F000A9A11 /* libdouble-conversion.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libdouble-conversion.a"; + remoteRef = 2EAFF5511FE0AC4F000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF5541FE0AC4F000A9A11 /* libprivatedata.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libprivatedata.a; + remoteRef = 2EAFF5531FE0AC4F000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF5561FE0AC4F000A9A11 /* libprivatedata-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libprivatedata-tvOS.a"; + remoteRef = 2EAFF5551FE0AC4F000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 2EAFF58D1FE0C469000A9A11 /* libRNGestureHandler.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNGestureHandler.a; + remoteRef = 2EAFF58C1FE0C469000A9A11 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -774,10 +1017,10 @@ remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */ = { + 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = "libReact-tvOS.a"; + path = libReact.a; remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -830,10 +1073,10 @@ remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = { + 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = "libRCTAnimation-tvOS.a"; + path = libRCTAnimation.a; remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -874,6 +1117,8 @@ files = ( 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + F104E1DDC29047C7B18F01E9 /* Octicons.ttf in Resources */, + 2EAFF5C21FE0CEA9000A9A11 /* MaterialIcons.ttf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -996,9 +1241,19 @@ "DEBUG=1", "$(inherited)", ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + ); INFOPLIST_FILE = devhubTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); OTHER_LDFLAGS = ( "-ObjC", "-lc++", @@ -1013,9 +1268,19 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + ); INFOPLIST_FILE = devhubTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); OTHER_LDFLAGS = ( "-ObjC", "-lc++", @@ -1031,6 +1296,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; + DEVELOPMENT_TEAM = JNXGJS86YQ; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + ); INFOPLIST_FILE = devhub/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( @@ -1048,6 +1319,12 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = JNXGJS86YQ; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + ); INFOPLIST_FILE = devhub/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( @@ -1072,8 +1349,18 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + ); INFOPLIST_FILE = "devhub-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); OTHER_LDFLAGS = ( "-ObjC", "-lc++", @@ -1098,8 +1385,18 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**", + ); INFOPLIST_FILE = "devhub-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); OTHER_LDFLAGS = ( "-ObjC", "-lc++", @@ -1125,6 +1422,11 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = "devhub-tvOSTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.devhub-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; @@ -1146,6 +1448,11 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = "devhub-tvOSTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.devhub-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; diff --git a/ios/devhub/Base.lproj/LaunchScreen.xib b/ios/devhub/Base.lproj/LaunchScreen.xib index 129e5a84..0c768622 100644 --- a/ios/devhub/Base.lproj/LaunchScreen.xib +++ b/ios/devhub/Base.lproj/LaunchScreen.xib @@ -1,9 +1,12 @@ - - + + + + + - - + + @@ -11,29 +14,7 @@ - - - - - - - - - - - - - + diff --git a/ios/devhub/Info.plist b/ios/devhub/Info.plist index f93d1bc9..0e9efe61 100644 --- a/ios/devhub/Info.plist +++ b/ios/devhub/Info.plist @@ -24,24 +24,7 @@ 1 LSRequiresIPhoneOS - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - NSLocationWhenInUseUsageDescription - NSAppTransportSecurity - NSExceptionDomains @@ -52,5 +35,28 @@ + NSLocationWhenInUseUsageDescription + + UIAppFonts + + MaterialIcons.ttf + Octicons.ttf + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarStyle + UIStatusBarStyleLightContent + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + diff --git a/package.json b/package.json index 49b25fd9..d27d7410 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,16 @@ "xcode": "open ios/devhub.xcodeproj" }, "dependencies": { + "@types/react-native-vector-icons": "^4.4.2", + "gravatar": "^1.6.0", "react": "^16.2.0", - "react-native": "^0.51.0" + "react-native": "^0.51.0", + "react-native-gesture-handler": "^1.0.0-alpha.35", + "react-native-vector-icons": "^4.4.2", + "warna": "^0.2.4" }, "devDependencies": { + "@types/gravatar": "^1.4.28", "@types/jest": "^21.1.5", "@types/react": "^16.0.21", "@types/react-native": "^0.50.2", @@ -25,7 +31,8 @@ "tslint": "^5.8.0", "tslint-config-airbnb": "^5.3.0", "tslint-react": "^3.2.0", - "typescript": "^2.6.1" + "typescript": "^2.6.1", + "why-did-you-update": "^0.1.0" }, "jest": { "preset": "react-native", @@ -34,13 +41,22 @@ "useBabelrc": true } }, - "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json"], + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx", + "json" + ], "transform": { "^.+\\.(jsx?)$": "/node_modules/babel-jest", "^.+\\.(tsx?)$": "/node_modules/ts-jest/preprocessor.js" }, "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", - "testPathIgnorePatterns": ["/node_modules/", "/.history/"], + "testPathIgnorePatterns": [ + "/node_modules/", + "/.history/" + ], "cacheDirectory": ".jest/cache" } } diff --git a/src/components/cards/NotificationCard.tsx b/src/components/cards/NotificationCard.tsx new file mode 100644 index 00000000..742ca894 --- /dev/null +++ b/src/components/cards/NotificationCard.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +import SwipeableCard, { IProps as ICardProps } from './partials/SwipeableCard' + +export interface IProps extends ICardProps {} + +export interface IState {} + +const NotificationCard = ({ username }: IProps) => + +export default NotificationCard diff --git a/src/components/cards/NotificationCards.tsx b/src/components/cards/NotificationCards.tsx new file mode 100644 index 00000000..73b8993b --- /dev/null +++ b/src/components/cards/NotificationCards.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import { FlatList } from 'react-native' + +import { INotification } from '../../utils/types' +import NotificationCard from './NotificationCard' +import CardItemSeparator from './partials/CardItemSeparator' + +export interface IProps { + notifications: INotification[] +} + +class NotificationCards extends React.PureComponent { + keyExtractor(notification: INotification) { + return notification.id + } + + renderItem({ item: { actor: { username } } }: { item: INotification }) { + return + } + + render() { + const { notifications } = this.props + return ( + + ) + } +} + +export default NotificationCards diff --git a/src/components/cards/partials/Card.tsx b/src/components/cards/partials/Card.tsx new file mode 100644 index 00000000..b8e36ace --- /dev/null +++ b/src/components/cards/partials/Card.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { StyleSheet, View, ViewStyle } from 'react-native' + +import theme from '../../../styles/themes/light' +import { contentPadding } from '../../../styles/variables' +import CardHeader, { IProps as ICardHeaderProps } from './CardHeader' +import RepositoryRow from './rows/RepositoryRow' + +export interface IProps extends ICardHeaderProps {} + +export interface IState {} + +const styles = StyleSheet.create({ + container: { + backgroundColor: theme.cardBackground, + paddingHorizontal: contentPadding, + paddingVertical: 2 * contentPadding, + } as ViewStyle, +}) + +const Card = ({ username }: IProps) => ( + + + + +) + +export default Card diff --git a/src/components/cards/partials/CardHeader.tsx b/src/components/cards/partials/CardHeader.tsx new file mode 100644 index 00000000..8f5062f0 --- /dev/null +++ b/src/components/cards/partials/CardHeader.tsx @@ -0,0 +1,58 @@ +import React from 'react' +import { StyleSheet, Text, View, ViewStyle } from 'react-native' + +import Avatar from '../../common/Avatar' +import cardStyles from '../styles' +import CardIcon from './CardIcon' + +export interface IProps { + username: string +} + +export interface IState {} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + flexGrow: 1, + } as ViewStyle, + + rightColumnCentered: { + flex: 1, + justifyContent: 'center', + } as ViewStyle, + + outerContainer: { + flexDirection: 'row', + justifyContent: 'center', + } as ViewStyle, + + innerContainer: { + flex: 1, + } as ViewStyle, +}) + +const CardHeader = ({ username }: IProps) => ( + + + + + + + + + + {username} +  • 2h (13:59) + + + starred a repository + + + + + + +) + +export default CardHeader diff --git a/src/components/cards/partials/CardIcon.tsx b/src/components/cards/partials/CardIcon.tsx new file mode 100644 index 00000000..950a40b0 --- /dev/null +++ b/src/components/cards/partials/CardIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { StyleSheet, ViewStyle } from 'react-native' +import { IconProps } from 'react-native-vector-icons/Icon' +import Icon from 'react-native-vector-icons/Octicons' + +import { contentPadding } from '../../../styles/variables' + +export interface IProps extends IconProps {} + +const styles = StyleSheet.create({ + container: { + fontSize: 18, + marginLeft: contentPadding, + } as ViewStyle, +}) + +const CardIcon = (props: IProps) => { + return +} + +export default CardIcon diff --git a/src/components/cards/partials/CardItemSeparator.tsx b/src/components/cards/partials/CardItemSeparator.tsx new file mode 100644 index 00000000..a932c253 --- /dev/null +++ b/src/components/cards/partials/CardItemSeparator.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import { StyleSheet, View, ViewStyle } from 'react-native' + +import theme from '../../../styles/themes/light' + +const styles = StyleSheet.create({ + separator: { + borderBottomColor: theme.base01, + borderBottomWidth: 1, + flexGrow: 1, + height: 1, + } as ViewStyle, +}) + +const CardItemSeparator = () => + +export default CardItemSeparator diff --git a/src/components/cards/partials/SwipeableCard.tsx b/src/components/cards/partials/SwipeableCard.tsx new file mode 100644 index 00000000..9d591201 --- /dev/null +++ b/src/components/cards/partials/SwipeableCard.tsx @@ -0,0 +1,37 @@ +import React from 'react' + +import SwipeableRow from '../../../libs/swipeable' +import Card, { IProps as ICardProps } from './Card' + +export interface IProps extends ICardProps {} + +export interface IState {} + +const SwipeableCard = (props: IProps) => ( + {}, + }, + ]} + rightActions={[ + { + type: 'FULL', + key: 'archive', + icon: 'archive', + color: '#497AFC', + label: 'Archive', + onPress: () => {}, + }, + ]} + > + + +) + +export default SwipeableCard diff --git a/src/components/cards/partials/rows/RepositoryRow.tsx b/src/components/cards/partials/rows/RepositoryRow.tsx new file mode 100644 index 00000000..ed041c69 --- /dev/null +++ b/src/components/cards/partials/rows/RepositoryRow.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import { Text, View } from 'react-native' + +import Avatar from '../../../common/Avatar' +import cardStyles from '../../styles' +import rowStyles from './styles' + +export interface IProps { + repository: string + owner: string +} + +export interface IState {} + +const RepositoryRow = ({ owner, repository }: IProps) => ( + + + + + + + + {repository} +  {owner} + + + +) + +export default RepositoryRow diff --git a/src/components/cards/partials/rows/styles.ts b/src/components/cards/partials/rows/styles.ts new file mode 100644 index 00000000..64c0442d --- /dev/null +++ b/src/components/cards/partials/rows/styles.ts @@ -0,0 +1,32 @@ +import { StyleSheet, TextStyle, ViewStyle } from 'react-native' + +import theme from '../../../../styles/themes/light' +import { contentPadding, radius, smallTextSize } from '../../../../styles/variables' + +export default StyleSheet.create({ + container: { + flexDirection: 'row', + flexGrow: 1, + marginTop: contentPadding, + } as ViewStyle, + + mainContentContainer: { + alignItems: 'center', + borderColor: theme.base01, + borderRadius: radius, + borderWidth: 1, + flexDirection: 'row', + flexGrow: 1, + paddingHorizontal: contentPadding, + paddingVertical: contentPadding / 2, + } as ViewStyle, + + ownerText: { + color: theme.base05, + fontSize: smallTextSize, + } as TextStyle, + + repositoryText: { + color: theme.base04, + } as TextStyle, +}) diff --git a/src/components/cards/styles.ts b/src/components/cards/styles.ts new file mode 100644 index 00000000..d5e5eb51 --- /dev/null +++ b/src/components/cards/styles.ts @@ -0,0 +1,46 @@ +import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native' + +import theme from '../../styles/themes/light' +import { avatarSize, contentPadding, smallTextSize } from '../../styles/variables' + +export default StyleSheet.create({ + horizontal: { + flexDirection: 'row', + } as ViewStyle, + + leftColumn: { + justifyContent: 'center', + marginRight: contentPadding, + width: avatarSize, + } as ViewStyle, + + avatar: { + alignSelf: 'flex-end', + } as ImageStyle, + + rightColumn: { + flex: 1, + } as ViewStyle, + + usernameText: { + alignSelf: 'center', + color: theme.base04, + fontWeight: 'bold', + lineHeight: 20, + } as TextStyle, + + timestampText: { + alignSelf: 'center', + color: theme.base05, + fontSize: smallTextSize, + } as TextStyle, + + mutedText: { + color: theme.base05, + } as TextStyle, + + descriptionText: { + color: theme.base05, + lineHeight: 20, + } as TextStyle, +}) diff --git a/src/components/common/Avatar.tsx b/src/components/common/Avatar.tsx new file mode 100644 index 00000000..edfd007c --- /dev/null +++ b/src/components/common/Avatar.tsx @@ -0,0 +1,48 @@ +import React from 'react' +import { Image, ImageStyle, StyleSheet, ViewStyle } from 'react-native' + +import { avatarSize, radius, smallAvatarSize } from '../../styles/variables' +import { getUserAvatarByEmail, getUserAvatarByUsername } from '../../utils/helpers/github' + +export interface IProps { + avatarURL?: string + email?: string + size?: number + small?: boolean + style?: ImageStyle + username?: string +} + +export const size = avatarSize + +const styles = StyleSheet.create({ + image: { + borderRadius: radius, + } as ViewStyle, +}) + +const Avatar = ({ avatarURL, email, size: _size, small, style, username, ...props }: IProps) => { + const finalSize = _size || (small ? smallAvatarSize : avatarSize) + const uri = + (username && getUserAvatarByUsername(username, { size: finalSize })) || + avatarURL || + (email && getUserAvatarByEmail(email, { size: finalSize })) + if (!uri) return null + + return ( + + ) +} + +export default Avatar diff --git a/src/components/common/Screen.tsx b/src/components/common/Screen.tsx new file mode 100644 index 00000000..8bb70b02 --- /dev/null +++ b/src/components/common/Screen.tsx @@ -0,0 +1,24 @@ +import React, { ReactNode } from 'react' +import { SafeAreaView, StyleSheet, ViewStyle } from 'react-native' + +import theme from '../../styles/themes/light' + +export const size = 48 + +export interface IProps { + children: ReactNode + style?: ViewStyle +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: theme.base00, + flex: 1, + } as ViewStyle, +}) + +const Screen = (props: IProps) => ( + +) + +export default Screen diff --git a/src/components/screens/NotificationsScreen.tsx b/src/components/screens/NotificationsScreen.tsx new file mode 100644 index 00000000..15a345f8 --- /dev/null +++ b/src/components/screens/NotificationsScreen.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +import NotificationCardsContainer from '../../containers/NotificationCardsContainer' +import Screen from '../common/Screen' + +const NotificationsScreen = () => ( + + + +) + +export default NotificationsScreen diff --git a/src/containers/NotificationCardsContainer.tsx b/src/containers/NotificationCardsContainer.tsx new file mode 100644 index 00000000..329ba304 --- /dev/null +++ b/src/containers/NotificationCardsContainer.tsx @@ -0,0 +1,15 @@ +import React from 'react' + +import NotificationCards from '../components/cards/NotificationCards' +import { INotification } from '../utils/types' + +const notifications: INotification[] = [ + { id: '0', actor: { id: '0', username: 'sibelius' } }, + { id: '1', actor: { id: '1', username: 'gaearon' } }, + { id: '2', actor: { id: '2', username: 'brunolemos' } }, + { id: '3', actor: { id: '3', username: 'augustolazaro' } }, +] + +const NotificationCardsContainer = () => + +export default NotificationCardsContainer diff --git a/src/index.tsx b/src/index.tsx index 31cb2159..84eba37f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,39 +1,18 @@ -import React, { Component } from 'react' -import { StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native' +import React from 'react' +import { StatusBar, StyleSheet, View } from 'react-native' -export interface IProps {} - -export interface IState {} - -export default class App extends Component { - render() { - return ( - - Welcome to React Native - To get started, edit index.js - Using Typescript - - ) - } -} +import NotificationsScreen from './components/screens/NotificationsScreen' +import theme from './styles/themes/light' const styles = StyleSheet.create({ container: { - alignItems: 'center', - backgroundColor: '#F5FCFF', flex: 1, - justifyContent: 'center', - } as ViewStyle, - - welcome: { - fontSize: 20, - margin: 10, - textAlign: 'center', - } as TextStyle, - - instructions: { - color: '#333333', - marginBottom: 5, - textAlign: 'center', - } as TextStyle, + }, }) + +export default () => ( + + + + +) diff --git a/src/libs/platform/index.ts b/src/libs/platform/index.ts new file mode 100755 index 00000000..86e90b1e --- /dev/null +++ b/src/libs/platform/index.ts @@ -0,0 +1,10 @@ +import { Platform as _Platform } from 'react-native' + +const Platform = { + ..._Platform, + isStandalone: true, + realOS: _Platform.OS, + selectUsingRealOS: _Platform.select, +} + +export default Platform diff --git a/src/libs/platform/index.web.ts b/src/libs/platform/index.web.ts new file mode 100755 index 00000000..902a7386 --- /dev/null +++ b/src/libs/platform/index.web.ts @@ -0,0 +1,21 @@ +import { Platform as _Platform } from 'react-native' + +function getOSName(): 'android' | 'ios' | 'web' { + const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera + + if (/android/i.test(userAgent)) return 'android' + if (/iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream) return 'ios' + return 'web' +} + +const realOS = getOSName() + +const Platform = { + realOS, + ..._Platform, + isStandalone: (window.navigator as any).standalone, + selectUsingRealOS: (obj: { android?: any; ios?: any; web?: any; default?: any }) => + Platform.realOS in obj ? obj[realOS] : 'web' in obj ? obj.web : obj.default, +} + +export default Platform diff --git a/src/libs/swipeable/AppleSwipeableRow.tsx b/src/libs/swipeable/AppleSwipeableRow.tsx new file mode 100644 index 00000000..5fcab003 --- /dev/null +++ b/src/libs/swipeable/AppleSwipeableRow.tsx @@ -0,0 +1,140 @@ +import React from 'react' +import { Animated, StyleSheet, Text } from 'react-native' +import { RectButton } from 'react-native-gesture-handler' +import Swipeable from 'react-native-gesture-handler/Swipeable' + +import BaseSwipeableRow, { IBaseAction, IBaseProps, Placement } from './BaseSwipeableRow' + +export { defaultWidth } from './BaseSwipeableRow' + +export interface IAction extends IBaseAction { + label: string +} + +export interface IProps extends IBaseProps {} + +export default class AppleSwipeableRow extends BaseSwipeableRow { + _swipeableRow = null + + renderButtonAction = ( + action: IAction, + { x, placement, progress }: { x: number; placement: Placement; progress }, + ) => { + const transform = { + translateX: + placement === 'LEFT' + ? progress.interpolate({ + inputRange: [0, 1], + outputRange: [-x, 0], + }) + : progress.interpolate({ + inputRange: [0, 1], + outputRange: [x, 0], + }), + } + + const pressHandler = () => { + action.onPress() + this.close() + alert(action.label) + } + + return ( + + + + {action.label} + + + + ) + } + + renderFullAction = (action: IAction, { dragX, placement }: { placement: Placement }) => { + const transform = { + translateX: + placement === 'LEFT' + ? dragX.interpolate({ + inputRange: [0, 50, 100, 101], + outputRange: [-20, 0, 0, 1], + }) + : dragX.interpolate({ + inputRange: [-101, -100, -50, 0], + outputRange: [-1, 0, 0, 20], + }), + } + + const pressHandler = () => { + action.onPress() + this.close() + } + + return ( + + + {action.label} + + + ) + } + + render() { + const { children, ...props } = this.props + + return ( + + {children} + + ) + } +} + +const styles = StyleSheet.create({ + actionText: { + backgroundColor: 'transparent', + fontSize: 16, + padding: 10, + }, + baseActionContainer: { + flex: 1, + justifyContent: 'center', + }, +}) diff --git a/src/libs/swipeable/BaseSwipeableRow.tsx b/src/libs/swipeable/BaseSwipeableRow.tsx new file mode 100644 index 00000000..494f7b47 --- /dev/null +++ b/src/libs/swipeable/BaseSwipeableRow.tsx @@ -0,0 +1,109 @@ +import React, { PureComponent } from 'react' +import { View } from 'react-native' + +enum BaseActionType { + BUTTON = 'BUTTON', + FULL = 'FULL', +} + +export interface IBaseAction { + color: string + key: string + onPress: () => void + textColor?: string + type?: BaseActionType + width?: number +} + +export interface IBaseProps { + leftActions: IBaseAction[] + rightActions: IBaseAction[] +} + +export interface IBaseState {} + +export enum Placement { + LEFT = 'LEFT', + RIGHT = 'RIGHT', +} + +export const defaultWidth = 64 + +export default class BaseSwipeableRow extends PureComponent { + _swipeableRow = null + + renderButtonAction = ( + action: IBaseAction, + { dragX, placement, progress, x }: { x: number; placement: Placement; progress: number }, + ) => { + throw new Error('Not implemented: renderButtonAction') + } + + renderFullAction = ( + action: IBaseAction, + { dragX, placement, progress }: { placement: Placement }, + ) => { + throw new Error('Not implemented: renderFullAction') + } + + renderLeftActions = (progress: number, dragX) => { + const { leftActions: actions } = this.props + + const fullAction = actions.find(action => action.type === 'FULL') + const buttonActions = actions.filter(action => action.type !== 'FULL') + + if (fullAction) return this.renderFullAction(fullAction, { dragX, placement: 'LEFT', progress }) + + const width = buttonActions.reduce((total, action) => total + (action.width || defaultWidth), 0) + let x = 0 + + return ( + + {buttonActions.map(action => { + x += action.width || defaultWidth + return this.renderButtonAction(action, { placement: 'LEFT', progress, x }) + })} + + ) + } + + renderRightActions = (progress: number, dragX) => { + const { rightActions: actions } = this.props + + const fullAction = actions.find(action => action.type === 'FULL') + const buttonActions = actions.filter(action => action.type !== 'FULL') + + if (fullAction) + return this.renderFullAction(fullAction, { dragX, placement: 'RIGHT', progress }) + + const width = buttonActions.reduce((total, action) => total + (action.width || defaultWidth), 0) + let x = width + + return ( + + {buttonActions.map(action => { + const component = this.renderButtonAction(action, { + dragX, + placement: 'RIGHT', + progress, + x, + }) + x -= action.width || defaultWidth + return component + })} + + ) + } + + updateRef = ref => { + this._swipeableRow = ref + } + + close = () => { + this._swipeableRow.close() + } + + render() { + throw new Error('Not implemented: render') + } +} diff --git a/src/libs/swipeable/GoogleSwipeableRow.tsx b/src/libs/swipeable/GoogleSwipeableRow.tsx new file mode 100644 index 00000000..295c60cf --- /dev/null +++ b/src/libs/swipeable/GoogleSwipeableRow.tsx @@ -0,0 +1,138 @@ +import React from 'react' +import { Animated, StyleSheet, Text } from 'react-native' +import { RectButton } from 'react-native-gesture-handler' +import Swipeable from 'react-native-gesture-handler/Swipeable' +import Icon from 'react-native-vector-icons/MaterialIcons' + +import BaseSwipeableRow, { IBaseAction, IBaseProps, Placement } from './BaseSwipeableRow' + +export { defaultWidth } from './BaseSwipeableRow' + +export interface IAction extends IBaseAction { + icon: string +} + +export interface IProps extends IBaseProps {} + +const AnimatedIcon = Animated.createAnimatedComponent(Icon) + +export default class GoogleSwipeableRow extends BaseSwipeableRow { + _swipeableRow = null + + renderButtonAction = ( + action: IAction, + { dragX, x, placement }: { x: number; placement: Placement }, + ) => { + const transform = { + scale: + placement === 'LEFT' + ? dragX.interpolate({ + inputRange: [x - 80, x], + outputRange: [0, 1], + extrapolate: 'clamp', + }) + : dragX.interpolate({ + inputRange: [-x, -x + 80], + outputRange: [1, 0], + extrapolate: 'clamp', + }), + } + + const pressHandler = () => { + action.onPress() + this.close() + alert(action.label) + } + + return ( + + + + ) + } + + renderFullAction = (action: IAction, { dragX, placement }: { placement: Placement }) => { + const transform = { + scale: + placement === 'LEFT' + ? dragX.interpolate({ + inputRange: [0, 80], + outputRange: [0, 1], + extrapolate: 'clamp', + }) + : dragX.interpolate({ + inputRange: [-80, 0], + outputRange: [1, 0], + extrapolate: 'clamp', + }), + } + + const pressHandler = () => { + action.onPress() + this.close() + } + + return ( + + + + ) + } + + render() { + const { children, ...props } = this.props + + return ( + + {children} + + ) + } +} + +const styles = StyleSheet.create({ + actionIcon: { + backgroundColor: 'transparent', + marginHorizontal: 10, + width: 30, + }, + baseActionContainer: { + flex: 1, + justifyContent: 'center', + }, +}) diff --git a/src/libs/swipeable/index.android.tsx b/src/libs/swipeable/index.android.tsx new file mode 100644 index 00000000..ea73bc8f --- /dev/null +++ b/src/libs/swipeable/index.android.tsx @@ -0,0 +1,3 @@ +import GoogleSwipeableRow from './GoogleSwipeableRow' + +export default GoogleSwipeableRow diff --git a/src/libs/swipeable/index.ios.tsx b/src/libs/swipeable/index.ios.tsx new file mode 100644 index 00000000..115aa9bb --- /dev/null +++ b/src/libs/swipeable/index.ios.tsx @@ -0,0 +1,3 @@ +import AppleSwipeableRow from './AppleSwipeableRow' + +export default AppleSwipeableRow diff --git a/src/styles/themes/base.ts b/src/styles/themes/base.ts new file mode 100755 index 00000000..40a44988 --- /dev/null +++ b/src/styles/themes/base.ts @@ -0,0 +1,20 @@ +export const lightBlue = '#49d3b4' +export const purple = '#6e5494' + +export const brand = lightBlue +export const brandSecondary = purple + +export const star = '#edb800' +export const blue = '#2196F3' +export const blueGray = '#607D8B' +export const brown = '#795548' +export const darkGray = '#444444' +export const gray = '#9E9E9E' +export const green = '#2cbe4e' +export const indigo = '#3F51B5' +export const orange = '#FF9800' +export const pink = '#E91E63' +export const lightRed = '#F44336' +export const red = '#cb2431' +export const teal = '#009688' +export const yellow = '#FFC107' diff --git a/src/styles/themes/dark-blue.ts b/src/styles/themes/dark-blue.ts new file mode 100755 index 00000000..a842b8ba --- /dev/null +++ b/src/styles/themes/dark-blue.ts @@ -0,0 +1,60 @@ +import Platform from '../../libs/platform' + +import * as base from './base' + +export const base00 = '#141c26' // page background +export const base01 = '#141c26' // card background -1 +export const base02 = '#1b2936' // card background 0 +export const base03 = '#243447' // card background +1 +export const base04 = '#dddddd' // color (to mute, use opacity 0.9 = #666666, #888888) +export const base05 = '#6b7d8c' // muted color +export const base06 = '#ffffff' // color high contrast +export const base07 = base.brand // brand 1 +export const base08 = base.brandSecondary // brand 2 +export const base09 = undefined +export const base0A = undefined +export const base0B = undefined +export const base0C = undefined +export const base0D = undefined +export const base0E = undefined +export const base0F = undefined + +export const base16 = { + base00, + base01, + base02, + base03, + base04, + base05, + base06, + base07, + base08, + base09, + base0A, + base0B, + base0C, + base0D, + base0E, + base0F, +} + +export const cardBackground = base02 +export const tabBarBackground = Platform.select({ + android: base01, + default: base02, +}) +export const statusBarBackground = Platform.select({ + android: tabBarBackground, + default: base01, +}) + +export default { + ...base, + ...base16, + cardBackground, + statusBarBackground, + tabBarBackground, + invert: () => require('./light').default, // tslint:disable-line + isDark: true, + name: 'dark-blue', +} diff --git a/src/styles/themes/dark.ts b/src/styles/themes/dark.ts new file mode 100755 index 00000000..3572c9d0 --- /dev/null +++ b/src/styles/themes/dark.ts @@ -0,0 +1,62 @@ +import { Platform } from 'react-native' + +import { fade } from '../../utils/helpers/color' +import { mutedOpacity } from '../variables' +import * as base from './base' + +export const base00 = '#1c1c1c' // page background +export const base01 = '#111111' // card background -1 +export const base02 = '#1c1c1c' // card background 0 +export const base03 = '#353535' // card background +1 +export const base04 = '#dddddd' // color (to mute, use opacity 0.9 = #666666, #888888) +export const base05 = fade(base04, mutedOpacity) // muted color +export const base06 = '#ffffff' // color high contrast +export const base07 = base.brand // brand 1 +export const base08 = base.brandSecondary // brand 2 +export const base09 = undefined // unread card background +export const base0A = undefined +export const base0B = undefined +export const base0C = undefined +export const base0D = undefined +export const base0E = undefined +export const base0F = undefined + +export const base16 = { + base00, + base01, + base02, + base03, + base04, + base05, + base06, + base07, + base08, + base09, + base0A, + base0B, + base0C, + base0D, + base0E, + base0F, +} + +export const cardBackground = base03 +export const tabBarBackground = Platform.select({ + android: base01, + default: base02, +}) +export const statusBarBackground = Platform.select({ + android: tabBarBackground, + default: base01, +}) + +export default { + ...base, + ...base16, + cardBackground, + statusBarBackground, + tabBarBackground, + invert: () => require('./light').default, // tslint:disable-line + isDark: true, + name: 'dark', +} diff --git a/src/styles/themes/index.ts b/src/styles/themes/index.ts new file mode 100755 index 00000000..2c484232 --- /dev/null +++ b/src/styles/themes/index.ts @@ -0,0 +1,13 @@ +import darkTheme from './dark' +import darkBlueTheme from './dark-blue' +import lightTheme from './light' + +export const DARK_THEME = darkTheme +export const DARK_BLUE_THEME = darkBlueTheme +export const LIGHT_THEME = lightTheme + +export default { + [DARK_THEME.name]: DARK_THEME, + [DARK_BLUE_THEME.name]: DARK_BLUE_THEME, + [LIGHT_THEME.name]: LIGHT_THEME, +} diff --git a/src/styles/themes/light.ts b/src/styles/themes/light.ts new file mode 100755 index 00000000..bfc9a38c --- /dev/null +++ b/src/styles/themes/light.ts @@ -0,0 +1,59 @@ +import { Platform } from 'react-native' + +import { lighten } from '../../utils/helpers/color' +import { mutedOpacity } from '../variables' +import * as base from './base' + +export const base00 = '#ffffff' // page background +export const base01 = '#ededed' // card background -1 +export const base02 = '#ffffff' // card background 0 +export const base03 = '#f0f0f0' // card background +1 +export const base04 = '#222222' // color +export const base05 = lighten('#222222', mutedOpacity).hex // muted color +export const base06 = '#000000' // color high contrast +export const base07 = base.brand // brand 1 +export const base08 = base.brandSecondary // brand 2 +export const base09 = undefined +export const base0A = undefined +export const base0B = undefined +export const base0C = undefined +export const base0D = undefined +export const base0E = undefined +export const base0F = undefined + +export const base16 = { + base00, + base01, + base02, + base03, + base04, + base05, + base06, + base07, + base08, + base09, + base0A, + base0B, + base0C, + base0D, + base0E, + base0F, +} + +export const cardBackground = base02 +export const tabBarBackground = base02 +export const statusBarBackground = Platform.select({ + android: tabBarBackground, + default: base01, +}) + +export default { + ...base, + ...base16, + cardBackground, + statusBarBackground, + tabBarBackground, + invert: () => require('./dark').default, // tslint:disable-line + isDark: false, + name: 'light', +} diff --git a/src/styles/variables.ts b/src/styles/variables.ts new file mode 100644 index 00000000..20c32d3e --- /dev/null +++ b/src/styles/variables.ts @@ -0,0 +1,6 @@ +export const avatarSize = 48 +export const contentPadding = 12 +export const mutedOpacity = 0.5 +export const radius = 4 +export const smallAvatarSize = avatarSize / 2 +export const smallTextSize = 12 diff --git a/src/utils/helpers/color.ts b/src/utils/helpers/color.ts new file mode 100644 index 00000000..cf8a1779 --- /dev/null +++ b/src/utils/helpers/color.ts @@ -0,0 +1,8 @@ +import warna from 'warna' + +export const { darken, lighten } = warna + +export function fade(color: string, opacity: number = 1) { + const { rgb } = warna.parse(color) + return `rgba(${rgb.red}, ${rgb.green}, ${rgb.blue}, ${opacity})` +} diff --git a/src/utils/helpers/github.ts b/src/utils/helpers/github.ts new file mode 100644 index 00000000..a7159d0e --- /dev/null +++ b/src/utils/helpers/github.ts @@ -0,0 +1,28 @@ +import gravatar from 'gravatar' + +import { getSteppedSize } from './shared' + +export function getUserAvatarByUsername(username: string, { size }: { size?: number } = {}) { + return username ? `https://github.com/${username}.png?size=${getSteppedSize(size)}` : '' +} + +export function tryGetUsernameFromGithubEmail(email: string) { + if (!email) return '' + + const emailSplit = email.split('@') + if (emailSplit.length === 2 && emailSplit[1] === 'users.noreply.github.com') return emailSplit[0] + + return '' +} + +export function getUserAvatarByEmail( + email: string, + { size, ...otherOptions }: { size?: number } = {}, +) { + const steppedSize = getSteppedSize(size) + const username = tryGetUsernameFromGithubEmail(email) + if (username) return getUserAvatarByUsername(username, { size: steppedSize }) + + const options = { size: `${steppedSize || ''}`, d: 'retro', ...otherOptions } + return `https:${gravatar.url(email, options)}`.replace('??', '?') +} diff --git a/src/utils/helpers/shared.ts b/src/utils/helpers/shared.ts new file mode 100644 index 00000000..b04541a7 --- /dev/null +++ b/src/utils/helpers/shared.ts @@ -0,0 +1,13 @@ +import { PixelRatio } from 'react-native' + +// sizes will be multiples of 50 for caching (e.g 50, 100, 150, ...) +export function getSteppedSize(size?: number, sizeSteps = 50) { + const steppedSize = + typeof size === 'number' ? sizeSteps * Math.max(1, Math.ceil(size / sizeSteps)) : sizeSteps + + return PixelRatio.getPixelSizeForLayoutSize(steppedSize) +} + +export function randomBetween(minNumber: number, maxNumber: number) { + return Math.floor(Math.random() * maxNumber) + minNumber +} diff --git a/src/utils/types.ts b/src/utils/types.ts new file mode 100644 index 00000000..ccd6e335 --- /dev/null +++ b/src/utils/types.ts @@ -0,0 +1,9 @@ +export interface IUser { + id: string + username: string +} + +export interface INotification { + id: string + actor: IUser +} diff --git a/tslint.json b/tslint.json index 3975e899..e9f120a9 100644 --- a/tslint.json +++ b/tslint.json @@ -3,12 +3,21 @@ "extends": ["tslint:recommended", "tslint-config-airbnb", "tslint-react"], "jsRules": {}, "rules": { - "semicolon": false, + "curly": false, + "import-name": false, + "jsx-boolean-value": false, + "jsx-no-multiline-js": false, "member-access": false, "no-empty-interface": false, - "import-name": false, - "curly": false, - "ter-arrow-parens": false + "semicolon": false, + "ter-arrow-parens": false, + "variable-name": [ + true, + "allow-leading-underscore", + "allow-pascal-case", + "ban-keywords", + "check-format" + ] }, "rulesDirectory": [] } diff --git a/yarn.lock b/yarn.lock index 144b6baa..984a33ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,27 @@ # yarn lockfile v1 +"@types/gravatar@^1.4.28": + version "1.4.28" + resolved "https://registry.yarnpkg.com/@types/gravatar/-/gravatar-1.4.28.tgz#a83527c354b3bce265ef489facfbed34971f9b16" + "@types/jest@^21.1.5": version "21.1.6" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-21.1.6.tgz#9467945ce33261e4fdd14276576951aa130515aa" +"@types/react-native-vector-icons@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@types/react-native-vector-icons/-/react-native-vector-icons-4.4.2.tgz#dd6b6a4d9dee7c85e3246f6c67905dbc1faee3d5" + dependencies: + "@types/react" "*" + "@types/react-native" "*" + +"@types/react-native@*": + version "0.51.0" + resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.51.0.tgz#322caad4224c258365a5afb17d8669939ee6d074" + dependencies: + "@types/react" "*" + "@types/react-native@^0.50.2": version "0.50.5" resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.50.5.tgz#d56742243851f4f55b0a55e460b94e605f9b38dd" @@ -887,6 +904,10 @@ block-stream@*: dependencies: inherits "~2.0.0" +blueimp-md5@^2.3.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.10.0.tgz#02f0843921f90dca14f5b8920a38593201d6964d" + body-parser@~1.13.3: version "1.13.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.13.3.tgz#c08cf330c3358e151016a05746f13f029c97fa97" @@ -979,6 +1000,10 @@ camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -1373,6 +1398,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +email-validator@^1.0.7: + version "1.1.1" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-1.1.1.tgz#b07f3be7bac1dc099bc43e75f6ae399f552d5a80" + encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -1795,6 +1824,15 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +gravatar@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/gravatar/-/gravatar-1.6.0.tgz#8bdc9b786ca725a8e7076416d1731f8d3331c976" + dependencies: + blueimp-md5 "^2.3.0" + email-validator "^1.0.7" + querystring "0.2.0" + yargs "^6.0.0" + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -2644,6 +2682,14 @@ lodash.escape@^3.0.0: dependencies: lodash._root "^3.0.0" +lodash.every@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.every/-/lodash.every-4.6.0.tgz#eb89984bebc4364279bb3aefbbd1ca19bfa6c6a7" + +lodash.filter@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -2652,6 +2698,18 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + +lodash.isfunction@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -2660,6 +2718,10 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" + lodash.pad@^4.1.0: version "4.5.1" resolved "https://registry.yarnpkg.com/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" @@ -2672,10 +2734,18 @@ lodash.padstart@^4.1.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" +lodash.pick@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" +lodash.some@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + lodash.template@^3.0.0: version "3.6.2" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" @@ -2697,11 +2767,15 @@ lodash.templatesettings@^3.0.0: lodash._reinterpolate "^3.0.0" lodash.escape "^3.0.0" +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + lodash@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.14.0, lodash@^4.16.6, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.6, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3107,6 +3181,12 @@ os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" @@ -3304,7 +3384,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.8, prop-types@^15.6.0: +prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" dependencies: @@ -3336,6 +3416,10 @@ qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" @@ -3383,6 +3467,13 @@ react-devtools-core@^2.5.0: shell-quote "^1.6.1" ws "^2.0.3" +react-native-gesture-handler@^1.0.0-alpha.35: + version "1.0.0-alpha.35" + resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.35.tgz#c16cf97151223cb8d4902d6dd597dc1612d8cb33" + dependencies: + invariant "^2.2.2" + prop-types "^15.5.10" + react-native-typescript-transformer@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/react-native-typescript-transformer/-/react-native-typescript-transformer-1.1.4.tgz#88bb6d2ccd63f0b4b3cbce99e96c0e9c9e83cabc" @@ -3391,6 +3482,14 @@ react-native-typescript-transformer@^1.1.4: jju "^1.3.0" source-map "^0.5.6" +react-native-vector-icons@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-4.4.2.tgz#090f42ee0396c4cc4eae0ddaa518028ba8df40c7" + dependencies: + lodash "^4.0.0" + prop-types "^15.5.10" + yargs "^8.0.2" + react-native@^0.51.0: version "0.51.0" resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.51.0.tgz#fe25934b3030fd323f3ca1a70f034133465955ed" @@ -4356,6 +4455,10 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" +warna@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/warna/-/warna-0.2.4.tgz#4c63e3db188f8b5176299526e5f95fc5c2e0dfb0" + watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" @@ -4392,6 +4495,10 @@ whatwg-url@^4.3.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -4402,6 +4509,20 @@ which@^1.2.12, which@^1.2.14, which@^1.2.9: dependencies: isexe "^2.0.0" +why-did-you-update@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/why-did-you-update/-/why-did-you-update-0.1.0.tgz#e523ff89d879bee4f4a4f7644a0621df9e2e7b76" + dependencies: + lodash.every "^4.6.0" + lodash.filter "^4.6.0" + lodash.isequal "^4.5.0" + lodash.isfunction "^3.0.8" + lodash.isstring "^4.0.1" + lodash.keys "^4.2.0" + lodash.pick "^4.4.0" + lodash.some "^4.6.0" + lodash.union "^4.6.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -4526,6 +4647,12 @@ yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" @@ -4555,6 +4682,42 @@ yargs@^10.0.3: y18n "^3.2.1" yargs-parser "^8.0.0" +yargs@^6.0.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + yargs@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c"