├── .babelrc ├── .editorconfig ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .tern-project ├── .watchmanconfig ├── Colors.json ├── LICENSE.md ├── android ├── HeyNeighbor.iml ├── app │ ├── app.iml │ ├── build.gradle │ ├── fonts.gradle │ ├── proguard-rules.pro │ ├── react.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── fonts │ │ │ ├── Lato.ttf │ │ │ ├── Lato_bold.ttf │ │ │ ├── Lato_bold_talic.ttf │ │ │ └── Lato_italic.ttf │ │ ├── java │ │ └── io │ │ │ └── scrollback │ │ │ └── neighborhoods │ │ │ ├── AppState.java │ │ │ ├── HeyNeighbor.java │ │ │ ├── InstallReferrerReceiver.java │ │ │ ├── MainActivity.java │ │ │ ├── bundle │ │ │ ├── Checksum.java │ │ │ ├── IOHelpers.java │ │ │ └── JSBundleManager.java │ │ │ └── modules │ │ │ ├── analytics │ │ │ ├── AnalyticsPackage.java │ │ │ ├── AnswersInstallTracker.java │ │ │ ├── AnswersInstallTrackerModule.java │ │ │ ├── AnswersModule.java │ │ │ ├── LifeCycleTracker.java │ │ │ └── Trackers.java │ │ │ ├── core │ │ │ ├── BuildConfigModule.java │ │ │ ├── CorePackage.java │ │ │ ├── GeolocationModule.java │ │ │ ├── ShareModule.java │ │ │ ├── URLResolverModule.java │ │ │ └── VersionCodesModule.java │ │ │ ├── facebook │ │ │ ├── FacebookModule.java │ │ │ └── FacebookPackage.java │ │ │ ├── gcm │ │ │ ├── HeyNeighborNotification.java │ │ │ ├── PushNotificationBroadcastReceiver.java │ │ │ ├── PushNotificationHandler.java │ │ │ ├── PushNotificationIntentService.java │ │ │ ├── PushNotificationModule.java │ │ │ └── PushNotificationPackage.java │ │ │ ├── google │ │ │ ├── GoogleLoginModule.java │ │ │ └── GoogleLoginPackage.java │ │ │ └── places │ │ │ ├── GooglePlacesModule.java │ │ │ └── GooglePlacesPackage.java │ │ └── res │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_status.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_status.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_status.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_status.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_status.png │ │ ├── values-v19 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app ├── containers │ ├── AccountContainer.js │ ├── AppContainer.js │ ├── AvatarContainer.js │ ├── BannerOfflineContainer.js │ ├── ChatContainer.js │ ├── ChatItemContainer.js │ ├── ChatMessagesContainer.js │ ├── ChatSuggestionsContainer.js │ ├── ChatTitleContainer.js │ ├── Container.js │ ├── DiscussionDetailsContainer.js │ ├── DiscussionItemContainer.js │ ├── DiscussionsContainer.js │ ├── HomeContainer.js │ ├── ImageUploadContainer.js │ ├── LocalitiesContainer.js │ ├── LocalitiesFilteredContainer.js │ ├── LocalityTitleContainer.js │ ├── MyPlacesContainer.js │ ├── NotificationBadgeContainer.js │ ├── NotificationCenterContainer.js │ ├── NotificationClearIconContainer.js │ ├── PeopleListContainer.js │ ├── ShareButtonContainer.js │ ├── SignUpContainer.js │ ├── StartDiscussionContainer.js │ ├── StatesFilteredContainer.js │ └── UserIconContainer.js ├── extras │ ├── analytics │ │ ├── analytics.js │ │ └── signin.js │ ├── gcm │ │ └── gcm.js │ ├── oembed │ │ ├── oembed-storage.js │ │ ├── oembed-test.js │ │ ├── oembed.js │ │ ├── providers.js │ │ └── regexes.js │ ├── push-notification │ │ └── gcm.js │ └── syncjoin │ │ └── syncjoin.js ├── lib │ ├── URL.js │ ├── __tests__ │ │ └── URL-test.js │ ├── debounce.js │ ├── generate.browser.js │ ├── get-avatar.js │ ├── group-objects-test.js │ ├── group-objects.js │ ├── location-utils.js │ ├── obj-utils-test.js │ ├── obj-utils.js │ ├── pendingQueries.js │ ├── range-ops.js │ ├── smiley.js │ ├── text-utils.js │ ├── time-utils.js │ ├── user-utils.js │ ├── validator-strings.js │ ├── validator-test.js │ └── validator.js ├── mocks │ ├── AsyncStorage.js │ └── ReactNative.js ├── modules │ ├── Answers.android.js │ ├── BuildConfig.android.js │ ├── Facebook.android.js │ ├── Geolocation.android.js │ ├── GoogleLogin.android.js │ ├── ImageChooser.android.js │ ├── Linking.android.js │ ├── Linking.ios.js │ ├── PushNotification.android.js │ ├── Share.android.js │ ├── SocialShare.android.js │ ├── URLResolver.android.js │ └── VersionCodes.android.js ├── navigation-rfc │ ├── CustomComponents │ │ ├── NavigationCard.js │ │ ├── NavigationHeader.js │ │ └── NavigationHeaderTitle.js │ ├── Navigation │ │ ├── NavigationActions.js │ │ ├── NavigationAnimatedView.js │ │ ├── NavigationContainer.js │ │ ├── NavigationReducer.js │ │ ├── NavigationRootContainer.js │ │ ├── NavigationState.js │ │ └── NavigationView.js │ └── polyfill.js ├── navigation │ ├── PersistentNavigator.js │ ├── renderNavigator.js │ ├── renderOverlay.js │ └── renderScene.js ├── routes │ ├── Route.js │ ├── __tests__ │ │ └── Route-test.js │ └── routeMapper.js ├── store.orig │ ├── action-handler.js │ ├── add-user-timezone.js │ ├── bulkQuery.js │ ├── entity-ops.js │ ├── init-user-up-manager.js │ ├── permissionWeights.js │ ├── property-list.js │ ├── rule-manager.js │ ├── rules │ │ ├── clearQueuedActions.js │ │ ├── handleUserPresence.js │ │ ├── loadRelatedUsers.js │ │ ├── loadRooms.js │ │ ├── loadTextsOnNav.js │ │ ├── loadThread.js │ │ ├── loadThreadsOnNav.js │ │ ├── manageNotes.js │ │ └── removeRelations.js │ ├── session-manager.js │ ├── socket.js │ ├── state-manager.js │ ├── store.js │ └── test │ │ ├── range-ops-test.js │ │ ├── range-test.js │ │ ├── state-manager-test.js │ │ └── test.js ├── store │ ├── actions.js │ ├── config.js │ ├── core.js │ ├── init.js │ └── store.js └── views │ ├── Account │ ├── Account.js │ ├── AccountButton.js │ ├── AccountPhotoChooser.js │ ├── AccountPhotoChooserItem.js │ ├── MyPlaces.js │ ├── PlaceButton.js │ ├── PlaceItem.js │ └── PlaceManager.js │ ├── App.js │ ├── AppText.js │ ├── AppTextInput.js │ ├── AppbarIcon.js │ ├── AppbarSecondary.js │ ├── AppbarTitle.js │ ├── AppbarTouchable.js │ ├── Avatar.android.js │ ├── Avatar.js │ ├── AvatarRound.js │ ├── Banner.js │ ├── BannerOffline.js │ ├── BannerUnavailable.js │ ├── Card.js │ ├── CardAuthor.js │ ├── CardSummary.js │ ├── CardTitle.js │ ├── Chat.js │ ├── ChatBubble.js │ ├── ChatInput.js │ ├── ChatItem.js │ ├── ChatMessages.js │ ├── ChatSuggestions.js │ ├── ChatTitle.js │ ├── CloseButton.js │ ├── DiscussionDetails.js │ ├── DiscussionDetailsCard.js │ ├── DiscussionFooter.js │ ├── DiscussionItem.js │ ├── DiscussionSummary.js │ ├── Discussions.js │ ├── Embed.js │ ├── EmbedSummary.js │ ├── EmbedThumbnail.js │ ├── EmbedTitle.js │ ├── FloatingActionButton.js │ ├── GrowingTextInput.js │ ├── Home.js │ ├── Icon.android.js │ ├── ImageUploadButton.js │ ├── ImageUploadChat.js │ ├── ImageUploadDiscussion.js │ ├── KeyboardSpacer.js │ ├── Link.js │ ├── ListHeader.js │ ├── ListItem.js │ ├── Loading.android.js │ ├── LoadingFancy.js │ ├── LoadingItem.js │ ├── Localities.js │ ├── LocalitiesFiltered.js │ ├── LocalityItem.js │ ├── LocalityTitle.js │ ├── Modal.js │ ├── ModalSheet.js │ ├── NotificationBadge.js │ ├── NotificationCenter.js │ ├── NotificationCenterItem.js │ ├── NotificationClearIcon.js │ ├── NotificationIcon.js │ ├── Offline.js │ ├── Onboard │ ├── GetStarted.js │ ├── LargeButton.js │ ├── LocationDetails.js │ ├── NextButton.js │ ├── NextButtonLabel.js │ ├── Onboard.js │ ├── OnboardError.js │ ├── OnboardParagraph.js │ ├── OnboardTitle.js │ ├── SignIn.js │ ├── SignUp.js │ └── UserDetails.js │ ├── Page.js │ ├── PageEmpty.js │ ├── PageLoading.js │ ├── PeopleList.js │ ├── PeopleListItem.js │ ├── RichText.js │ ├── SearchButton.android.js │ ├── SearchableList.js │ ├── Searchbar.js │ ├── ShareButton.js │ ├── Splash.js │ ├── StartDiscussion.js │ ├── StartDiscussionButton.js │ ├── StateItem.js │ ├── StatesFiltered.js │ ├── StatusbarWrapper.js │ ├── Time.js │ ├── TouchFeedback.js │ ├── UpgradeBanner.js │ └── UserIcon.js ├── assets ├── astronaut.png ├── astronaut@1.5x.png ├── astronaut@2x.png ├── astronaut@3x.png ├── astronaut@4x.png ├── logo.png ├── logo@1.5x.png ├── logo@2x.png ├── logo@3x.png ├── logo@4x.png ├── logotype.png ├── logotype@1.5x.png ├── logotype@2x.png ├── logotype@3x.png ├── logotype@4x.png ├── monkey-cool.png ├── monkey-cool@1.5x.png ├── monkey-cool@2x.png ├── monkey-cool@3x.png ├── monkey-cool@4x.png ├── monkey-happy.png ├── monkey-happy@1.5x.png ├── monkey-happy@2x.png ├── monkey-happy@3x.png ├── monkey-happy@4x.png ├── monkey-meh.png ├── monkey-meh@1.5x.png ├── monkey-meh@2x.png ├── monkey-meh@3x.png ├── monkey-meh@4x.png ├── monkey-sad.png ├── monkey-sad@1.5x.png ├── monkey-sad@2x.png ├── monkey-sad@3x.png ├── monkey-sad@4x.png ├── open-door.png ├── open-door@1.5x.png ├── open-door@2x.png ├── open-door@3x.png ├── open-door@4x.png ├── scrollback_logo.png ├── scrollback_logo@1.5x.png ├── scrollback_logo@2x.png ├── scrollback_logo@3x.png ├── scrollback_logo@4x.png ├── signin_bg.jpg ├── signin_bg@1.5x.jpg ├── signin_bg@2x.jpg ├── signin_bg@3x.jpg ├── triangle_left.png ├── triangle_left@1.5x.png ├── triangle_left@2x.png ├── triangle_left@3x.png ├── triangle_left@4x.png ├── triangle_right.png ├── triangle_right@1.5x.png ├── triangle_right@2x.png ├── triangle_right@3x.png └── triangle_right@4x.png ├── config-defaults.json ├── config.json ├── index.android.js ├── index.ios.js ├── ios ├── HeyNeighbor.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── HeyNeighbor.xcscheme ├── HeyNeighbor │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── HeyNeighborTests │ ├── HeyNeighborTests.m │ └── Info.plist ├── package.json └── tools ├── .eslintrc └── bundle.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-native/packager/react-packager/.babelrc" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = tab 12 | indent_size = 4 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [*.{yml,yaml}] 24 | indent_style = space 25 | indent_size = 2 26 | 27 | [*.{java,css,less,scss}] 28 | indent_style = space 29 | indent_size = 4 30 | 31 | [{package,bower}.json] 32 | indent_style = space 33 | indent_size = 2 34 | 35 | [{.eslintrc,.babelrc}] 36 | indent_style = space 37 | indent_size = 2 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # node.js 26 | # 27 | node_modules/ 28 | npm-debug.log 29 | 30 | # Android 31 | # 32 | 33 | # Built application files 34 | *.apk 35 | *.ap_ 36 | 37 | # Files for the Dalvik VM 38 | *.dex 39 | 40 | # Java class files 41 | *.class 42 | 43 | # Generated files 44 | bin/ 45 | gen/ 46 | 47 | # Gradle files 48 | .gradle/ 49 | build/ 50 | /*/build/ 51 | 52 | # Local configuration file (sdk path, etc) 53 | local.properties 54 | 55 | # Proguard folder generated by Eclipse 56 | proguard/ 57 | 58 | # Log Files 59 | *.log 60 | 61 | # Keystore 62 | *.jks 63 | *.keystore 64 | 65 | # IDE 66 | .idea 67 | 68 | # Fabric 69 | fabric.properties 70 | com_crashlytics_export_strings.xml 71 | 72 | # Appvirality 73 | appvirality.properties 74 | 75 | # Built files 76 | index.android.bundle 77 | index.ios.bundle 78 | 79 | # Hey Neighbor 80 | server-config.js 81 | client-config.js 82 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaVersion": 6, 3 | "libs": [], 4 | "plugins": { 5 | "complete_strings": {}, 6 | "doc_comment": { 7 | "fullDocs": true 8 | }, 9 | "node": {}, 10 | "modules": {}, 11 | "es_modules": {} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "white": "#fff", 3 | "black": "#000", 4 | "grey": "#999", 5 | "lightGrey": "#eee", 6 | "darkGrey": "#444", 7 | "primary": "#673ab7", 8 | "accent": "#ff9419", 9 | "badge": "#e91e63", 10 | "info": "#2196f3", 11 | "error": "#f44336", 12 | "success": "#4caf50", 13 | "google": "#488ef1", 14 | "facebook": "#3b5998", 15 | "fadedWhite": "rgba(255, 255, 255, .5)", 16 | "fadedBlack": "rgba(0, 0, 0, .5)", 17 | "separator": "rgba(0, 0, 0, .08)", 18 | "underlay": "rgba(0, 0, 0, .12)", 19 | "placeholder": "rgba(0, 0, 0, .16)" 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Askabt. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /android/HeyNeighbor.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/fonts.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Task to copy icon font files 3 | */ 4 | def iconFontsDir = '../../node_modules/react-native-vector-icons/Fonts'; 5 | def iconFontNames = [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ]; 6 | 7 | task copyDebugIconFonts(type: Copy) { 8 | iconFontNames.each { name -> 9 | from("$iconFontsDir/$name") 10 | into("$buildDir/intermediates/assets/debug/fonts/") 11 | } 12 | } 13 | 14 | task copyReleaseIconFonts(type: Copy) { 15 | iconFontNames.each { name -> 16 | from("$iconFontsDir/$name") 17 | into("$buildDir/intermediates/assets/release/fonts/") 18 | } 19 | } 20 | 21 | gradle.projectsEvaluated { 22 | generateDebugAssets.dependsOn copyDebugIconFonts 23 | generateReleaseAssets.dependsOn copyReleaseIconFonts 24 | } 25 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Lato.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/assets/fonts/Lato.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Lato_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/assets/fonts/Lato_bold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Lato_bold_talic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/assets/fonts/Lato_bold_talic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Lato_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/assets/fonts/Lato_italic.ttf -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/AppState.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | 7 | public class AppState implements Application.ActivityLifecycleCallbacks { 8 | 9 | private static AppState instance; 10 | private static boolean foreground; 11 | 12 | public static void init(Application app) { 13 | if (instance == null) { 14 | instance = new AppState(); 15 | 16 | app.registerActivityLifecycleCallbacks(instance); 17 | } 18 | } 19 | 20 | public static boolean isForeground() { 21 | return foreground; 22 | } 23 | 24 | @Override 25 | public void onActivityPaused(Activity activity) { 26 | foreground = false; 27 | } 28 | 29 | @Override 30 | public void onActivityResumed(Activity activity) { 31 | foreground = true; 32 | } 33 | 34 | @Override 35 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 36 | } 37 | 38 | @Override 39 | public void onActivityStarted(Activity activity) { 40 | } 41 | 42 | @Override 43 | public void onActivityStopped(Activity activity) { 44 | } 45 | 46 | @Override 47 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) { 48 | } 49 | 50 | @Override 51 | public void onActivityDestroyed(Activity activity) { 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/HeyNeighbor.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods; 2 | 3 | import android.app.Application; 4 | 5 | import com.crashlytics.android.Crashlytics; 6 | 7 | import io.fabric.sdk.android.Fabric; 8 | import io.scrollback.neighborhoods.modules.analytics.LifeCycleTracker; 9 | 10 | public class HeyNeighbor extends Application { 11 | @Override 12 | public void onCreate() { 13 | super.onCreate(); 14 | 15 | Fabric.with(this, new Crashlytics()); 16 | 17 | AppState.init(this); 18 | LifeCycleTracker.init(this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/InstallReferrerReceiver.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import io.scrollback.neighborhoods.modules.analytics.AnswersInstallTracker; 8 | 9 | public class InstallReferrerReceiver extends BroadcastReceiver { 10 | 11 | @Override 12 | public void onReceive(Context context, Intent intent) { 13 | if (intent != null && intent.getAction().equals("com.android.vending.INSTALL_REFERRER")) { 14 | final String referrer = intent.getStringExtra("referrer"); 15 | 16 | if (referrer != null && referrer.length() != 0) { 17 | AnswersInstallTracker.getInstance(context).setReferrer(referrer); 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/bundle/Checksum.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.bundle; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.math.BigInteger; 10 | import java.security.MessageDigest; 11 | import java.security.NoSuchAlgorithmException; 12 | 13 | public class Checksum { 14 | public static String MD5(@NonNull InputStream stream) throws IOException, NoSuchAlgorithmException { 15 | MessageDigest md = MessageDigest.getInstance("MD5"); 16 | 17 | byte[] buffer = new byte[8192]; 18 | int numOfBytesRead; 19 | 20 | while ((numOfBytesRead = stream.read(buffer)) > 0) { 21 | md.update(buffer, 0, numOfBytesRead); 22 | } 23 | 24 | byte[] hash = md.digest(); 25 | 26 | return String.format("%032x", new BigInteger(1, hash)); 27 | } 28 | 29 | public static String MD5(@NonNull File file) throws IOException, NoSuchAlgorithmException { 30 | InputStream stream = new FileInputStream(file); 31 | 32 | try { 33 | return MD5(stream); 34 | } finally { 35 | stream.close(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/analytics/AnalyticsPackage.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.analytics; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class AnalyticsPackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList( 18 | new AnswersModule(reactContext), 19 | new AnswersInstallTrackerModule(reactContext) 20 | ); 21 | } 22 | 23 | @Override 24 | public List> createJSModules() { 25 | return Collections.emptyList(); 26 | } 27 | 28 | @Override 29 | public List createViewManagers(ReactApplicationContext reactContext) { 30 | return Collections.emptyList(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/analytics/LifeCycleTracker.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.analytics; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | 7 | import java.util.Date; 8 | 9 | public class LifeCycleTracker implements Application.ActivityLifecycleCallbacks { 10 | 11 | private static final String EVENT_NAME = "App Usage"; 12 | 13 | private static LifeCycleTracker instance; 14 | private Date startTime; 15 | 16 | public static void init(Application app) { 17 | if (instance == null) { 18 | instance = new LifeCycleTracker(); 19 | 20 | app.registerActivityLifecycleCallbacks(instance); 21 | } 22 | } 23 | 24 | @Override 25 | public void onActivityPaused(Activity activity) { 26 | Trackers.logTiming(EVENT_NAME, startTime, new Date()); 27 | } 28 | 29 | @Override 30 | public void onActivityResumed(Activity activity) { 31 | startTime = new Date(); 32 | } 33 | 34 | @Override 35 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 36 | } 37 | 38 | @Override 39 | public void onActivityStarted(Activity activity) { 40 | } 41 | 42 | @Override 43 | public void onActivityStopped(Activity activity) { 44 | } 45 | 46 | @Override 47 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) { 48 | } 49 | 50 | @Override 51 | public void onActivityDestroyed(Activity activity) { 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/core/BuildConfigModule.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.core; 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext; 4 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import io.scrollback.neighborhoods.BuildConfig; 10 | 11 | public class BuildConfigModule extends ReactContextBaseJavaModule { 12 | 13 | public BuildConfigModule(ReactApplicationContext reactContext) { 14 | super(reactContext); 15 | } 16 | 17 | @Override 18 | public String getName() { 19 | return "BuildConfigModule"; 20 | } 21 | 22 | @Override 23 | public Map getConstants() { 24 | final Map constants = new HashMap<>(); 25 | 26 | constants.put("APPLICATION_ID", BuildConfig.APPLICATION_ID); 27 | constants.put("BUILD_TYPE", BuildConfig.BUILD_TYPE); 28 | constants.put("DEBUG", BuildConfig.DEBUG); 29 | constants.put("FLAVOR", BuildConfig.FLAVOR); 30 | constants.put("VERSION_CODE", BuildConfig.VERSION_CODE); 31 | constants.put("VERSION_NAME", BuildConfig.VERSION_NAME); 32 | 33 | return constants; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/core/CorePackage.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.core; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class CorePackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList( 18 | new BuildConfigModule(reactContext), 19 | new VersionCodesModule(reactContext), 20 | new URLResolverModule(reactContext), 21 | new GeolocationModule(reactContext), 22 | new ShareModule(reactContext) 23 | ); 24 | } 25 | 26 | @Override 27 | public List> createJSModules() { 28 | return Collections.emptyList(); 29 | } 30 | 31 | @Override 32 | public List createViewManagers(ReactApplicationContext reactContext) { 33 | return Arrays.asList(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/core/ShareModule.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.core; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | 6 | import com.facebook.react.bridge.Promise; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 9 | import com.facebook.react.bridge.ReactMethod; 10 | 11 | public class ShareModule extends ReactContextBaseJavaModule { 12 | 13 | private static final String ACTIVITY_DOES_NOT_EXIST_ERROR = "Activity doesn't exist"; 14 | 15 | public ShareModule(ReactApplicationContext reactContext) { 16 | super(reactContext); 17 | } 18 | 19 | @Override 20 | public String getName() { 21 | return "ShareModule"; 22 | } 23 | 24 | @ReactMethod 25 | public void shareItem(final String title, final String content, final Promise promise) { 26 | Intent sharingIntent = new Intent(Intent.ACTION_SEND); 27 | 28 | sharingIntent.setType("text/plain"); 29 | sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, content); 30 | 31 | Activity currentActivity = getCurrentActivity(); 32 | 33 | if (currentActivity != null) { 34 | currentActivity.startActivity(Intent.createChooser(sharingIntent, title)); 35 | promise.resolve(true); 36 | } else { 37 | promise.reject(ACTIVITY_DOES_NOT_EXIST_ERROR); 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/facebook/FacebookPackage.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.facebook; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class FacebookPackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList(new FacebookModule(reactContext)); 18 | } 19 | 20 | @Override 21 | public List> createJSModules() { 22 | return Collections.emptyList(); 23 | } 24 | 25 | @Override 26 | public List createViewManagers(ReactApplicationContext reactContext) { 27 | return Collections.emptyList(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/gcm/PushNotificationBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.gcm; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.support.v4.content.WakefulBroadcastReceiver; 8 | 9 | public class PushNotificationBroadcastReceiver extends WakefulBroadcastReceiver { 10 | @Override 11 | public void onReceive(Context context, Intent intent) { 12 | // Explicitly specify that the IntentService will handle the intent. 13 | ComponentName comp = new ComponentName(context.getPackageName(), PushNotificationIntentService.class.getName()); 14 | 15 | // Start the service, keeping the device awake while it is launching. 16 | startWakefulService(context, (intent.setComponent(comp))); 17 | 18 | setResultCode(Activity.RESULT_OK); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/gcm/PushNotificationIntentService.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.gcm; 2 | 3 | import android.app.IntentService; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | 8 | import com.google.android.gms.gcm.GoogleCloudMessaging; 9 | 10 | public class PushNotificationIntentService extends IntentService { 11 | 12 | private static final String TAG = "GCM"; 13 | private static final int NOTIFICATION_ID = 1; 14 | 15 | public PushNotificationIntentService() { 16 | super("PushNotificationIntentService"); 17 | } 18 | 19 | @Override 20 | protected void onHandleIntent(Intent intent) { 21 | if (intent == null) { 22 | return; 23 | } 24 | 25 | Bundle extras = intent.getExtras(); 26 | GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); 27 | 28 | // The getMessageType() intent parameter must be the intent you received 29 | // in your BroadcastReceiver. 30 | String messageType = gcm.getMessageType(intent); 31 | 32 | if (!extras.isEmpty()) { 33 | if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { 34 | Log.e(TAG, "Error in sending message: " + extras.toString()); 35 | } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) { 36 | Log.e(TAG, "Messages deleted on server: " + extras.toString()); 37 | } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { 38 | // If it's a regular GCM message, do some work 39 | Log.d(TAG, "Payload received: " + extras.toString()); 40 | 41 | new PushNotificationHandler(this).handleNotification(NOTIFICATION_ID, HeyNeighborNotification.fromBundle(this, extras)); 42 | } 43 | } 44 | 45 | // Release the wake lock provided by the WakefulBroadcastReceiver. 46 | PushNotificationBroadcastReceiver.completeWakefulIntent(intent); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/gcm/PushNotificationPackage.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.gcm; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class PushNotificationPackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList( 18 | new PushNotificationModule(reactContext) 19 | ); 20 | } 21 | 22 | @Override 23 | public List> createJSModules() { 24 | return Collections.emptyList(); 25 | } 26 | 27 | @Override 28 | public List createViewManagers(ReactApplicationContext reactContext) { 29 | return Collections.emptyList(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/google/GoogleLoginPackage.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.google; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class GoogleLoginPackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList(new GoogleLoginModule(reactContext)); 18 | } 19 | 20 | @Override 21 | public List> createJSModules() { 22 | return Collections.emptyList(); 23 | } 24 | 25 | @Override 26 | public List createViewManagers(ReactApplicationContext reactContext) { 27 | return Collections.emptyList(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/scrollback/neighborhoods/modules/places/GooglePlacesPackage.java: -------------------------------------------------------------------------------- 1 | package io.scrollback.neighborhoods.modules.places; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | 14 | public class GooglePlacesPackage implements ReactPackage { 15 | 16 | @Override 17 | public List createNativeModules(ReactApplicationContext reactContext) { 18 | return Arrays.asList(new GooglePlacesModule(reactContext)); 19 | } 20 | 21 | @Override 22 | public List> createJSModules() { 23 | return Collections.emptyList(); 24 | } 25 | 26 | @Override 27 | public List createViewManagers(ReactApplicationContext reactContext) { 28 | return Collections.emptyList(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-hdpi/ic_status.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-mdpi/ic_status.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-xhdpi/ic_status.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-xxhdpi/ic_status.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/app/src/main/res/mipmap-xxxhdpi/ic_status.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-v19/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #673ab7 3 | #563099 4 | #ff9800 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | heyneighbor.chat 3 | https: 4 | Hey, Neighbor! 5 | 1389363534614084 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrollback/io.scrollback.neighborhoods/de5f8d0792cbd64230cdec7534c38fa29e906f22/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'HeyNeighbor' 2 | 3 | include ':app' 4 | 5 | include ':react-native-image-chooser' 6 | project(':react-native-image-chooser').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-chooser/android') 7 | -------------------------------------------------------------------------------- /app/containers/AccountContainer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React from 'react-native'; 4 | import Account from '../views/Account/Account'; 5 | import Container from './Container'; 6 | import store from '../store/store'; 7 | 8 | class AccountContainer extends React.Component { 9 | state = { 10 | user: 'missing' 11 | }; 12 | 13 | componentDidMount() { 14 | this.runAfterInteractions(this._updateData); 15 | 16 | this.handle('statechange', changes => { 17 | const user = store.get('user'); 18 | 19 | if (changes.entities && changes.entities[user]) { 20 | this._updateData(); 21 | } 22 | }); 23 | } 24 | 25 | _updateData = () => { 26 | this.setState({ 27 | user: store.getUser() 28 | }); 29 | }; 30 | 31 | _saveUser = user => { 32 | this.dispatch('user', { 33 | to: user.id, 34 | user 35 | }); 36 | 37 | this.setState({ user }); 38 | }; 39 | 40 | _signOut = () => { 41 | this.emit('logout'); 42 | }; 43 | 44 | render() { 45 | return ( 46 | 52 | ); 53 | } 54 | } 55 | 56 | export default Container(AccountContainer); 57 | -------------------------------------------------------------------------------- /app/containers/AppContainer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React from 'react-native'; 4 | import App from '../views/App'; 5 | import Container from './Container'; 6 | import store from '../store/store'; 7 | 8 | class AppContainer extends React.Component { 9 | state = { 10 | user: 'missing', 11 | connectionStatus: 'connecting' 12 | }; 13 | 14 | componentDidMount() { 15 | this.handle('statechange', changes => { 16 | if (changes && 'user' in changes || this.state.user === 'missing' && changes.app.connectionStatus) { 17 | this._updateData(); 18 | } 19 | }); 20 | } 21 | 22 | _updateData = () => { 23 | const user = store.get('user'); 24 | const connectionStatus = store.get('app', 'connectionStatus') || 'connecting'; 25 | 26 | if (user && user !== this.state.user) { 27 | this.setState({ 28 | user, 29 | connectionStatus 30 | }); 31 | } else if (connectionStatus !== this.state.connectionStatus) { 32 | this.setState({ 33 | connectionStatus 34 | }); 35 | } 36 | }; 37 | 38 | render() { 39 | return ; 40 | } 41 | } 42 | 43 | export default Container(AppContainer); 44 | -------------------------------------------------------------------------------- /app/containers/AvatarContainer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React from 'react-native'; 4 | import Avatar from '../views/Avatar'; 5 | import Container from './Container'; 6 | import store from '../store/store'; 7 | import config from '../store/config'; 8 | import getAvatar from '../lib/get-avatar'; 9 | 10 | const { 11 | PixelRatio 12 | } = React; 13 | 14 | class AvatarContainer extends React.Component { 15 | 16 | static propTypes = { 17 | nick: React.PropTypes.string.isRequired, 18 | size: React.PropTypes.number 19 | }; 20 | 21 | static defaultProps = { 22 | size: 48 23 | }; 24 | 25 | state = { 26 | uri: null 27 | }; 28 | 29 | componentDidMount() { 30 | this.runAfterInteractions(this._updateData); 31 | 32 | this.handle('statechange', changes => { 33 | if (changes.entities && changes.entities[this.props.nick]) { 34 | this._updateData(); 35 | } 36 | }); 37 | } 38 | 39 | _updateData = () => { 40 | const { protocol, host } = config.server; 41 | const { nick, size } = this.props; 42 | 43 | const user = store.getUser(nick); 44 | 45 | let uri; 46 | 47 | if (user && user.picture) { 48 | uri = getAvatar(user.picture, (size * PixelRatio.get())); 49 | } else { 50 | uri = protocol + '//' + host + '/i/' + nick + '/picture?size=' + (size * PixelRatio.get()); 51 | } 52 | 53 | this.setState({ 54 | uri 55 | }); 56 | }; 57 | 58 | render() { 59 | return ; 60 | } 61 | } 62 | 63 | export default Container(AvatarContainer); 64 | -------------------------------------------------------------------------------- /app/containers/BannerOfflineContainer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React from 'react-native'; 4 | import BannerOffline from '../views/BannerOffline'; 5 | import Container from './Container'; 6 | import store from '../store/store'; 7 | 8 | class BannerOfflineContainer extends React.Component { 9 | state = { 10 | connectionStatus: null 11 | }; 12 | 13 | componentDidMount() { 14 | this.runAfterInteractions(this._updateData); 15 | 16 | this.handle('statechange', changes => { 17 | if (changes.app && changes.app.connectionStatus) { 18 | this._updateData(); 19 | } 20 | }); 21 | } 22 | 23 | _updateData = () => { 24 | this.setState({ 25 | connectionStatus: store.get('app', 'connectionStatus') 26 | }); 27 | }; 28 | 29 | render() { 30 | return ( 31 | 32 | ); 33 | } 34 | } 35 | 36 | export default Container(BannerOfflineContainer); 37 | -------------------------------------------------------------------------------- /app/containers/ChatContainer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React from 'react-native'; 4 | import Chat from '../views/Chat'; 5 | import Container from './Container'; 6 | import store from '../store/store'; 7 | 8 | class ChatContainer extends React.Component { 9 | static propTypes = { 10 | room: React.PropTypes.string.isRequired, 11 | thread: React.PropTypes.string.isRequired 12 | }; 13 | 14 | state = { 15 | user: 'missing' 16 | }; 17 | 18 | componentDidMount() { 19 | this.runAfterInteractions(this._updateData); 20 | } 21 | 22 | _updateData = () => { 23 | this.setState({ 24 | user: store.get('user') 25 | }); 26 | }; 27 | 28 | _sendMessage = (text, textId) => { 29 | const textObj = { 30 | id: null, 31 | text: text.trim(), 32 | thread: this.props.thread, 33 | to: this.props.room, 34 | from: this.state.user 35 | }; 36 | 37 | if (textId) { 38 | textObj.id = textId; 39 | } 40 | 41 | this.dispatch('text', textObj); 42 | }; 43 | 44 | render() { 45 | return ( 46 | 51 | ); 52 | } 53 | } 54 | 55 | export default Container(ChatContainer); 56 | -------------------------------------------------------------------------------- /app/containers/ChatItemContainer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React from 'react-native'; 4 | import ChatItem from '../views/ChatItem'; 5 | import Container from './Container'; 6 | import store from '../store/store'; 7 | import actions from '../store/actions'; 8 | 9 | class ChatItemContainer extends React.Component { 10 | static propTypes = { 11 | text: React.PropTypes.shape({ 12 | id: React.PropTypes.string.isRequired, 13 | from: React.PropTypes.string.isRequired, 14 | to: React.PropTypes.string.isRequired 15 | }).isRequired 16 | }; 17 | 18 | _isUserAdmin = () => { 19 | return store.isUserAdmin(store.get('user'), this.props.text.to); 20 | }; 21 | 22 | _isUserBanned = () => { 23 | return store.isUserBanned(this.props.text.from, this.props.text.to); 24 | }; 25 | 26 | _hideText = () => { 27 | return actions.hideText(this.props.text); 28 | }; 29 | 30 | _unhideText = () => { 31 | return actions.unhideText(this.props.text); 32 | }; 33 | 34 | _banUser = () => { 35 | return actions.banUser(this.props.text); 36 | }; 37 | 38 | _unbanUser = () => { 39 | return actions.unbanUser(this.props.text); 40 | }; 41 | 42 | render() { 43 | return ( 44 |