├── .github └── FUNDING.yml ├── ios ├── zulip.mp3 ├── zulip-logo.png ├── ZulipMobile │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-20x20@2x.png │ │ │ ├── Icon-20x20@3x.png │ │ │ ├── Icon-29x29@2x.png │ │ │ ├── Icon-29x29@3x.png │ │ │ ├── Icon-40x40@2x.png │ │ │ ├── Icon-40x40@3x.png │ │ │ ├── Icon-60x60@2x.png │ │ │ ├── Icon-60x60@3x.png │ │ │ ├── Icon-76x76@2x.png │ │ │ ├── Icon-1024x1024@1x.png │ │ │ └── Icon-83.5x83.5@2x.png │ │ └── Brand.colorset │ │ │ └── Contents.json │ ├── UtilManager.h │ ├── main.m │ ├── ZLPConstantsBridge.m │ ├── AppDelegate.h │ ├── ZulipMobile.entitlements │ ├── ZLPNotificationsBridge.m │ └── UtilManager.m ├── ZulipMobile.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── upload.plist └── ZulipMobile-Bridging-Header.h ├── static ├── img │ ├── logo.png │ ├── app-store-badge.png │ ├── apple-logo-black.png │ ├── apple-logo-white.png │ ├── google-play-badge.png │ ├── google_auth_logo.png │ ├── message-loading.png │ ├── spinning-progress.png │ ├── spinning-progress-black.png │ └── spinning-progress-white.png ├── assets │ └── fonts │ │ ├── zulip-icons.ttf │ │ └── zulip-icons.map.js └── icons │ └── follow.svg ├── fastlane └── metadata │ └── android │ └── en-US │ ├── short_description.txt │ ├── images │ └── phoneScreenshots │ │ └── 1.png │ └── full_description.txt ├── types ├── expo-application │ ├── build │ │ ├── Application.types.js.flow │ │ └── ExpoApplication.js.flow │ └── index.js.flow ├── expo-modules-core │ ├── index.js.flow │ ├── build │ │ ├── sweet │ │ │ ├── setUpErrorManager.fx.js.flow │ │ │ └── NativeErrorManager.js.flow │ │ ├── SyntheticPlatformEmitter.js.flow │ │ ├── NativeViewManagerAdapter.js.flow │ │ ├── errors │ │ │ ├── CodedError.js.flow │ │ │ └── UnavailabilityError.js.flow │ │ ├── NativeViewManagerAdapter.native.js.flow │ │ ├── NativeModulesProxy.js.flow │ │ ├── NativeModulesProxy.native.js.flow │ │ ├── NativeModulesProxy.types.js.flow │ │ ├── deprecate.js.flow │ │ ├── requireNativeModule.js.flow │ │ ├── environment │ │ │ └── browser.js.flow │ │ ├── PermissionsInterface.js.flow │ │ └── Platform.js.flow │ └── src │ │ └── ts-declarations │ │ └── NativeEventEmitter.js.flow ├── expo-web-browser │ ├── index.js.flow │ └── build │ │ └── ExpoWebBrowser.js.flow ├── expo-mail-composer │ ├── index.js.flow │ └── build │ │ ├── ExpoMailComposer.js.flow │ │ ├── MailComposer.js.flow │ │ └── MailComposer.types.js.flow ├── @react-native-clipboard │ └── clipboard │ │ ├── index.js.flow │ │ └── dist │ │ ├── useClipboard.js.flow │ │ ├── index.js.flow │ │ └── Clipboard.js.flow ├── @react-navigation │ ├── core │ │ ├── index.js.flow │ │ └── lib │ │ │ └── typescript │ │ │ └── src │ │ │ ├── useIsFocused.js.flow │ │ │ ├── isArrayEqual.js.flow │ │ │ ├── useRegisterNavigator.js.flow │ │ │ ├── useFocusEffect.js.flow │ │ │ ├── useRoute.js.flow │ │ │ ├── useNavigation.js.flow │ │ │ ├── useNavigationState.js.flow │ │ │ ├── checkLegacyPathConfig.js.flow │ │ │ ├── CurrentRenderContext.js.flow │ │ │ ├── useRouteCache.js.flow │ │ │ ├── StaticContainer.js.flow │ │ │ ├── NavigationRouteContext.js.flow │ │ │ ├── checkSerializable.js.flow │ │ │ ├── getFocusedRouteNameFromRoute.js.flow │ │ │ ├── useSyncState.js.flow │ │ │ ├── UnhandledActionContext.js.flow │ │ │ ├── useEventEmitter.js.flow │ │ │ ├── useOnGetState.js.flow │ │ │ ├── NavigationHelpersContext.js.flow │ │ │ ├── NavigationContext.js.flow │ │ │ ├── useScheduleUpdate.js.flow │ │ │ ├── Screen.js.flow │ │ │ ├── getPathFromState.js.flow │ │ │ ├── useFocusEvents.js.flow │ │ │ ├── useFocusedListenersChildrenAdapter.js.flow │ │ │ ├── getStateFromPath.js.flow │ │ │ ├── useComponent.js.flow │ │ │ ├── useCurrentRender.js.flow │ │ │ ├── useOnRouteFocus.js.flow │ │ │ ├── BaseNavigationContainer.js.flow │ │ │ ├── useOptionsGetters.js.flow │ │ │ ├── createNavigatorFactory.js.flow │ │ │ ├── EnsureSingleNavigator.js.flow │ │ │ └── getActionFromState.js.flow │ ├── stack │ │ ├── index.js.flow │ │ └── lib │ │ │ └── typescript │ │ │ └── src │ │ │ ├── views │ │ │ ├── GestureHandler.ios.js.flow │ │ │ ├── MaskedView.ios.js.flow │ │ │ ├── GestureHandler.android.js.flow │ │ │ ├── MaskedView.android.js.flow │ │ │ ├── Header │ │ │ │ ├── Header.js.flow │ │ │ │ └── HeaderBackButton.js.flow │ │ │ ├── SafeAreaProviderCompat.js.flow │ │ │ ├── GestureHandlerNative.js.flow │ │ │ ├── GestureHandler.js.flow │ │ │ ├── TouchableItem.js.flow │ │ │ ├── MaskedView.js.flow │ │ │ ├── BorderlessButton.js.flow │ │ │ ├── TouchableItem.ios.js.flow │ │ │ └── MaskedViewNative.js.flow │ │ │ ├── utils │ │ │ ├── useHeaderHeight.js.flow │ │ │ ├── debounce.js.flow │ │ │ ├── getInvertedMultiplier.js.flow │ │ │ ├── getDistanceForDirection.js.flow │ │ │ ├── HeaderHeightContext.js.flow │ │ │ ├── HeaderShownContext.js.flow │ │ │ ├── useCardAnimation.js.flow │ │ │ ├── memoize.js.flow │ │ │ ├── CardAnimationContext.js.flow │ │ │ ├── PreviousSceneContext.js.flow │ │ │ ├── useGestureHandlerRef.js.flow │ │ │ ├── GestureHandlerRefContext.js.flow │ │ │ └── conditional.js.flow │ │ │ └── TransitionConfigs │ │ │ ├── TransitionSpecs.js.flow │ │ │ ├── TransitionPresets.js.flow │ │ │ └── HeaderStyleInterpolators.js.flow │ ├── native │ │ ├── index.js.flow │ │ └── lib │ │ │ └── typescript │ │ │ └── src │ │ │ ├── useLinkTo.js.flow │ │ │ ├── useDocumentTitle.native.js.flow │ │ │ ├── extractPathFromURL.js.flow │ │ │ ├── theming │ │ │ ├── DarkTheme.js.flow │ │ │ ├── DefaultTheme.js.flow │ │ │ ├── useTheme.js.flow │ │ │ ├── ThemeContext.js.flow │ │ │ └── ThemeProvider.js.flow │ │ │ ├── useLinkBuilder.js.flow │ │ │ ├── useThenable.js.flow │ │ │ ├── LinkingContext.js.flow │ │ │ ├── useBackButton.js.flow │ │ │ ├── ServerContext.js.flow │ │ │ ├── useDocumentTitle.js.flow │ │ │ ├── __mocks__ │ │ │ └── window.js.flow │ │ │ ├── ServerContainer.js.flow │ │ │ └── useLinkProps.js.flow │ ├── routers │ │ ├── index.js.flow │ │ └── lib │ │ │ └── typescript │ │ │ └── src │ │ │ └── index.js.flow │ ├── bottom-tabs │ │ ├── index.js.flow │ │ └── lib │ │ │ └── typescript │ │ │ └── src │ │ │ ├── utils │ │ │ ├── useIsKeyboardShown.js.flow │ │ │ ├── useBottomTabBarHeight.js.flow │ │ │ ├── useWindowDimensions.js.flow │ │ │ ├── BottomTabBarHeightContext.js.flow │ │ │ └── BottomTabBarHeightCallbackContext.js.flow │ │ │ ├── navigators │ │ │ └── createBottomTabNavigator.js.flow │ │ │ ├── views │ │ │ ├── ResourceSavingScene.js.flow │ │ │ ├── SafeAreaProviderCompat.js.flow │ │ │ └── Badge.js.flow │ │ │ └── index.js.flow │ └── material-top-tabs │ │ ├── index.js.flow │ │ └── lib │ │ └── typescript │ │ └── src │ │ ├── views │ │ ├── MaterialTopTabBar.js.flow │ │ └── MaterialTopTabView.js.flow │ │ └── index.js.flow ├── expo-screen-orientation │ ├── index.js.flow │ ├── plugin │ │ └── build │ │ │ └── withScreenOrientation.js.flow │ └── build │ │ └── ExpoScreenOrientation.js.flow ├── react-native-image-picker │ ├── index.js.flow │ └── lib │ │ └── typescript │ │ ├── platforms │ │ ├── NativeImagePicker.js.flow │ │ ├── web.js.flow │ │ └── native.js.flow │ │ └── index.js.flow ├── react-native-tab-view │ ├── index.js.flow │ └── lib │ │ └── typescript │ │ └── src │ │ ├── memoize.js.flow │ │ ├── SceneMap.js.flow │ │ └── index.js.flow ├── @react-native-camera-roll │ └── camera-roll │ │ ├── lib │ │ └── typescript │ │ │ ├── __mocks__ │ │ │ └── nativeInterface.js.flow │ │ │ ├── __tests__ │ │ │ ├── CameraRollTest.js.flow │ │ │ ├── useCameraRoll.js.flow │ │ │ └── CameraRollIOSPermissionTest.js.flow │ │ │ ├── nativeInterface.js.flow │ │ │ ├── cameraRollPermissionNativeInterface.js.flow │ │ │ ├── index.js.flow │ │ │ └── useCameraRoll.js.flow │ │ └── index.js.flow ├── react-native-document-picker │ └── index.js.flow ├── react-native-safe-area-context │ ├── index.js.flow │ └── lib │ │ └── typescript │ │ └── src │ │ ├── NativeSafeAreaProvider.js.flow │ │ ├── index.js.flow │ │ ├── InitialWindow.js.flow │ │ ├── InitialWindow.native.js.flow │ │ ├── CompatNativeSafeAreaProvider.js.flow │ │ ├── specs │ │ ├── NativeSafeAreaView.js.flow │ │ └── NativeSafeAreaContext.js.flow │ │ └── SafeAreaView.js.flow ├── react-native-open-notification │ └── index.js.flow ├── react-native-reanimated │ └── index.js.flow └── react-native-gesture-handler.js.flow ├── android ├── app │ └── src │ │ ├── debug │ │ ├── res │ │ │ ├── values │ │ │ │ └── strings.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.webp │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.webp │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.webp │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.webp │ │ │ └── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.webp │ │ └── AndroidManifest.xml │ │ └── main │ │ ├── res │ │ ├── raw │ │ │ ├── chime2.m4a │ │ │ ├── chime3.m4a │ │ │ ├── chime4.m4a │ │ │ └── zulip.mp3 │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.webp │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.webp │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.webp │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.webp │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.webp │ │ ├── drawable-hdpi │ │ │ └── zulip_notification.webp │ │ ├── drawable-mdpi │ │ │ └── zulip_notification.webp │ │ ├── drawable-xhdpi │ │ │ └── zulip_notification.webp │ │ ├── drawable-xxhdpi │ │ │ └── zulip_notification.webp │ │ ├── drawable-xxxhdpi │ │ │ └── zulip_notification.webp │ │ ├── anim │ │ │ ├── slide_in_left.xml │ │ │ ├── slide_in_right.xml │ │ │ ├── slide_out_left.xml │ │ │ └── slide_out_right.xml │ │ └── values │ │ │ ├── color.xml │ │ │ ├── styles.xml │ │ │ ├── strings.xml │ │ │ └── firebase.xml │ │ └── java │ │ └── com │ │ └── zulipmobile │ │ ├── sharing │ │ ├── SharingModule.kt │ │ └── SharingPackage.kt │ │ ├── notifications │ │ ├── NotificationsPackage.kt │ │ └── FcmListenerService.kt │ │ ├── SentryUtils.kt │ │ └── ShareToZulipActivity.kt ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .idea │ ├── codeStyles │ │ └── codeStyleConfig.xml │ └── vcs.xml └── settings.gradle ├── .buckconfig ├── .npmrc ├── jsconfig.json ├── src ├── third │ └── redux-persist │ │ ├── constants.js │ │ ├── index.js │ │ └── utils │ │ └── isStatePlainEnough.js ├── webview │ ├── js │ │ ├── sendMessage.js │ │ └── matchesPolyfill.js │ ├── html │ │ ├── __tests__ │ │ │ ├── render-test.js │ │ │ └── template-test.js │ │ ├── time.js │ │ ├── messageTypingAsHtml.js │ │ └── messageListElementHtml.js │ ├── css │ │ ├── cssNight.js │ │ └── cssEmojis.js │ └── static │ │ └── images │ │ └── follow.svg ├── api │ ├── apiTypes.js │ ├── mark_as_read │ │ ├── markAllAsRead.js │ │ ├── markStreamAsRead.js │ │ └── markTopicAsRead.js │ ├── deleteEventQueue.js │ ├── devFetchApiKey.js │ ├── messages │ │ ├── deleteTopic.js │ │ ├── toggleMessageStarred.js │ │ ├── getMessageHistory.js │ │ ├── deleteMessage.js │ │ ├── sendMessage.js │ │ └── updateMessageFlags.js │ ├── typing.js │ ├── notifications │ │ ├── sendTestNotification.js │ │ ├── forgetPushToken.js │ │ └── savePushToken.js │ ├── fetchApiKey.js │ ├── streams │ │ ├── getStreamId.js │ │ └── getStreams.js │ ├── devListUsers.js │ ├── transport.js │ ├── checkCompatibility.js │ ├── getTopics.js │ ├── emoji_reactions │ │ ├── emojiReactionAdd.js │ │ └── emojiReactionRemove.js │ ├── subscriptions │ │ ├── getSubscriptions.js │ │ ├── updateUserTopic.js │ │ ├── getSubscriptionToStream.js │ │ ├── subscriptionRemove.js │ │ ├── subscriptionAdd.js │ │ └── setTopicMute.js │ ├── submessages │ │ └── sendSubmessage.js │ ├── realm │ │ └── createRealmFilter.js │ ├── users │ │ ├── createUser.js │ │ ├── getUsers.js │ │ └── getUserProfile.js │ ├── reportPresence.js │ ├── uploadFile.js │ ├── pollForEvents.js │ └── settings │ │ └── toggleMobilePushSettings.js ├── __flow-tests__ │ └── types-test.js ├── drafts │ ├── draftsSelectors.js │ └── draftsActions.js ├── settings │ ├── settingsSelectors.js │ └── settingsActions.js ├── isAppOwnDomain.js ├── lightbox │ └── share.js ├── common │ ├── __tests__ │ │ ├── getStatusBarStyle-test.js │ │ └── getStatusBarColor-test.js │ ├── SectionSeparator.js │ ├── Logo.js │ ├── LineSeparator.js │ ├── OwnAvatar.js │ ├── ViewPlaceholder.js │ ├── SectionSeparatorBetween.js │ ├── SearchEmptyState.js │ └── SectionHeader.js ├── nativeModules │ └── ShareFileAndroid.js ├── __tests__ │ ├── jsBackport-test.js │ ├── lib │ │ └── intl.js │ └── isAppOwnDomain-test.js ├── nav │ ├── globalTypes.js │ └── IconUnreadMentions.js ├── styles │ ├── navStyles.js │ ├── composeBoxStyles.js │ ├── miscStyles.js │ └── constants.js ├── i18n │ └── i18n.js ├── title │ ├── TitlePlain.js │ └── ActivityText.js ├── streams │ └── getIsNotificationEnabled.js ├── chat │ ├── fetchingSelectors.js │ └── InvalidNarrow.js ├── message │ └── AnnouncementOnly.js ├── actions.js ├── emoji │ └── zulipExtraEmojiMap.js ├── utils │ ├── color.js │ ├── unread.js │ ├── networkActivity.js │ ├── __tests__ │ │ └── DefaultMap-test.js │ └── keyMirror.js ├── selectors.js ├── session │ └── sessionActions.js ├── boot │ ├── StoreHydratedGate.js │ └── __tests__ │ │ └── reducers-test.js ├── account │ └── accountMisc.js ├── sharing │ └── types.js ├── alertWords │ └── alertWordsReducer.js ├── caughtup │ └── caughtUpSelectors.js ├── mute │ └── muteModelTypes.js ├── config.js ├── autocomplete │ └── getAutocompletedText.js ├── user-picker │ └── AvatarList.js └── react-native-action-sheet.js ├── flow-typed ├── globals.js └── npm │ ├── flow-bin_v0.x.x.js │ └── deep-freeze_v0.0.1.js ├── jest ├── restorePromise.js ├── savePromise.js ├── presetIos.js ├── presetAndroid.js └── globalFetch.js ├── .tx └── config ├── tools ├── gradle ├── verify-webview-js ├── zulip-icon-debug.svg ├── deps ├── flow-todo.eslintrc.yaml └── z-white.svg ├── index.js ├── .prettierignore ├── docs ├── background │ └── recommended-reading.md └── howto │ └── forked-rn.md ├── .vscode ├── settings.json ├── launch.json └── extensions.json ├── wallaby.js ├── .eslintignore ├── .prettierrc.js └── react-native.config.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: zulip 2 | patreon: zulip 3 | open_collective: zulip 4 | -------------------------------------------------------------------------------- /ios/zulip.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/zulip.mp3 -------------------------------------------------------------------------------- /ios/zulip-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/zulip-logo.png -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/logo.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | The Zulip mobile app, chat for distributed teams -------------------------------------------------------------------------------- /types/expo-application/build/Application.types.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | -------------------------------------------------------------------------------- /static/img/app-store-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/app-store-badge.png -------------------------------------------------------------------------------- /static/img/apple-logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/apple-logo-black.png -------------------------------------------------------------------------------- /static/img/apple-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/apple-logo-white.png -------------------------------------------------------------------------------- /static/img/google-play-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/google-play-badge.png -------------------------------------------------------------------------------- /static/img/google_auth_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/google_auth_logo.png -------------------------------------------------------------------------------- /static/img/message-loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/message-loading.png -------------------------------------------------------------------------------- /static/img/spinning-progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/spinning-progress.png -------------------------------------------------------------------------------- /types/expo-modules-core/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './build/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/expo-web-browser/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './build/WebBrowser.js.flow'; 5 | -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /static/assets/fonts/zulip-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/assets/fonts/zulip-icons.ttf -------------------------------------------------------------------------------- /types/expo-application/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './build/Application.js.flow'; 5 | -------------------------------------------------------------------------------- /types/expo-mail-composer/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './build/MailComposer.js.flow'; 5 | -------------------------------------------------------------------------------- /android/app/src/debug/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Zulip (debug) 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/raw/chime2.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/raw/chime2.m4a -------------------------------------------------------------------------------- /android/app/src/main/res/raw/chime3.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/raw/chime3.m4a -------------------------------------------------------------------------------- /android/app/src/main/res/raw/chime4.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/raw/chime4.m4a -------------------------------------------------------------------------------- /android/app/src/main/res/raw/zulip.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/raw/zulip.mp3 -------------------------------------------------------------------------------- /static/img/spinning-progress-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/spinning-progress-black.png -------------------------------------------------------------------------------- /static/img/spinning-progress-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/static/img/spinning-progress-white.png -------------------------------------------------------------------------------- /types/expo-modules-core/build/sweet/setUpErrorManager.fx.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export {}; 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /types/@react-native-clipboard/clipboard/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './dist/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/core/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/expo-screen-orientation/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './build/ScreenOrientation.js.flow'; 5 | -------------------------------------------------------------------------------- /types/react-native-image-picker/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/react-native-tab-view/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/__mocks__/nativeInterface.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | -------------------------------------------------------------------------------- /types/@react-navigation/native/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/routers/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/react-native-document-picker/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Windows users might need to set an absolute path for this. 2 | # See https://stackoverflow.com/a/46006249/378130 . 3 | script-shell = bash 4 | -------------------------------------------------------------------------------- /types/@react-navigation/material-top-tabs/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated 3 | */ 4 | export * from './lib/typescript/src/index.js.flow'; 5 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/__tests__/CameraRollTest.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export {}; 5 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/__tests__/useCameraRoll.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export {}; 5 | -------------------------------------------------------------------------------- /android/app/src/debug/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/debug/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/debug/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/debug/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/debug/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/debug/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/debug/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true 4 | }, 5 | "exclude": [ 6 | "node_modules" 7 | ] 8 | } -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/__tests__/CameraRollIOSPermissionTest.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export {}; 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/zulip_notification.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/drawable-hdpi/zulip_notification.webp -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/zulip_notification.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/drawable-mdpi/zulip_notification.webp -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/GestureHandler.ios.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export * from './GestureHandlerNative'; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/MaskedView.ios.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export { default } from './MaskedViewNative'; 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/zulip_notification.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/drawable-xhdpi/zulip_notification.webp -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/zulip_notification.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/drawable-xxhdpi/zulip_notification.webp -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useIsFocused.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useIsFocused(): boolean; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/GestureHandler.android.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export * from './GestureHandlerNative'; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/MaskedView.android.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export { default } from './MaskedViewNative'; 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/zulip_notification.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/android/app/src/main/res/drawable-xxxhdpi/zulip_notification.webp -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-20x20@2x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-20x20@3x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-29x29@2x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-29x29@3x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-40x40@2x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-40x40@3x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-60x60@2x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-60x60@3x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-76x76@2x.png -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/nativeInterface.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare var _default: any; 5 | export default _default; 6 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useLinkTo.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useLinkTo(): (path: string) => void; 5 | -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulip/zulip-mobile/HEAD/ios/ZulipMobile/Assets.xcassets/AppIcon.appiconset/Icon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /src/third/redux-persist/constants.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | export const KEY_PREFIX: string = 'reduxPersist:'; 4 | export const REHYDRATE: 'persist/REHYDRATE' = 'persist/REHYDRATE'; 5 | -------------------------------------------------------------------------------- /types/@react-native-clipboard/clipboard/dist/useClipboard.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export var useClipboard: () => [string, (content: string) => void]; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/isArrayEqual.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function isArrayEqual(a: any[], b: any[]): boolean; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useRegisterNavigator.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useRegisterNavigator(): string; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useDocumentTitle.native.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useDocumentTitle(): void; 5 | -------------------------------------------------------------------------------- /android/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /flow-typed/globals.js: -------------------------------------------------------------------------------- 1 | // Definitions we want Flow to assume. 2 | // 3 | // For docs on the format, see: 4 | // https://flow.org/en/docs/libdefs/creation/ 5 | 6 | declare var __TEST__: true | void; 7 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/useHeaderHeight.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useFloatingHeaderHeight(): number; 5 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/SyntheticPlatformEmitter.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export { default } from 'react-native/Libraries/EventEmitter/RCTDeviceEventEmitter'; 5 | -------------------------------------------------------------------------------- /ios/ZulipMobile/UtilManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // UtilManager.h 3 | // ZulipMobile 4 | // 5 | 6 | #import 7 | 8 | @interface UtilManager : NSObject 9 | @end 10 | -------------------------------------------------------------------------------- /jest/restorePromise.js: -------------------------------------------------------------------------------- 1 | // For facebook/jest#10221. After savePromise.js and Jest's setup 2 | // files have run, restore the natural value of `global.Promise`. 3 | global.Promise = global.originalPromise; 4 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/utils/useIsKeyboardShown.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useIsKeyboardShown(): boolean; 5 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/cameraRollPermissionNativeInterface.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare var _default: any; 5 | export default _default; 6 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/navigators/createBottomTabNavigator.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare var _default: any; 5 | export default _default; 6 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/utils/useBottomTabBarHeight.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useFloatingBottomTabBarHeight(): number; 5 | -------------------------------------------------------------------------------- /types/react-native-open-notification/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | 5 | class NotificationSetting { 6 | static open: () => void; 7 | } 8 | export default NotificationSetting; 9 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/debounce.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function debounce void>(func: T, duration: number): T; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/extractPathFromURL.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function extractPathFromURL(prefixes: string[], url: string): string | void; 5 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/theming/DarkTheme.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type Theme } from '../types'; 5 | declare var DarkTheme: Theme; 6 | export default DarkTheme; 7 | -------------------------------------------------------------------------------- /types/@react-native-clipboard/clipboard/dist/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { Clipboard } from './Clipboard'; 5 | export { useClipboard } from './useClipboard'; 6 | export default Clipboard; 7 | -------------------------------------------------------------------------------- /jest/savePromise.js: -------------------------------------------------------------------------------- 1 | // For facebook/jest#10221. Before Jest's setup files have run, take 2 | // note of what the natural value of `global.Promise` is, so we can 3 | // restore it in restorePromise.js. 4 | global.originalPromise = Promise; 5 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export * from './useCameraRoll'; 5 | export * from './CameraRoll'; 6 | export * from './CameraRollIOSPermission'; 7 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/theming/DefaultTheme.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type Theme } from '../types'; 5 | declare var DefaultTheme: Theme; 6 | export default DefaultTheme; 7 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/NativeSafeAreaProvider.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import NativeSafeAreaProvider from './specs/NativeSafeAreaProvider'; 5 | export { NativeSafeAreaProvider }; 6 | -------------------------------------------------------------------------------- /flow-typed/npm/flow-bin_v0.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 4e6a5da3290fe9ea49e6bcdced64f358 2 | // flow-typed version: c6154227d1/flow-bin_v0.x.x/flow_>=v0.25.x <=v0.103.x 3 | 4 | declare module "flow-bin" { 5 | declare module.exports: string; 6 | } 7 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useLinkBuilder.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useLinkBuilder(): ( 5 | name: string, 6 | params?: { ... } | void, 7 | ) => string | void; 8 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/NativeViewManagerAdapter.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import * as React from 'react'; 5 | declare export function requireNativeViewManager

(viewName: string): React.ComponentType

; 6 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/errors/CodedError.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export class CodedError extends Error { 5 | code: string; 6 | info?: any; 7 | constructor(code: string, message: string): any; 8 | } 9 | -------------------------------------------------------------------------------- /types/react-native-reanimated/index.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | // Simple manual stubs, while we focus on other libraries. 3 | 4 | export class Node {} 5 | export class Value {} 6 | export class View {} 7 | 8 | export default { Node, Value, View }; 9 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [o:zulip:p:zulip:r:mobile] 5 | type = KEYVALUEJSON 6 | file_filter = static/translations/messages_.json 7 | source_lang = en 8 | source_file = static/translations/messages_en.json 9 | -------------------------------------------------------------------------------- /src/webview/js/sendMessage.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { WebViewOutboundEvent } from '../handleOutboundEvents'; 3 | 4 | export default (msg: WebViewOutboundEvent) => { 5 | window.ReactNativeWebView.postMessage(JSON.stringify(msg)); 6 | }; 7 | -------------------------------------------------------------------------------- /tools/gradle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | this_dir=${BASH_SOURCE[0]%/*} 5 | . "${this_dir}"/lib/ensure-coreutils.sh 6 | root_dir=$(readlink -f "${this_dir}"/..) 7 | 8 | exec "${root_dir}"/android/gradlew -p "${root_dir}"/android "$@" 9 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/utils/useWindowDimensions.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useWindowDimensions(): { 5 | height: number, 6 | width: number, 7 | ... 8 | }; 9 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/NativeViewManagerAdapter.native.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import * as React from 'react'; 5 | declare export function requireNativeViewManager

(viewName: string): React.ComponentType

; 6 | -------------------------------------------------------------------------------- /src/api/apiTypes.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | export type * from './transportTypes'; 4 | export type * from './modelTypes'; 5 | export type * from './eventTypes'; 6 | export type * from './initialDataTypes'; 7 | export type * from './permissionsTypes'; 8 | -------------------------------------------------------------------------------- /flow-typed/npm/deep-freeze_v0.0.1.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 2a3c1f56ec559e89dd447792f9debaf6 2 | // flow-typed version: c6154227d1/deep-freeze_v0.0.1/flow_>=v0.25.x <=v0.103.x 3 | 4 | declare module 'deep-freeze' { 5 | declare module.exports: (o: T) => T; 6 | } 7 | -------------------------------------------------------------------------------- /ios/ZulipMobile/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export * from './SafeAreaContext'; 5 | export * from './SafeAreaView'; 6 | export * from './InitialWindow'; 7 | export * from './SafeArea.types'; 8 | -------------------------------------------------------------------------------- /src/api/mark_as_read/markAllAsRead.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | export default async (auth: Auth): Promise => apiPost(auth, 'mark_all_as_read'); 6 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useFocusEffect.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | type EffectCallback = () => void | void | (() => void); 5 | declare export default function useFocusEffect(effect: EffectCallback): void; 6 | export {}; 7 | -------------------------------------------------------------------------------- /types/expo-screen-orientation/plugin/build/withScreenOrientation.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | 5 | // This module seems pretty useless, so we've erased everything in it. If 6 | // that seems wrong, we can process it (or part of it) as usual. 7 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useThenable.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { PromiseLike } from 'tsflower/subst/lib'; 5 | declare export default function useThenable(create: () => PromiseLike): [boolean, T | void]; 6 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/NativeModulesProxy.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ProxyNativeModule } from './NativeModulesProxy.types'; 5 | declare var _default: { [moduleName: string]: ProxyNativeModule, ... }; 6 | export default _default; 7 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/theming/useTheme.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Theme as $tsflower_import_type$_$_2e__2e_$Theme } from '..'; 5 | declare export default function useTheme(): $tsflower_import_type$_$_2e__2e_$Theme; 6 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/getInvertedMultiplier.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type GestureDirection } from '../types'; 5 | declare export default function getInvertedMultiplier(gestureDirection: GestureDirection): 1 | -1; 6 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/errors/UnavailabilityError.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { CodedError } from './CodedError'; 5 | declare export class UnavailabilityError extends CodedError { 6 | constructor(moduleName: string, propertyName: string): any; 7 | } 8 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/NativeModulesProxy.native.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ProxyNativeModule } from './NativeModulesProxy.types'; 5 | declare var NativeModulesProxy: { [moduleName: string]: ProxyNativeModule, ... }; 6 | export default NativeModulesProxy; 7 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/NativeModulesProxy.types.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export type ProxyNativeModule = { 5 | [propertyName: string]: any, 6 | addListener: (eventName: string) => void, 7 | removeListeners: (count: number) => void, 8 | ... 9 | }; 10 | -------------------------------------------------------------------------------- /src/__flow-tests__/types-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Action } from '../types'; 3 | 4 | // Assert that Action does not allow arbitrary objects. 5 | { 6 | const foo = { nonexistent_key: 'bar' }; 7 | // $FlowExpectedError[incompatible-type] 8 | const bar: Action = foo; 9 | } 10 | -------------------------------------------------------------------------------- /src/drafts/draftsSelectors.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Narrow, PerAccountState } from '../types'; 3 | import { keyFromNarrow } from '../utils/narrow'; 4 | 5 | export const getDraftForNarrow = (state: PerAccountState, narrow: Narrow): string => 6 | state.drafts[keyFromNarrow(narrow)] || ''; 7 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useRoute.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ParamListBase } from '@react-navigation/routers'; 5 | import { type RouteProp } from './types'; 6 | declare export default function useRoute>(): T; 7 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/sweet/NativeErrorManager.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ProxyNativeModule as $tsflower_import_type$_$_2e__2e_$ProxyNativeModule } from '..'; 5 | declare var _default: $tsflower_import_type$_$_2e__2e_$ProxyNativeModule; 6 | export default _default; 7 | -------------------------------------------------------------------------------- /tools/verify-webview-js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | oldjs=$(<./src/webview/js/generatedEs3.js) 3 | 4 | tools/generate-webview-js 5 | 6 | newjs=$(<./src/webview/js/generatedEs3.js) 7 | 8 | if [ "$oldjs" != "$newjs" ]; then 9 | echo "generatedEs3.js is not updated with current js file." 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /ios/ZulipMobile.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useNavigation.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ParamListBase } from '@react-navigation/routers'; 5 | import { type NavigationProp } from './types'; 6 | declare export default function useNavigation>(): T; 7 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/InitialWindow.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type EdgeInsets, type Metrics } from './SafeArea.types'; 5 | declare export var initialWindowMetrics: Metrics | null; 6 | declare export var initialWindowSafeAreaInsets: EdgeInsets | null; 7 | -------------------------------------------------------------------------------- /ios/ZulipMobile.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/ZulipMobile/ZLPConstantsBridge.m: -------------------------------------------------------------------------------- 1 | #import "React/RCTBridgeModule.h" 2 | 3 | // Register the ZLPConstants implementation with React Native, needed 4 | // because ZLPConstants is in Swift: 5 | // https://reactnative.dev/docs/0.68/native-modules-ios#exporting-swift 6 | @interface RCT_EXTERN_MODULE(ZLPConstants, NSObject) 7 | @end 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /src/drafts/draftsActions.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Narrow, PerAccountAction } from '../types'; 3 | import { DRAFT_UPDATE } from '../actionConstants'; 4 | 5 | export const draftUpdate = (narrow: Narrow, content: string): PerAccountAction => ({ 6 | type: DRAFT_UPDATE, 7 | narrow, 8 | content, 9 | }); 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | #d7ccc8 5 | 6 | #6492fe 7 | 8 | -------------------------------------------------------------------------------- /src/api/mark_as_read/markStreamAsRead.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | export default async (auth: Auth, streamId: number): Promise => 6 | apiPost(auth, 'mark_stream_as_read', { 7 | stream_id: streamId, 8 | }); 9 | -------------------------------------------------------------------------------- /src/third/redux-persist/index.js: -------------------------------------------------------------------------------- 1 | // @flow strict-local 2 | 3 | import autoRehydrate from './autoRehydrate'; 4 | import createPersistor from './createPersistor'; 5 | import persistStore from './persistStore'; 6 | 7 | export type { Persistor, Config } from './types'; 8 | 9 | export { autoRehydrate, createPersistor, persistStore }; 10 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/getDistanceForDirection.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type GestureDirection, type Layout } from '../types'; 5 | declare export default function getDistanceForDirection( 6 | layout: Layout, 7 | gestureDirection: GestureDirection, 8 | ): number; 9 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useNavigationState.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState } from '@react-navigation/routers'; 5 | type Selector = (state: NavigationState<>) => T; 6 | declare export default function useNavigationState(selector: Selector): T; 7 | export {}; 8 | -------------------------------------------------------------------------------- /types/expo-application/build/ExpoApplication.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ProxyNativeModule as $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule } from 'expo-modules-core'; 5 | declare var _default: $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule; 6 | export default _default; 7 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/HeaderHeightContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | declare var _default: $tsflower_subst$React$Context; 7 | export default _default; 8 | -------------------------------------------------------------------------------- /types/expo-mail-composer/build/ExpoMailComposer.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ProxyNativeModule as $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule } from 'expo-modules-core'; 5 | declare var _default: $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule; 6 | export default _default; 7 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/deprecate.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function deprecate( 5 | library: string, 6 | deprecatedAPI: string, 7 | options?: { 8 | replacement?: string, 9 | currentVersion?: string, 10 | versionToRemove?: string, 11 | ... 12 | }, 13 | ): void; 14 | -------------------------------------------------------------------------------- /types/expo-web-browser/build/ExpoWebBrowser.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ProxyNativeModule as $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule, } from "expo-modules-core"; 5 | declare var _default: $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule; 6 | export default _default; 7 | -------------------------------------------------------------------------------- /src/settings/settingsSelectors.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ColorSchemeName } from 'react-native/Libraries/Utilities/NativeAppearance'; 3 | import type { ThemeSetting, ThemeName } from '../reduxTypes'; 4 | 5 | export const getThemeToUse = (theme: ThemeSetting, osScheme: ?ColorSchemeName): ThemeName => 6 | theme === 'default' ? 'light' : 'dark'; 7 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/utils/BottomTabBarHeightContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | declare var _default: $tsflower_subst$React$Context; 7 | export default _default; 8 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/HeaderShownContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | declare var HeaderShownContext: $tsflower_subst$React$Context; 7 | export default HeaderShownContext; 8 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/useCardAnimation.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { StackCardInterpolationProps as $tsflower_import_type$_$_2e__2e_$StackCardInterpolationProps } from '..'; 5 | declare export default function useCardAnimation(): $tsflower_import_type$_$_2e__2e_$StackCardInterpolationProps; 6 | -------------------------------------------------------------------------------- /types/expo-screen-orientation/build/ExpoScreenOrientation.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ProxyNativeModule as $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule } from 'expo-modules-core'; 5 | declare var _default: $tsflower_import_type$_$expo_2d_modules_2d_core$ProxyNativeModule; 6 | export default _default; 7 | -------------------------------------------------------------------------------- /src/isAppOwnDomain.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import config from './config'; 3 | 4 | /** 5 | * Whether a URL is hosted by the same org that publishes the app. 6 | */ 7 | export default function isAppOwnDomain(url: URL): boolean { 8 | return config.appOwnDomains.some( 9 | domain => url.host === domain || url.host.endsWith(`.${domain}`), 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/lightbox/share.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { Share } from 'react-native'; 3 | 4 | import { BRAND_COLOR } from '../styles'; 5 | 6 | export default (url: string) => { 7 | const shareOptions = { 8 | message: url, 9 | title: 'Shared using Zulip!', 10 | }; 11 | Share.share(shareOptions, { tintColor: BRAND_COLOR }).catch(err => {}); 12 | }; 13 | -------------------------------------------------------------------------------- /src/api/deleteEventQueue.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from './transportTypes'; 3 | import { apiDelete } from './apiFetch'; 4 | 5 | /** See https://zulip.com/api/delete-queue */ 6 | export default (auth: Auth, queueId: string): Promise => 7 | apiDelete(auth, 'events', { 8 | queue_id: queueId, 9 | }); 10 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/requireNativeModule.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | /* tsflower-unimplemented: ModuleDeclaration */ 5 | /* declare global { 6 | var ExpoModules: undefined | { 7 | [key: string]: any; 8 | }; 9 | } */ 10 | 11 | declare export function requireNativeModule(moduleName: string): ModuleType; 12 | -------------------------------------------------------------------------------- /types/react-native-tab-view/lib/typescript/src/memoize.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function memoize< 5 | Result, 6 | Deps: /* tsflower-warning: unimplemented: 'readonly' as type operator */ 7 | any[] /* readonly any[] */, 8 | >( 9 | callback: (...deps: Deps) => Result, 10 | ): (...dependencies: Deps) => Result; 11 | -------------------------------------------------------------------------------- /ios/ZulipMobile/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import 6 | 7 | @interface AppDelegate : EXAppDelegateWrapper 8 | @property (nonatomic, strong) UIWindow *window; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /src/api/mark_as_read/markTopicAsRead.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | export default async (auth: Auth, streamId: number, topic: string): Promise => 6 | apiPost(auth, 'mark_topic_as_read', { 7 | stream_id: streamId, 8 | topic_name: topic, 9 | }); 10 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/utils/BottomTabBarHeightCallbackContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | declare var _default: $tsflower_subst$React$Context<(height: number) => void | void>; 7 | export default _default; 8 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/memoize.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function memoize< 5 | Result, 6 | Deps: /* tsflower-warning: unimplemented: 'readonly' as type operator */ 7 | any[] /* readonly any[] */, 8 | >( 9 | callback: (...deps: Deps) => Result, 10 | ): (...dependencies: Deps) => Result; 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | // React Navigation requires this react-native-gesture-handler import, 3 | // as the very first import of this entry-point file. See our #5373. 4 | import 'react-native-gesture-handler'; 5 | import { AppRegistry } from 'react-native'; 6 | import ZulipMobile from './src/ZulipMobile'; 7 | 8 | AppRegistry.registerComponent('ZulipMobile', () => ZulipMobile); 9 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/theming/ThemeContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type Theme } from '../types'; 7 | declare var ThemeContext: $tsflower_subst$React$Context; 8 | export default ThemeContext; 9 | -------------------------------------------------------------------------------- /src/common/__tests__/getStatusBarStyle-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { getStatusBarStyle } from '../ZulipStatusBar'; 3 | 4 | describe('getStatusBarStyle', () => { 5 | test('return bar style according to given color', () => { 6 | expect(getStatusBarStyle('#fff')).toEqual('dark-content'); 7 | expect(getStatusBarStyle('#000')).toEqual('light-content'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/nativeModules/ShareFileAndroid.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | /** 3 | * This exposes the native CustomTabsAndroid module as a JS module. This has a 4 | * function 'openURL' which takes the following parameters: 5 | * 6 | * 1. String url: A url to be opened in customTabs 7 | */ 8 | import { NativeModules } from 'react-native'; 9 | 10 | export default NativeModules.ShareFileAndroid; 11 | -------------------------------------------------------------------------------- /src/settings/settingsActions.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { AccountIndependentAction, GlobalSettingsState } from '../types'; 3 | import { SET_GLOBAL_SETTINGS } from '../actionConstants'; 4 | 5 | export const setGlobalSettings = ( 6 | update: $Shape<$Exact>, 7 | ): AccountIndependentAction => ({ 8 | type: SET_GLOBAL_SETTINGS, 9 | update, 10 | }); 11 | -------------------------------------------------------------------------------- /types/expo-mail-composer/build/MailComposer.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type MailComposerOptions, type MailComposerResult } from './MailComposer.types'; 5 | declare export function composeAsync(options: MailComposerOptions): Promise; 6 | declare export function isAvailableAsync(): Promise; 7 | export * from './MailComposer.types'; 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /static/assets/fonts/zulip-icons.map.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is @generated -- do not edit. 3 | * To make changes, see tools/build-icon-font. 4 | * 5 | * @flow strict 6 | */ 7 | export default { 8 | "bot": 61697, 9 | "ellipsis-v-solid": 61698, 10 | "gif": 61699, 11 | "globe": 61700, 12 | "language": 61701, 13 | "mute": 61702, 14 | "readreceipts": 61703, 15 | "follow": 61704 16 | }; 17 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/checkLegacyPathConfig.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type PathConfigMap } from './types'; 5 | 6 | type Options = { 7 | initialRouteName?: string, 8 | screens: PathConfigMap, 9 | ... 10 | }; 11 | 12 | declare export default function checkLegacyPathConfig(config?: Options): [boolean, Options | void]; 13 | export {}; 14 | -------------------------------------------------------------------------------- /types/@react-navigation/material-top-tabs/lib/typescript/src/views/MaterialTopTabBar.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 5 | import { type MaterialTopTabBarProps } from '../types'; 6 | declare export default function TabBarTop( 7 | props: MaterialTopTabBarProps, 8 | ): $tsflower_subst$React$JSX$Element; 9 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/CurrentRenderContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | declare var CurrentRenderContext: $tsflower_subst$React$Context<{ 7 | options?: { ... } | void, 8 | ... 9 | } | void>; 10 | export default CurrentRenderContext; 11 | -------------------------------------------------------------------------------- /ios/ZulipMobile/ZulipMobile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.applesignin 8 | 9 | Default 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useRouteCache.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState, type Route } from '@react-navigation/routers'; 5 | declare export var SUPPRESS_STATE_ACCESS_WARNING: { value: boolean, ... }; 6 | declare export default function useRouteCache>( 7 | routes: $ElementType, 8 | ): Route[]; 9 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/LinkingContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type LinkingOptions } from './types'; 7 | declare var LinkingContext: $tsflower_subst$React$Context<{ options: LinkingOptions | void, ... }>; 8 | export default LinkingContext; 9 | -------------------------------------------------------------------------------- /jest/presetIos.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The preset we're making tweaks to. 3 | */ 4 | const basePreset = require('../node_modules/jest-expo/ios/jest-preset.js'); 5 | 6 | // See comment in our Jest config about how this is used. 7 | module.exports = { 8 | ...basePreset, 9 | setupFiles: [ 10 | require.resolve('./savePromise.js'), 11 | ...basePreset.setupFiles, 12 | require.resolve('./restorePromise.js'), 13 | ], 14 | }; 15 | -------------------------------------------------------------------------------- /src/__tests__/jsBackport-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import { objectFromEntries } from '../jsBackport'; 4 | 5 | describe('objectFromEntries', () => { 6 | test('basic', () => { 7 | expect( 8 | // prettier-ignore 9 | objectFromEntries([['number', 1], ['null', null], ['obj', {}], ['undef', undefined]]), 10 | ).toStrictEqual({ number: 1, null: null, obj: {}, undef: undefined }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/api/devFetchApiKey.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from './transportTypes'; 3 | import { apiPost } from './apiFetch'; 4 | 5 | type ApiResponseDevFetchApiKey = {| 6 | ...$Exact, 7 | api_key: string, 8 | |}; 9 | 10 | export default (auth: Auth, email: string): Promise => 11 | apiPost(auth, 'dev_fetch_api_key', { username: email }); 12 | -------------------------------------------------------------------------------- /src/nav/globalTypes.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import type { AppNavigatorParamList } from './AppNavigator'; 4 | import type { SharingNavigatorParamList } from '../sharing/SharingScreen'; 5 | import type { MainTabsNavigatorParamList } from '../main/MainTabsScreen'; 6 | 7 | export type GlobalParamList = {| 8 | ...AppNavigatorParamList, 9 | ...SharingNavigatorParamList, 10 | ...MainTabsNavigatorParamList, 11 | |}; 12 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/CardAnimationContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type StackCardInterpolationProps } from '../types'; 7 | declare var _default: $tsflower_subst$React$Context; 8 | export default _default; 9 | -------------------------------------------------------------------------------- /jest/presetAndroid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The preset we're making tweaks to. 3 | */ 4 | const basePreset = require('../node_modules/jest-expo/android/jest-preset.js'); 5 | 6 | // See comment in our Jest config about how this is used. 7 | module.exports = { 8 | ...basePreset, 9 | setupFiles: [ 10 | require.resolve('./savePromise.js'), 11 | ...basePreset.setupFiles, 12 | require.resolve('./restorePromise.js'), 13 | ], 14 | }; 15 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/StaticContainer.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { MemoExoticComponent as $tsflower_subst$React$MemoExoticComponent } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | declare function StaticContainer(props: any): any; 7 | declare var _default: $tsflower_subst$React$MemoExoticComponent; 8 | export default _default; 9 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/Header/Header.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { NamedExoticComponent as $tsflower_subst$React$NamedExoticComponent } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type StackHeaderProps } from '../../types'; 7 | declare var _default: $tsflower_subst$React$NamedExoticComponent; 8 | export default _default; 9 | -------------------------------------------------------------------------------- /src/api/messages/deleteTopic.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | /** 6 | * Delete all messages in a stream for a given topic. 7 | */ 8 | export default async (auth: Auth, streamId: number, topicName: string): Promise => 9 | apiPost(auth, `streams/${streamId}/delete_topic`, { 10 | topic_name: topicName, 11 | }); 12 | -------------------------------------------------------------------------------- /tools/zulip-icon-debug.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DEBUG 6 | 7 | 8 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/NavigationRouteContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type Route } from '@react-navigation/routers'; 7 | declare var NavigationContext: $tsflower_subst$React$Context | void>; 8 | export default NavigationContext; 9 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/Header/HeaderBackButton.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 5 | import { type StackHeaderLeftButtonProps } from '../../types'; 6 | type Props = StackHeaderLeftButtonProps; 7 | declare export default function HeaderBackButton(Props): $tsflower_subst$React$JSX$Element; 8 | export {}; 9 | -------------------------------------------------------------------------------- /src/styles/navStyles.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { BRAND_COLOR } from './constants'; 3 | 4 | export const statics = { 5 | navWrapper: { 6 | flex: 1, 7 | flexDirection: 'row', 8 | alignItems: 'center', 9 | justifyContent: 'flex-start', 10 | }, 11 | navSubtitle: { 12 | fontSize: 13, 13 | }, 14 | navTitle: { 15 | color: BRAND_COLOR, 16 | textAlign: 'left', 17 | fontSize: 20, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/checkSerializable.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | type ReactText = string | number; // verbatim from @types/react 5 | 6 | declare export default function checkSerializable(o: { [key: string]: any, ... }): 7 | | { serializable: true, ... } 8 | | { 9 | serializable: false, 10 | location: ReactText[], 11 | reason: string, 12 | ... 13 | }; 14 | -------------------------------------------------------------------------------- /src/api/typing.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from './transportTypes'; 3 | import { apiPost } from './apiFetch'; 4 | 5 | type TypingOperation = 'start' | 'stop'; 6 | 7 | /** See https://zulip.com/api/set-typing-status */ 8 | export default (auth: Auth, recipients: string, operation: TypingOperation): Promise => 9 | apiPost(auth, 'typing', { 10 | to: recipients, 11 | op: operation, 12 | }); 13 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useBackButton.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { RefObject as $tsflower_subst$React$RefObject } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type NavigationContainerRef } from '@react-navigation/core'; 7 | declare export default function useBackButton( 8 | ref: $tsflower_subst$React$RefObject, 9 | ): void; 10 | -------------------------------------------------------------------------------- /src/api/notifications/sendTestNotification.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import type { ApiResponse, Auth } from '../transportTypes'; 4 | import { apiPost } from '../apiFetch'; 5 | 6 | /** See https://zulip.com/api/test-notify */ 7 | export default async ( 8 | auth: Auth, 9 | params: {| 10 | token: string, 11 | |}, 12 | ): Promise => 13 | apiPost(auth, 'mobile_push/test_notification', { 14 | token: params.token, 15 | }); 16 | -------------------------------------------------------------------------------- /src/api/fetchApiKey.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from './transportTypes'; 3 | import { apiPost } from './apiFetch'; 4 | 5 | type ApiResponseFetchApiKey = {| 6 | ...$Exact, 7 | email: string, 8 | api_key: string, 9 | |}; 10 | 11 | export default (auth: Auth, email: string, password: string): Promise => 12 | apiPost(auth, 'fetch_api_key', { username: email, password }); 13 | -------------------------------------------------------------------------------- /src/styles/composeBoxStyles.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | export default { 4 | disabledComposeBox: { 5 | flexDirection: 'row', 6 | alignItems: 'center', 7 | justifyContent: 'space-around', 8 | backgroundColor: 'gray', 9 | paddingHorizontal: 16, 10 | paddingVertical: 8, 11 | }, 12 | disabledComposeButton: { 13 | padding: 12, 14 | }, 15 | disabledComposeText: { 16 | flex: 1, 17 | color: 'white', 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/getFocusedRouteNameFromRoute.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Partial } from 'tsflower/subst/lib'; 5 | import { type Route, type PartialState, type NavigationState } from '@react-navigation/routers'; 6 | 7 | declare export default function getFocusedRouteNameFromRoute( 8 | route: Partial> & { state?: PartialState>, ... }, 9 | ): string | void; 10 | -------------------------------------------------------------------------------- /ios/ZulipMobile/Assets.xcassets/Brand.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xFE", 9 | "green" : "0x92", 10 | "red" : "0x64" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/api/streams/getStreamId.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import { apiGet } from '../apiFetch'; 4 | 5 | type ApiResponseStreamId = {| 6 | ...$Exact, 7 | stream_id: number, 8 | |}; 9 | 10 | /** See https://zulip.com/api/get-stream-id */ 11 | export default async (auth: Auth, stream: string): Promise => 12 | apiGet(auth, 'get_stream_id', { stream }); 13 | -------------------------------------------------------------------------------- /src/i18n/i18n.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { LocalizableText } from '../types'; 3 | 4 | /** 5 | * A LocalizableText that always resolves to the given string. 6 | * 7 | * Useful for wrapping user data, like the name of a user or a stream, 8 | * in a context where we sometimes also show a string that needs translation. 9 | */ 10 | export function noTranslation(value: string): LocalizableText { 11 | return { text: '{_}', values: { _: value } }; 12 | } 13 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/InitialWindow.native.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { EdgeInsets as $tsflower_import_type$_$_2e__2f_SafeArea_2e_types$EdgeInsets } from './SafeArea.types'; 5 | import { type Metrics } from './SafeArea.types'; 6 | declare export var initialWindowMetrics: Metrics | null; 7 | declare export var initialWindowSafeAreaInsets: $tsflower_import_type$_$_2e__2f_SafeArea_2e_types$EdgeInsets | void; 8 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/CompatNativeSafeAreaProvider.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type NativeSafeAreaProviderProps } from './SafeArea.types'; 7 | declare export function CompatNativeSafeAreaProvider( 8 | NativeSafeAreaProviderProps, 9 | ): $tsflower_subst$React$JSX$Element; 10 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # These are purely type definitions, no runtime code. Most of them 2 | # are third-party code, too, so naturally don't match our style. 3 | **/flow-typed/** 4 | types/react-intl.js.flow 5 | types/@react-native-community/netinfo/** 6 | types/@sentry/react-native.js.flow 7 | types/expo-web-browser/** 8 | types/react-native-webview.js.flow 9 | 10 | # Third-party code: react-native. We leave this code in the style we 11 | # received it in. 12 | src/third/react-native 13 | -------------------------------------------------------------------------------- /src/api/streams/getStreams.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import type { Stream } from '../apiTypes'; 4 | import { apiGet } from '../apiFetch'; 5 | 6 | type ApiResponseStreams = {| 7 | ...$Exact, 8 | streams: $ReadOnlyArray, 9 | |}; 10 | 11 | /** See https://zulip.com/api/get-streams */ 12 | export default async (auth: Auth): Promise => apiGet(auth, 'streams'); 13 | -------------------------------------------------------------------------------- /src/title/TitlePlain.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { Text } from 'react-native'; 5 | 6 | import styles from '../styles'; 7 | 8 | type Props = $ReadOnly<{| 9 | text: string, 10 | color: string, 11 | |}>; 12 | 13 | export default function TitlePlain(props: Props): Node { 14 | const { text, color } = props; 15 | return {text}; 16 | } 17 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useSyncState.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export default function useSyncState( 5 | initialState?: () => T | T /* tsflower-warning: unimplemented: 'readonly' as type operator */, 6 | ): [ 7 | T, 8 | () => T, 9 | (state: T) => void, 10 | (callback: () => void) => void, 11 | () => void, 12 | ] /* readonly [T, () => T, (state: T) => void, (callback: () => void) => void, () => void] */; 13 | -------------------------------------------------------------------------------- /types/react-native-image-picker/lib/typescript/platforms/NativeImagePicker.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type TurboModule } from 'react-native/Libraries/TurboModule/RCTExport'; 5 | 6 | export interface Spec extends TurboModule { 7 | launchCamera(options: Object, callback: () => void): void; 8 | launchImageLibrary(options: Object, callback: () => void): void; 9 | } 10 | 11 | declare var _default: Spec | null; 12 | export default _default; 13 | -------------------------------------------------------------------------------- /src/api/devListUsers.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from './transportTypes'; 3 | import type { DevUser } from './apiTypes'; 4 | import { apiGet } from './apiFetch'; 5 | 6 | type ApiResponseDevListUsers = {| 7 | ...$Exact, 8 | direct_admins: $ReadOnlyArray, 9 | direct_users: $ReadOnlyArray, 10 | |}; 11 | 12 | export default (auth: Auth): Promise => apiGet(auth, 'dev_list_users'); 13 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/UnhandledActionContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type NavigationAction } from '@react-navigation/routers'; 7 | declare var UnhandledActionContext: $tsflower_subst$React$Context< 8 | (action: NavigationAction) => void | void, 9 | >; 10 | export default UnhandledActionContext; 11 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useEventEmitter.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type EventEmitter, type EventConsumer } from './types'; 5 | export type NavigationEventEmitter = EventEmitter & { 6 | create: (target: string) => EventConsumer, 7 | ... 8 | }; 9 | declare export default function useEventEmitter( 10 | listen?: (e: any) => void, 11 | ): NavigationEventEmitter; 12 | -------------------------------------------------------------------------------- /types/react-native-image-picker/lib/typescript/platforms/web.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ImageLibraryOptions, type Callback, type ImagePickerResponse } from '../types'; 5 | declare export function camera( 6 | options?: ImageLibraryOptions, 7 | callback?: Callback, 8 | ): Promise; 9 | declare export function imageLibrary( 10 | options?: ImageLibraryOptions, 11 | callback?: Callback, 12 | ): Promise; 13 | -------------------------------------------------------------------------------- /src/webview/html/__tests__/render-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import messageTypingAsHtml from '../messageTypingAsHtml'; 3 | import * as eg from '../../../__tests__/lib/exampleData'; 4 | 5 | describe('typing', () => { 6 | it('escapes &< (e.g., in `avatar_url` and `email`', () => { 7 | const name = '&&2 < 0 )); then 21 | usage 22 | fi 23 | 24 | direct_dep_names 25 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useOnGetState.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState } from '@react-navigation/routers'; 5 | import { type GetStateListener } from './NavigationBuilderContext'; 6 | 7 | type Options = { 8 | getState: () => NavigationState<>, 9 | getStateListeners: { [key: string]: GetStateListener | void }, 10 | ... 11 | }; 12 | 13 | declare export default function useOnGetState(Options): void; 14 | export {}; 15 | -------------------------------------------------------------------------------- /src/api/messages/toggleMessageStarred.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth } from '../transportTypes'; 3 | import updateMessageFlags from './updateMessageFlags'; 4 | import type { ApiResponseUpdateMessageFlags } from './updateMessageFlags'; 5 | 6 | export default ( 7 | auth: Auth, 8 | messageIds: $ReadOnlyArray, 9 | starMessage: boolean, 10 | ): Promise => 11 | updateMessageFlags(auth, messageIds, starMessage ? 'add' : 'remove', 'starred'); 12 | -------------------------------------------------------------------------------- /types/react-native-tab-view/lib/typescript/src/SceneMap.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type SceneRendererProps } from './types'; 7 | declare export default function SceneMap(scenes: { 8 | [key: string]: React.ComponentType, 9 | ... 10 | }): (SceneRendererProps & { route: any, ... }) => $tsflower_subst$React$JSX$Element; 11 | -------------------------------------------------------------------------------- /src/api/transport.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth } from './transportTypes'; 3 | import { base64Utf8Encode } from '../utils/encoding'; 4 | 5 | export const getAuthHeaders = (auth: Auth): {| Authorization?: string |} => 6 | // The `Object.freeze`` in the `:` case avoids a Flow issue: 7 | // https://github.com/facebook/flow/issues/2386#issuecomment-695064325 8 | auth.apiKey 9 | ? { Authorization: `Basic ${base64Utf8Encode(`${auth.email}:${auth.apiKey}`)}` } 10 | : Object.freeze({}); 11 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/NavigationHelpersContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type NavigationHelpers } from './types'; 7 | declare var NavigationHelpersContext: $tsflower_subst$React$Context | void>; 11 | export default NavigationHelpersContext; 12 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/TransitionConfigs/TransitionSpecs.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type TransitionSpec } from '../types'; 5 | declare export var TransitionIOSSpec: TransitionSpec; 6 | declare export var FadeInFromBottomAndroidSpec: TransitionSpec; 7 | declare export var FadeOutToBottomAndroidSpec: TransitionSpec; 8 | declare export var RevealFromBottomAndroidSpec: TransitionSpec; 9 | declare export var ScaleFromCenterAndroidSpec: TransitionSpec; 10 | -------------------------------------------------------------------------------- /src/api/checkCompatibility.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import userAgent from '../utils/userAgent'; 3 | 4 | // check with server if current mobile app is compatible with latest backend 5 | // compatibility fails only if server responds with 400 (but not with 200 or 404) 6 | export default (): Promise => 7 | fetch('https://zulip.com/compatibility', { 8 | headers: { 9 | 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 10 | 'User-Agent': userAgent, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /src/api/getTopics.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from './transportTypes'; 3 | import type { Topic } from './apiTypes'; 4 | import { apiGet } from './apiFetch'; 5 | 6 | type ApiResponseTopics = {| 7 | ...$Exact, 8 | topics: $ReadOnlyArray, 9 | |}; 10 | 11 | /** See https://zulip.com/api/get-stream-topics */ 12 | export default async (auth: Auth, streamId: number): Promise => 13 | apiGet(auth, `users/me/${streamId}/topics`); 14 | -------------------------------------------------------------------------------- /src/common/SectionSeparator.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { View } from 'react-native'; 5 | 6 | import { createStyleSheet } from '../styles'; 7 | 8 | const styles = createStyleSheet({ 9 | separator: { 10 | height: 1, 11 | margin: 10, 12 | backgroundColor: 'hsla(0, 0%, 50%, 0.75)', 13 | }, 14 | }); 15 | 16 | export default function SectionSeparator(props: {||}): Node { 17 | return ; 18 | } 19 | -------------------------------------------------------------------------------- /src/streams/getIsNotificationEnabled.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Subscription } from '../types'; 3 | 4 | /** 5 | * Whether push notifications are enabled for this stream. 6 | * 7 | * The `userSettingsStreamNotification` parameter should correspond to 8 | * `state.settings.streamNotification`. 9 | */ 10 | export default ( 11 | subscription: Subscription | void, 12 | userSettingStreamNotification: boolean, 13 | ): boolean => subscription?.push_notifications ?? userSettingStreamNotification; 14 | -------------------------------------------------------------------------------- /src/third/redux-persist/utils/isStatePlainEnough.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | export default function isStatePlainEnough(a: mixed): boolean { 4 | // isPlainObject + duck type not immutable 5 | if (a === null) { 6 | return false; 7 | } 8 | if (typeof a !== 'object') { 9 | return false; 10 | } 11 | if (typeof a.asMutable === 'function') { 12 | return false; 13 | } 14 | const proto = Object.getPrototypeOf(a); 15 | return proto === null || Object.getPrototypeOf(proto) === null; 16 | } 17 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/SafeAreaProviderCompat.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ReactNode as $tsflower_subst$React$ReactNode, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | type Props = { children: $tsflower_subst$React$ReactNode, ... }; 11 | declare export default function SafeAreaProviderCompat(Props): $tsflower_subst$React$JSX$Element; 12 | export {}; 13 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/environment/browser.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare export var isDOMAvailable: $FlowFixMe /* false */ /* tsflower-error: const type inferred from FalseKeyword */; 5 | declare export var canUseEventListeners: $FlowFixMe /* false */ /* tsflower-error: const type inferred from FalseKeyword */; 6 | declare export var canUseViewport: $FlowFixMe /* false */ /* tsflower-error: const type inferred from FalseKeyword */; 7 | declare export var isAsyncDebugging: boolean; 8 | -------------------------------------------------------------------------------- /src/api/emoji_reactions/emojiReactionAdd.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | export default ( 6 | auth: Auth, 7 | messageId: number, 8 | reactionType: string, 9 | emojiCode: string, 10 | emojiName: string, 11 | ): Promise => 12 | apiPost(auth, `messages/${messageId}/reactions`, { 13 | reaction_type: reactionType, 14 | emoji_code: emojiCode, 15 | emoji_name: emojiName, 16 | }); 17 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/NavigationContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type NavigationProp } from './types'; 7 | declare var NavigationContext: $tsflower_subst$React$Context | void>; 14 | export default NavigationContext; 15 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useScheduleUpdate.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | 7 | declare export var ScheduleUpdateContext: $tsflower_subst$React$Context<{ 8 | scheduleUpdate: (callback: () => void) => void, 9 | flushUpdates: () => void, 10 | ... 11 | }>; 12 | 13 | declare export default function useScheduleUpdate(callback: () => void): void; 14 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/ServerContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | 7 | export type ServerContextType = { 8 | location?: { 9 | pathname: string, 10 | search: string, 11 | ... 12 | }, 13 | ... 14 | }; 15 | 16 | declare var ServerContext: $tsflower_subst$React$Context; 17 | export default ServerContext; 18 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/PreviousSceneContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { Context as $tsflower_subst$React$Context } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type Route } from '@react-navigation/native'; 7 | import { type Scene } from '../types'; 8 | declare var PreviousSceneContext: $tsflower_subst$React$Context, 10 | > | void>; 11 | export default PreviousSceneContext; 12 | -------------------------------------------------------------------------------- /jest/globalFetch.js: -------------------------------------------------------------------------------- 1 | global.fetch = jest.fn(); 2 | 3 | fetch.mockResponseSuccess = body => { 4 | fetch.mockImplementation(() => 5 | Promise.resolve({ json: () => Promise.resolve(JSON.parse(body)), status: 200, ok: true }), 6 | ); 7 | }; 8 | 9 | fetch.mockResponseFailure = error => { 10 | fetch.mockImplementation(() => Promise.reject(error)); 11 | }; 12 | 13 | fetch.mockErrorStatusCode = status => { 14 | fetch.mockImplementation({ status }); 15 | }; 16 | 17 | fetch.reset = () => { 18 | fetch.mockReset(); 19 | }; 20 | -------------------------------------------------------------------------------- /src/api/emoji_reactions/emojiReactionRemove.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponse } from '../transportTypes'; 3 | import { apiDelete } from '../apiFetch'; 4 | 5 | export default ( 6 | auth: Auth, 7 | messageId: number, 8 | reactionType: string, 9 | emojiCode: string, 10 | emojiName: string, 11 | ): Promise => 12 | apiDelete(auth, `messages/${messageId}/reactions`, { 13 | reaction_type: reactionType, 14 | emoji_code: emojiCode, 15 | emoji_name: emojiName, 16 | }); 17 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/PermissionsInterface.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | /* tsflower-unimplemented: EnumDeclaration */ 5 | /* export declare enum PermissionStatus { 6 | GRANTED = "granted", 7 | UNDETERMINED = "undetermined", 8 | DENIED = "denied" 9 | } */ 10 | 11 | export type PermissionExpiration = 'never' | number; 12 | 13 | export interface PermissionResponse { 14 | status: PermissionStatus; 15 | expires: PermissionExpiration; 16 | granted: boolean; 17 | canAskAgain: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /src/api/subscriptions/getSubscriptions.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import type { Subscription } from '../apiTypes'; 4 | import { apiGet } from '../apiFetch'; 5 | 6 | type ApiResponseSubscriptions = {| 7 | ...$Exact, 8 | subscriptions: $ReadOnlyArray, 9 | |}; 10 | 11 | /** See https://zulip.com/api/get-subscriptions */ 12 | export default (auth: Auth): Promise => 13 | apiGet(auth, 'users/me/subscriptions'); 14 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useDocumentTitle.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { RefObject as $tsflower_subst$React$RefObject } from 'tsflower/subst/react'; 5 | import * as React from 'react'; 6 | import { type NavigationContainerRef } from '@react-navigation/core'; 7 | import { type DocumentTitleOptions } from './types'; 8 | 9 | declare export default function useDocumentTitle( 10 | ref: $tsflower_subst$React$RefObject, 11 | ?DocumentTitleOptions, 12 | ): void; 13 | -------------------------------------------------------------------------------- /types/react-native-image-picker/lib/typescript/platforms/native.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { 5 | type CameraOptions, 6 | type ImageLibraryOptions, 7 | type Callback, 8 | type ImagePickerResponse, 9 | } from '../types'; 10 | 11 | declare export function camera( 12 | options: CameraOptions, 13 | callback?: Callback, 14 | ): Promise; 15 | declare export function imageLibrary( 16 | options: ImageLibraryOptions, 17 | callback?: Callback, 18 | ): Promise; 19 | -------------------------------------------------------------------------------- /src/chat/fetchingSelectors.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Fetching, PerAccountState, Narrow } from '../types'; 3 | import { getFetching } from '../directSelectors'; 4 | import { keyFromNarrow } from '../utils/narrow'; 5 | 6 | /** The value implicitly represented by a missing entry in FetchingState. */ 7 | export const DEFAULT_FETCHING = { older: false, newer: false }; 8 | 9 | export const getFetchingForNarrow = (state: PerAccountState, narrow: Narrow): Fetching => 10 | getFetching(state)[keyFromNarrow(narrow)] || DEFAULT_FETCHING; 11 | -------------------------------------------------------------------------------- /src/webview/css/cssNight.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | export default ` 4 | body { 5 | color: hsl(210, 11%, 85%); 6 | background: hsl(212, 28%, 18%); 7 | } 8 | .poll-vote { 9 | color: hsl(210, 11%, 85%); 10 | } 11 | .topic-header { 12 | background: hsl(212, 13%, 38%); 13 | } 14 | .msg-timestamp { 15 | background: hsl(212, 28%, 25%); 16 | } 17 | .highlight { 18 | background-color: hsla(51, 100%, 64%, 0.42); 19 | } 20 | .message_inline_image img.image-loading-placeholder { 21 | content: url("images/loader-white.svg"); 22 | } 23 | `; 24 | -------------------------------------------------------------------------------- /types/@react-native-camera-roll/camera-roll/lib/typescript/useCameraRoll.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { 5 | type GetPhotosParams, 6 | type PhotoIdentifiersPage, 7 | type SaveToCameraRollOptions, 8 | } from './CameraRoll'; 9 | 10 | type UseCameraRollResult = [ 11 | PhotoIdentifiersPage, 12 | (config?: GetPhotosParams) => Promise, 13 | (tag: string, options?: SaveToCameraRollOptions) => Promise, 14 | ]; 15 | 16 | declare export function useCameraRoll(): UseCameraRollResult; 17 | export {}; 18 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/useGestureHandlerRef.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { PanGestureHandler as $tsflower_import_type$_$react_2d_native_2d_gesture_2d_handler$PanGestureHandler } from 'react-native-gesture-handler'; 5 | import type { Ref as $tsflower_subst$React$Ref } from 'tsflower/subst/react'; 6 | import * as React from 'react'; 7 | declare export default function useGestureHandlerRef(): $tsflower_subst$React$Ref<$tsflower_import_type$_$react_2d_native_2d_gesture_2d_handler$PanGestureHandler>; 8 | -------------------------------------------------------------------------------- /src/api/submessages/sendSubmessage.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import type { ApiResponse, Auth } from '../transportTypes'; 4 | import { apiPost } from '../apiFetch'; 5 | 6 | /** See https://zulip.readthedocs.io/en/latest/subsystems/widgets.html#poll-todo-lists-and-games */ 7 | // `msg_type` only exists as widget at the moment, see #3205. 8 | export default async (auth: Auth, messageId: number, content: string): Promise => 9 | apiPost(auth, 'submessage', { 10 | message_id: messageId, 11 | msg_type: 'widget', 12 | content, 13 | }); 14 | -------------------------------------------------------------------------------- /src/common/Logo.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { Image } from 'react-native'; 5 | 6 | import logoImg from '../../static/img/logo.png'; 7 | import { createStyleSheet } from '../styles'; 8 | 9 | const styles = createStyleSheet({ 10 | logo: { 11 | width: 40, 12 | height: 40, 13 | margin: 20, 14 | alignSelf: 'center', 15 | }, 16 | }); 17 | 18 | export default function Logo(): Node { 19 | return ; 20 | } 21 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/Screen.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ParamListBase, type NavigationState } from '@react-navigation/routers'; 5 | import { type RouteConfig, type EventMapBase } from './types'; 6 | declare export default function Screen< 7 | ParamList: ParamListBase, 8 | RouteName: $Keys, 9 | State: NavigationState<>, 10 | ScreenOptions: { ... }, 11 | EventMap: EventMapBase, 12 | >( 13 | _: RouteConfig, 14 | ): null; 15 | -------------------------------------------------------------------------------- /src/api/realm/createRealmFilter.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | type ApiResponseRealmCreateFilters = {| 6 | ...$Exact, 7 | id: number, 8 | |}; 9 | 10 | /** https://zulip.com/api/add-linkifier */ 11 | export default async ( 12 | auth: Auth, 13 | pattern: string, 14 | urlFormatString: string, 15 | ): Promise => 16 | apiPost(auth, 'realm/filters', { pattern, url_format_string: urlFormatString }); 17 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/getPathFromState.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState, type PartialState } from '@react-navigation/routers'; 5 | import { type PathConfigMap } from './types'; 6 | 7 | type Options = { 8 | initialRouteName?: string, 9 | screens: PathConfigMap, 10 | ... 11 | }; 12 | 13 | type State = NavigationState<> | $Diff>, {| stale: mixed |}>; 14 | declare export default function getPathFromState(state: State, options?: Options): string; 15 | export {}; 16 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useFocusEvents.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState } from '@react-navigation/routers'; 5 | import { type NavigationEventEmitter } from './useEventEmitter'; 6 | import { type EventMapCore } from './types'; 7 | 8 | type Options> = { 9 | state: State, 10 | emitter: NavigationEventEmitter>, 11 | ... 12 | }; 13 | 14 | declare export default function useFocusEvents>(Options): void; 15 | export {}; 16 | -------------------------------------------------------------------------------- /ios/ZulipMobile/ZLPNotificationsBridge.m: -------------------------------------------------------------------------------- 1 | #import "React/RCTBridgeModule.h" 2 | #import "React/RCTEventEmitter.h" 3 | 4 | // Register our Swift modules with React Native: 5 | // https://reactnative.dev/docs/0.68/native-modules-ios#exporting-swift 6 | 7 | @interface RCT_EXTERN_MODULE(ZLPNotificationsEvents, RCTEventEmitter) 8 | @end 9 | 10 | @interface RCT_EXTERN_MODULE(ZLPNotificationsStatus, NSObject) 11 | 12 | RCT_EXTERN_METHOD(areNotificationsAuthorized: 13 | (RCTPromiseResolveBlock) resolve 14 | rejecter: (RCTPromiseRejectBlock) reject 15 | ) 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /types/@react-navigation/material-top-tabs/lib/typescript/src/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export { default as createMaterialTopTabNavigator } from './navigators/createMaterialTopTabNavigator'; 5 | export { default as MaterialTopTabView } from './views/MaterialTopTabView'; 6 | export { default as MaterialTopTabBar } from './views/MaterialTopTabBar'; 7 | export { 8 | MaterialTopTabNavigationOptions, 9 | MaterialTopTabNavigationProp, 10 | MaterialTopTabScreenProps, 11 | MaterialTopTabBarProps, 12 | MaterialTopTabBarOptions, 13 | } from './types'; 14 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useFocusedListenersChildrenAdapter.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ParamListBase } from '@react-navigation/routers'; 5 | import { type FocusedNavigationListener } from './NavigationBuilderContext'; 6 | import { type NavigationHelpers } from './types'; 7 | 8 | type Options = { 9 | navigation: NavigationHelpers, 10 | focusedListeners: FocusedNavigationListener[], 11 | ... 12 | }; 13 | 14 | declare export default function useFocusedListenersChildrenAdapter(Options): void; 15 | export {}; 16 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/theming/ThemeProvider.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ReactNode as $tsflower_subst$React$ReactNode, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | import { type Theme } from '../types'; 11 | 12 | type Props = { 13 | value: Theme, 14 | children: $tsflower_subst$React$ReactNode, 15 | ... 16 | }; 17 | 18 | declare export default function ThemeProvider(Props): $tsflower_subst$React$JSX$Element; 19 | export {}; 20 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/GestureHandlerNative.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 5 | import { type PanGestureHandlerProperties } from 'react-native-gesture-handler'; 6 | declare export function PanGestureHandler( 7 | props: PanGestureHandlerProperties, 8 | ): $tsflower_subst$React$JSX$Element; 9 | export { 10 | GestureHandlerRootView, 11 | State as GestureState, 12 | PanGestureHandlerGestureEvent, 13 | } from 'react-native-gesture-handler'; 14 | -------------------------------------------------------------------------------- /android/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/background/recommended-reading.md: -------------------------------------------------------------------------------- 1 | # Recommended reading 2 | 3 | ## React Native 4 | 5 | We recommend just official documentation of React Native - take a look at their 6 | [Getting started](https://reactnative.dev/docs/getting-started) section. 7 | 8 | 9 | ## Redux 10 | 11 | To know and understand what actually Redux is we encourage you to watch 12 | [this free video tutorial](https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist). 13 | 14 | 15 | ## Flexbox 16 | Play [the game](http://flexboxfroggy.com/) and learn how Flexbox works. 17 | -------------------------------------------------------------------------------- /src/api/users/createUser.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponseSuccess, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | /** 6 | * See https://zulip.com/api/create-user 7 | * Note: The requesting user must be an administrator. 8 | */ 9 | export default ( 10 | auth: Auth, 11 | email: string, 12 | password: string, 13 | fullName: string, 14 | shortName: string, 15 | ): Promise => 16 | apiPost(auth, 'users', { 17 | email, 18 | password, 19 | full_name: fullName, 20 | short_name: shortName, 21 | }); 22 | -------------------------------------------------------------------------------- /src/message/AnnouncementOnly.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { View } from 'react-native'; 5 | 6 | import ZulipTextIntl from '../common/ZulipTextIntl'; 7 | import styles from '../styles'; 8 | 9 | export default function AnnouncementOnly(props: {||}): Node { 10 | return ( 11 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /tools/flow-todo.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | parser: hermes-eslint 2 | plugins: 3 | - ft-flow 4 | rules: 5 | ft-flow/no-weak-types: error 6 | ft-flow/require-parameter-type: 7 | - error 8 | - excludeArrowFunctions: true 9 | ft-flow/require-return-type: 10 | - error 11 | - always 12 | - excludeArrowFunctions: true 13 | excludeMatching: 14 | - "^render$" 15 | 16 | # Things that might also be good and we might do after the areas above 17 | # are clean or nearly clean: 18 | # - change `excludeArrowFunctions` to "expressionsOnly", for both 19 | # parameter and return types 20 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/getStateFromPath.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState, type PartialState } from '@react-navigation/routers'; 5 | import { type PathConfigMap } from './types'; 6 | 7 | type Options = { 8 | initialRouteName?: string, 9 | screens: PathConfigMap, 10 | ... 11 | }; 12 | 13 | type ResultState = PartialState> & { state?: ResultState, ... }; 14 | declare export default function getStateFromPath( 15 | path: string, 16 | options?: Options, 17 | ): ResultState | void; 18 | export {}; 19 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useComponent.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ComponentProps as $tsflower_subst$React$ComponentProps, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | 11 | declare export default function useComponent, P: { ... }>( 12 | Component: T, 13 | props: P, 14 | ): ( 15 | rest: $Diff<$tsflower_subst$React$ComponentProps, {| [key: $Keys

]: mixed |}>, 16 | ) => $tsflower_subst$React$JSX$Element; 17 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | The Zulip mobile app. 2 | 3 | Zulip is a team chat product for enterprises, open-source projects, working groups, and communities. Zulip’s unique threading model allows everyone to stay involved, even those that spend most of their day away from chat. https://zulipchat.com/why-zulip 4 | 5 | Like everything Zulip, this app is 100% free and open-source software: https://github.com/zulip/zulip-mobile . Thank you to the hundreds of contributors who have made Zulip what it is! 6 | 7 | Please send questions, comments, and bug reports to support@zulipchat.com, or tweet @zulip. -------------------------------------------------------------------------------- /src/actions.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | export * from './account/accountActions'; 3 | export * from './events/eventActions'; 4 | export * from './nav/navActions'; 5 | export * from './drafts/draftsActions'; 6 | export * from './message/fetchActions'; 7 | export * from './message/messagesActions'; 8 | export * from './outbox/outboxActions'; 9 | export * from './session/sessionActions'; 10 | export * from './settings/settingsActions'; 11 | export * from './streams/streamsActions'; 12 | export * from './topics/topicActions'; 13 | export * from './typing/typingActions'; 14 | export * from './users/usersActions'; 15 | -------------------------------------------------------------------------------- /src/emoji/zulipExtraEmojiMap.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ImageEmoji } from '../types'; 3 | 4 | /** 5 | * Make this to ressemble with realm emoji 6 | * so that both emoji type can be handled in similiar way 7 | * thus id has no meaning here 8 | */ 9 | const zulipExtraEmojiMap: {| [id: string]: ImageEmoji |} = { 10 | zulip: { 11 | reaction_type: 'zulip_extra_emoji', 12 | deactivated: false, 13 | code: 'zulip', 14 | name: 'zulip', 15 | source_url: '/static/generated/emoji/images/emoji/unicode/zulip.png', 16 | }, 17 | }; 18 | 19 | export default zulipExtraEmojiMap; 20 | -------------------------------------------------------------------------------- /tools/z-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/notifications/forgetPushToken.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth } from '../transportTypes'; 3 | import { apiDelete } from '../apiFetch'; 4 | 5 | /** 6 | * Tell the server to forget this device token for push notifications. 7 | * 8 | * @param mobileOS - Choose the server-side API intended for iOS or Android clients. 9 | */ 10 | export default (auth: Auth, mobileOS: 'ios' | 'android', token: string): Promise => { 11 | const routeName = mobileOS === 'android' ? 'android_gcm_reg_id' : 'apns_device_token'; 12 | return apiDelete(auth, `users/me/${routeName}`, { token }); 13 | }; 14 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/views/ResourceSavingScene.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ReactNode as $tsflower_subst$React$ReactNode, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | 11 | type Props = { 12 | isVisible: boolean, 13 | children: $tsflower_subst$React$ReactNode, 14 | enabled: boolean, 15 | style?: any, 16 | ... 17 | }; 18 | 19 | declare export default function ResourceSavingScene(Props): $tsflower_subst$React$JSX$Element; 20 | export {}; 21 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useCurrentRender.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState, type ParamListBase } from '@react-navigation/routers'; 5 | import { type Descriptor, type NavigationHelpers } from './types'; 6 | 7 | type Options = { 8 | state: NavigationState<>, 9 | navigation: NavigationHelpers, 10 | descriptors: { 11 | [key: string]: Descriptor, { ... }>, 12 | ... 13 | }, 14 | ... 15 | }; 16 | 17 | declare export default function useCurrentRender(Options): void; 18 | export {}; 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Workspace Settings for the zulip-mobile repo. 2 | { 3 | // Disable TS-centric validation. We'll rely on ESLint for general validation. 4 | // See https://github.com/Microsoft/vscode/issues/15171 5 | "javascript.validate.enable": false, 6 | 7 | // Makes IntelliSense work with Flow. See 8 | // https://github.com/Microsoft/vscode-react-native/blob/master/doc/intellisense.md . 9 | "flow.useNPMPackagedFlow": true, 10 | 11 | "[javascript]": { 12 | // Format JS code with prettier-eslint. 13 | "editor.defaultFormatter": "esbenp.prettier-vscode", 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /src/api/messages/getMessageHistory.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import type { MessageSnapshot } from '../apiTypes'; 4 | import { apiGet } from '../apiFetch'; 5 | 6 | type ApiResponseMessageHistory = {| 7 | ...$Exact, 8 | message_history: $ReadOnlyArray, 9 | |}; 10 | 11 | /** See https://zulip.com/api/get-message-history */ 12 | export default async (auth: Auth, messageId: number): Promise => 13 | apiGet(auth, `messages/${messageId}/history`, { 14 | message_id: messageId, 15 | }); 16 | -------------------------------------------------------------------------------- /src/common/LineSeparator.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React, { useContext } from 'react'; 3 | import type { Node } from 'react'; 4 | import { View } from 'react-native'; 5 | 6 | import { ThemeContext, createStyleSheet } from '../styles'; 7 | 8 | const componentStyles = createStyleSheet({ 9 | lineSeparator: { 10 | height: 1, 11 | margin: 4, 12 | }, 13 | }); 14 | 15 | export default function LineSeparator(props: {||}): Node { 16 | const themeContext = useContext(ThemeContext); 17 | return ( 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/utils/color.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | // $FlowFixMe[untyped-import] 3 | import Color from 'color'; 4 | import type { ColorValue } from 'react-native/Libraries/StyleSheet/StyleSheet'; 5 | 6 | export const foregroundColorFromBackground = (color: ColorValue): 'black' | 'white' => 7 | Color(color).luminosity() > 0.4 ? 'black' : 'white'; 8 | 9 | export const colorHashFromString = (name: string): string => { 10 | let hash = 0; 11 | for (let i = 0; i < name.length; i++) { 12 | hash = hash * 31 + name.charCodeAt(i); 13 | hash %= 0x1000000; 14 | } 15 | 16 | return `#${hash.toString(16).padStart(6, '0')}`; 17 | }; 18 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useOnRouteFocus.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { 5 | type NavigationAction, 6 | type NavigationState, 7 | type Router, 8 | } from '@react-navigation/routers'; 9 | 10 | type Options = { 11 | router: Router, Action>, 12 | getState: () => NavigationState<>, 13 | setState: (state: NavigationState<>) => void, 14 | key?: string, 15 | ... 16 | }; 17 | 18 | declare export default function useOnRouteFocus( 19 | Options, 20 | ): (key: string) => void; 21 | export {}; 22 | -------------------------------------------------------------------------------- /src/__tests__/lib/intl.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import type { GetText } from '../../types'; 4 | 5 | // Our translation function, usually given the name _. 6 | // eslint-disable-next-line no-underscore-dangle 7 | export const mock_: GetText = m => { 8 | if (typeof m === 'object') { 9 | if (m.text === '{_}') { 10 | // $FlowIgnore[incompatible-indexer] 11 | /* $FlowIgnore[incompatible-cast] 12 | We expect an `m.values` that corresponds to `m.text`. */ 13 | const values = (m.values: {| +_: string |}); 14 | return values._; 15 | } 16 | return m.text; 17 | } 18 | return m; 19 | }; 20 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/zulipmobile/sharing/SharingModule.kt: -------------------------------------------------------------------------------- 1 | package com.zulipmobile.sharing 2 | 3 | import com.facebook.react.bridge.* 4 | 5 | internal class SharingModule(reactContext: ReactApplicationContext) : 6 | ReactContextBaseJavaModule(reactContext) { 7 | 8 | override fun getName(): String { 9 | return "Sharing" 10 | } 11 | 12 | @ReactMethod 13 | fun readInitialSharedContent(promise: Promise) { 14 | promise.resolve(initialSharedData) 15 | initialSharedData = null 16 | } 17 | 18 | companion object { 19 | var initialSharedData: WritableMap? = null 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /wallaby.js: -------------------------------------------------------------------------------- 1 | module.exports = (wallaby) => ({ 2 | files: ['src/**/*.js', '!src/**/__tests__/*.js'], 3 | tests: ['src/**/__tests__/*.js'], 4 | env: { 5 | type: 'node', 6 | runner: 'node', 7 | }, 8 | testFramework: 'jest', 9 | compilers: { 10 | 'src/**/*.js': wallaby.compilers.babel(), 11 | }, 12 | setup: () => 13 | wallaby.testFramework.configure({ 14 | // https://facebook.github.io/jest/docs/api.html#config-options 15 | // you may just pass `require('./package.json').jest`, if you use it for your Jest config 16 | // don't forget to include package.json in the files list in this case 17 | }), 18 | }); 19 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/api/subscriptions/updateUserTopic.js: -------------------------------------------------------------------------------- 1 | // @flow strict-local 2 | import type { UserTopicVisibilityPolicy } from '../modelTypes'; 3 | import type { ApiResponseSuccess, Auth } from '../transportTypes'; 4 | import { apiPost } from '../apiFetch'; 5 | 6 | /** https://chat.zulip.org/api/update-user-topic */ 7 | export default function updateUserTopic( 8 | auth: Auth, 9 | stream_id: number, 10 | topic: string, 11 | visibility_policy: UserTopicVisibilityPolicy, 12 | ): Promise { 13 | return apiPost(auth, '/user_topics', { 14 | stream_id, 15 | topic, 16 | visibility_policy: (visibility_policy: number), 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug Android", 9 | "program": "${workspaceRoot}/.vscode/launchReactNative.js", 10 | "type": "reactnative", 11 | "request": "launch", 12 | "platform": "android", 13 | "sourceMaps": true, 14 | "outDir": "${workspaceRoot}/.vscode/.react" 15 | }, 16 | ] 17 | } -------------------------------------------------------------------------------- /ios/upload.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | method 6 | app-store 7 | destination 8 | upload 9 | signingStyle 10 | manual 11 | provisioningProfiles 12 | 13 | org.zulip.Zulip 14 | 15 | iOS app distribution 2022 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/selectors.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | export * from './account/accountsSelectors'; 3 | export * from './pm-conversations/pmConversationsSelectors'; 4 | export * from './caughtup/caughtUpSelectors'; 5 | export * from './chat/narrowsSelectors'; 6 | export * from './chat/fetchingSelectors'; 7 | export * from './directSelectors'; 8 | export * from './emoji/emojiSelectors'; 9 | export * from './message/messageSelectors'; 10 | export * from './subscriptions/subscriptionSelectors'; 11 | export * from './topics/topicSelectors'; 12 | export * from './typing/typingSelectors'; 13 | export * from './unread/unreadSelectors'; 14 | export * from './users/userSelectors'; 15 | -------------------------------------------------------------------------------- /src/session/sessionActions.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { PerAccountAction, AccountIndependentAction, Orientation } from '../types'; 3 | import { APP_ONLINE, APP_ORIENTATION, DISMISS_SERVER_COMPAT_NOTICE } from '../actionConstants'; 4 | 5 | export const appOnline = (isOnline: boolean | null): AccountIndependentAction => ({ 6 | type: APP_ONLINE, 7 | isOnline, 8 | }); 9 | 10 | export const appOrientation = (orientation: Orientation): AccountIndependentAction => ({ 11 | type: APP_ORIENTATION, 12 | orientation, 13 | }); 14 | 15 | export const dismissCompatNotice = (): PerAccountAction => ({ 16 | type: DISMISS_SERVER_COMPAT_NOTICE, 17 | }); 18 | -------------------------------------------------------------------------------- /src/webview/html/time.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import template from './template'; 3 | import type { TimeMessageListElement } from '../../types'; 4 | import { humanDate } from '../../utils/date'; 5 | 6 | /** 7 | * The HTML string for a message-list element of the "time" type. 8 | * 9 | * This is a private helper of messageListElementHtml. 10 | */ 11 | export default (element: TimeMessageListElement): string => template`\ 12 |

13 |
14 | ${humanDate(new Date(element.timestamp * 1000))} 15 |
16 |
`; 17 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # How to upgrade Gradle: 2 | # $ tools/gradle wrapper --distribution-type=all --gradle-version=NEW_VERSION 3 | # $ tools/gradle wrapper --distribution-type=all --gradle-version=NEW_VERSION 4 | # (Yep, run the same command twice. The first updates this file so we use 5 | # the new Gradle; the second updates the wrapper's jar and scripts, so that 6 | # the wrapper is the one from the new Gradle too.) 7 | distributionBase=GRADLE_USER_HOME 8 | distributionPath=wrapper/dists 9 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip 10 | zipStoreBase=GRADLE_USER_HOME 11 | zipStorePath=wrapper/dists 12 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/GestureHandlerRefContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { PanGestureHandler as $tsflower_import_type$_$react_2d_native_2d_gesture_2d_handler$PanGestureHandler } from 'react-native-gesture-handler'; 5 | import type { 6 | Context as $tsflower_subst$React$Context, 7 | Ref as $tsflower_subst$React$Ref, 8 | } from 'tsflower/subst/react'; 9 | import * as React from 'react'; 10 | declare var _default: $tsflower_subst$React$Context< 11 | $tsflower_subst$React$Ref<$tsflower_import_type$_$react_2d_native_2d_gesture_2d_handler$PanGestureHandler>, 12 | >; 13 | export default _default; 14 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/__mocks__/window.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | declare var _default: { 5 | document: { title: string, ... }, 6 | location: URL, 7 | history: { 8 | +state: any, 9 | pushState(state: any, _: string, path: string): void, 10 | replaceState(state: any, _: string, path: string): void, 11 | go(n: number): void, 12 | back(): void, 13 | forward(): void, 14 | ... 15 | }, 16 | addEventListener: (type: 'popstate', listener: () => void) => void, 17 | removeEventListener: (type: 'popstate', listener: () => void) => void, 18 | ... 19 | }; 20 | 21 | export default _default; 22 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/zulipmobile/sharing/SharingPackage.kt: -------------------------------------------------------------------------------- 1 | package com.zulipmobile.sharing 2 | 3 | import com.facebook.react.ReactPackage 4 | import com.facebook.react.bridge.NativeModule 5 | import com.facebook.react.bridge.ReactApplicationContext 6 | import com.facebook.react.uimanager.ViewManager 7 | 8 | class SharingPackage : ReactPackage { 9 | override fun createViewManagers(reactContext: ReactApplicationContext): List> { 10 | return emptyList() 11 | } 12 | 13 | override fun createNativeModules(reactContext: ReactApplicationContext): List { 14 | return arrayListOf(SharingModule(reactContext)) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/BaseNavigationContainer.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ForwardRefExoticComponent as $tsflower_subst$React$ForwardRefExoticComponent, 6 | RefAttributes as $tsflower_subst$React$RefAttributes, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | import { type NavigationContainerRef, type NavigationContainerProps } from './types'; 11 | declare var BaseNavigationContainer: $tsflower_subst$React$ForwardRefExoticComponent< 12 | NavigationContainerProps & $tsflower_subst$React$RefAttributes, 13 | >; 14 | export default BaseNavigationContainer; 15 | -------------------------------------------------------------------------------- /types/expo-mail-composer/build/MailComposer.types.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export type MailComposerOptions = { 5 | recipients?: string[], 6 | ccRecipients?: string[], 7 | bccRecipients?: string[], 8 | subject?: string, 9 | body?: string, 10 | isHtml?: boolean, 11 | attachments?: string[], 12 | ... 13 | }; 14 | 15 | export type MailComposerResult = { status: MailComposerStatusT, ... }; 16 | 17 | declare export var MailComposerStatus: {| 18 | +UNDETERMINED: 'undetermined', 19 | +SENT: 'sent', 20 | +SAVED: 'saved', 21 | +CANCELLED: 'cancelled', 22 | |}; 23 | export type MailComposerStatusT = $Values; 24 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/TransitionConfigs/TransitionPresets.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type TransitionPreset } from '../types'; 5 | declare export var SlideFromRightIOS: TransitionPreset; 6 | declare export var ModalSlideFromBottomIOS: TransitionPreset; 7 | declare export var ModalPresentationIOS: TransitionPreset; 8 | declare export var FadeFromBottomAndroid: TransitionPreset; 9 | declare export var RevealFromBottomAndroid: TransitionPreset; 10 | declare export var ScaleFromCenterAndroid: TransitionPreset; 11 | declare export var DefaultTransition: TransitionPreset; 12 | declare export var ModalTransition: TransitionPreset; 13 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/utils/conditional.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | AnimatedInterpolation as $tsflower_subst$RN$Animated$AnimatedInterpolation, 6 | AnimatedAddition as $tsflower_subst$RN$Animated$AnimatedAddition, 7 | } from 'tsflower/subst/react-native'; 8 | 9 | import { Animated } from 'react-native'; 10 | 11 | declare export default function conditional( 12 | condition: $tsflower_subst$RN$Animated$AnimatedInterpolation, 13 | main: $tsflower_subst$RN$Animated$AnimatedInterpolation, 14 | fallback: $tsflower_subst$RN$Animated$AnimatedInterpolation, 15 | ): $tsflower_subst$RN$Animated$AnimatedAddition; 16 | -------------------------------------------------------------------------------- /src/common/OwnAvatar.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | 5 | import { useSelector } from '../react-redux'; 6 | import UserAvatar from './UserAvatar'; 7 | import { getOwnUser } from '../users/userSelectors'; 8 | 9 | type Props = $ReadOnly<{| 10 | size: number, 11 | |}>; 12 | 13 | /** 14 | * Renders an image of the current user's avatar 15 | * 16 | * @prop size - Sets width and height in logical pixels. 17 | */ 18 | export default function OwnAvatar(props: Props): Node { 19 | const { size } = props; 20 | const user = useSelector(getOwnUser); 21 | return ; 22 | } 23 | -------------------------------------------------------------------------------- /types/expo-modules-core/src/ts-declarations/NativeEventEmitter.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | /* tsflower-unimplemented: ModuleDeclaration */ 5 | /* declare module 'react-native/Libraries/EventEmitter/NativeEventEmitter' { 6 | import { EventEmitter } from 'react-native'; 7 | 8 | interface NativeEventEmitter extends EventEmitter { 9 | new (nativeModule: NativeModule): NativeEventEmitters; 10 | } 11 | 12 | const NativeEventEmitter: NativeEventEmitter; 13 | 14 | export default NativeEventEmitter; 15 | 16 | type NativeModule = { 17 | addListener: (eventType: string) => void; 18 | removeListeners: (count: number) => void; 19 | }; 20 | } */ 21 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/useOptionsGetters.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type ParamListBase, type NavigationState } from '@react-navigation/routers'; 5 | import { type NavigationProp } from './types'; 6 | 7 | type Options = { 8 | key?: string, 9 | navigation?: NavigationProp, { ... }>, 10 | options?: { ... } | void, 11 | ... 12 | }; 13 | 14 | declare export default function useOptionsGetters(Options): { 15 | addOptionsGetter: (key: string, getter: () => { ... } | void | null) => () => void, 16 | getCurrentOptions: () => { ... } | null | void, 17 | ... 18 | }; 19 | 20 | export {}; 21 | -------------------------------------------------------------------------------- /types/react-native-image-picker/lib/typescript/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ImagePickerResponse as $tsflower_import_type$_$_2e__2f_types$ImagePickerResponse } from './types'; 5 | import { type CameraOptions, type ImageLibraryOptions, type Callback } from './types'; 6 | export * from './types'; 7 | declare export function launchCamera( 8 | options: CameraOptions, 9 | callback?: Callback, 10 | ): Promise<$tsflower_import_type$_$_2e__2f_types$ImagePickerResponse>; 11 | declare export function launchImageLibrary( 12 | options: ImageLibraryOptions, 13 | callback?: Callback, 14 | ): Promise<$tsflower_import_type$_$_2e__2f_types$ImagePickerResponse>; 15 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "msjsdiag.vscode-react-native", 8 | "flowtype.flow-for-vscode", 9 | "dbaeumer.vscode-eslint", 10 | "esbenp.prettier-vscode" 11 | ], 12 | 13 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 14 | // Nothing in here but adding this in order to add extentions later as required. 15 | "unwantedRecommendations": [] 16 | } 17 | -------------------------------------------------------------------------------- /static/icons/follow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Zulip 3 | Messages 4 | No Browser Found 5 | 6 | %d conversation 7 | %d conversations 8 | 9 | Share To 10 | 11 | %1$s to you and %2$s other 12 | %1$s to you and %2$s others 13 | 14 | You 15 | 16 | -------------------------------------------------------------------------------- /src/boot/StoreHydratedGate.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | 5 | import { useGlobalSelector } from '../react-redux'; 6 | import { getIsHydrated } from '../selectors'; 7 | import FullScreenLoading from '../common/FullScreenLoading'; 8 | 9 | type Props = $ReadOnly<{| 10 | children: Node, 11 | |}>; 12 | 13 | /** 14 | * Where we prevent everything from rendering while waiting for rehydration. 15 | */ 16 | export default function StoreHydratedGate(props: Props): Node { 17 | const { children } = props; 18 | 19 | const isHydrated = useGlobalSelector(getIsHydrated); 20 | 21 | return isHydrated ? children : ; 22 | } 23 | -------------------------------------------------------------------------------- /types/react-native-gesture-handler.js.flow: -------------------------------------------------------------------------------- 1 | // These are hand-written stubs, while we focus on other libraries 2 | // that consume this one. 3 | // @flow 4 | 5 | import * as React from 'react'; 6 | 7 | export type PanGestureHandlerProps = $FlowFixMe; 8 | export type PanGestureHandlerProperties = $FlowFixMe; 9 | export type PanGestureHandlerGestureEvent = $FlowFixMe; 10 | export class PanGestureHandler extends React.Component {} 11 | 12 | export type TapGestureHandler = $FlowFixMe; 13 | export type TapGestureHandlerProperties = $FlowFixMe; 14 | export type State = $FlowFixMe; 15 | 16 | declare export var GestureHandlerRootView: $FlowFixMe; 17 | declare export var BaseButton: $FlowFixMe; 18 | -------------------------------------------------------------------------------- /src/webview/static/images/follow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/GestureHandler.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import * as React from 'react'; 5 | import { View } from 'react-native'; 6 | import { type PanGestureHandlerProperties } from 'react-native-gesture-handler'; 7 | declare export var PanGestureHandler: React.ComponentType; 8 | declare export var GestureHandlerRootView: typeof View; 9 | 10 | declare export var GestureState: { 11 | UNDETERMINED: number, 12 | FAILED: number, 13 | BEGAN: number, 14 | CANCELLED: number, 15 | ACTIVE: number, 16 | END: number, 17 | ... 18 | }; 19 | 20 | export { PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; 21 | -------------------------------------------------------------------------------- /src/account/accountMisc.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Account, Auth, Identity } from '../types'; 3 | 4 | const identitySlice = ({ realm, email }): Identity => ({ realm, email }); 5 | 6 | export const identityOfAuth: Auth => Identity = identitySlice; 7 | 8 | export const identityOfAccount: ($ReadOnly<{ ...Identity, ... }>) => Identity = identitySlice; 9 | 10 | /** A string corresponding uniquely to an identity, for use in `Map`s. */ 11 | export const keyOfIdentity = ({ realm, email }: Identity): string => 12 | `${realm.toString()}\0${email}`; 13 | 14 | export const authOfAccount = (account: Account): Auth => { 15 | const { realm, email, apiKey } = account; 16 | return { realm, email, apiKey }; 17 | }; 18 | -------------------------------------------------------------------------------- /src/api/messages/deleteMessage.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPatch } from '../apiFetch'; 4 | 5 | // TODO(#4701): Make an API method for DELETE /messages/{id}. Use it to 6 | // implement the permanent message deletion capability: 7 | // https://zulip.com/help/configure-message-editing-and-deletion 8 | // To do so, we'll need input from realm_delete_own_message_policy, 9 | // realm_message_content_delete_limit_seconds, the user's role, the current 10 | // time, and maybe more; we'll want #3898 if we can. 11 | export default async (auth: Auth, id: number): Promise => 12 | apiPatch(auth, `messages/${id}`, { 13 | content: '', 14 | }); 15 | -------------------------------------------------------------------------------- /src/api/users/getUsers.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import type { User } from '../apiTypes'; 4 | import { apiGet } from '../apiFetch'; 5 | 6 | type ApiResponseUsers = {| 7 | ...$Exact, 8 | members: $ReadOnlyArray<{| ...User, avatar_url: string | null |}>, 9 | |}; 10 | 11 | // TODO: If we start to use this, we need to convert `.avatar_url` to 12 | // an AvatarURL instance, like we do in `registerForEvents` and 13 | // `EVENT_USER_ADD` and RealmUserUpdateEvent. 14 | 15 | /** See https://zulip.com/api/get-users */ 16 | export default (auth: Auth): Promise => 17 | apiGet(auth, 'users', { client_gravatar: true }); 18 | -------------------------------------------------------------------------------- /src/common/__tests__/getStatusBarColor-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { getStatusBarColor } from '../ZulipStatusBar'; 3 | 4 | const themeDark = 'dark'; 5 | const themeLight = 'light'; 6 | 7 | describe('getStatusBarColor', () => { 8 | test('returns specific color when given, regardless of theme', () => { 9 | expect(getStatusBarColor('#fff', themeLight)).toEqual('#fff'); 10 | expect(getStatusBarColor('#fff', themeDark)).toEqual('#fff'); 11 | }); 12 | 13 | test('returns color according to theme for default case', () => { 14 | expect(getStatusBarColor(undefined, themeLight)).toEqual('white'); 15 | expect(getStatusBarColor(undefined, themeDark)).toEqual('hsl(212, 28%, 18%)'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/createNavigatorFactory.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import * as React from 'react'; 5 | import { type NavigationState } from '@react-navigation/routers'; 6 | import { type TypedNavigator, type EventMapBase } from './types'; 7 | declare export default function createNavigatorFactory< 8 | State: NavigationState<>, 9 | ScreenOptions: { ... }, 10 | EventMap: EventMapBase, 11 | NavigatorComponent: React.ComponentType, 12 | >( 13 | Navigator: NavigatorComponent, 14 | ): () => TypedNavigator< 15 | ParamList, 16 | State, 17 | ScreenOptions, 18 | EventMap, 19 | NavigatorComponent, 20 | >; 21 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export { default as createBottomTabNavigator } from './navigators/createBottomTabNavigator'; 5 | export { default as BottomTabView } from './views/BottomTabView'; 6 | export { default as BottomTabBar } from './views/BottomTabBar'; 7 | export { default as BottomTabBarHeightContext } from './utils/BottomTabBarHeightContext'; 8 | export { default as useBottomTabBarHeight } from './utils/useBottomTabBarHeight'; 9 | export { 10 | BottomTabNavigationOptions, 11 | BottomTabNavigationProp, 12 | BottomTabScreenProps, 13 | BottomTabBarProps, 14 | BottomTabBarOptions, 15 | BottomTabBarButtonProps, 16 | } from './types'; 17 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/zulipmobile/notifications/NotificationsPackage.kt: -------------------------------------------------------------------------------- 1 | package com.zulipmobile.notifications 2 | 3 | import com.facebook.react.ReactPackage 4 | import com.facebook.react.bridge.ReactApplicationContext 5 | import com.facebook.react.bridge.NativeModule 6 | import com.facebook.react.uimanager.ViewManager 7 | import java.util.ArrayList 8 | 9 | class NotificationsPackage : ReactPackage { 10 | override fun createViewManagers(reactContext: ReactApplicationContext): List> { 11 | return emptyList() 12 | } 13 | 14 | override fun createNativeModules(reactContext: ReactApplicationContext): List { 15 | return listOf(NotificationsModule(reactContext)) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/api/reportPresence.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponseSuccess, Auth } from './transportTypes'; 3 | import type { PresenceSnapshot } from './apiTypes'; 4 | import { apiPost } from './apiFetch'; 5 | 6 | type ApiResponseWithPresence = {| 7 | ...$Exact, 8 | server_timestamp: number, 9 | presences: PresenceSnapshot, 10 | |}; 11 | 12 | /** See https://zulip.readthedocs.io/en/latest/subsystems/presence.html . */ 13 | export default ( 14 | auth: Auth, 15 | isActive: boolean = true, 16 | newUserInput: boolean = false, 17 | ): Promise => 18 | apiPost(auth, 'users/me/presence', { 19 | status: isActive ? 'active' : 'idle', 20 | new_user_input: newUserInput, 21 | }); 22 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/EnsureSingleNavigator.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ReactNode as $tsflower_subst$React$ReactNode, 6 | Context as $tsflower_subst$React$Context, 7 | JSX$Element as $tsflower_subst$React$JSX$Element, 8 | } from 'tsflower/subst/react'; 9 | 10 | import * as React from 'react'; 11 | type Props = { children: $tsflower_subst$React$ReactNode, ... }; 12 | 13 | declare export var SingleNavigatorContext: $tsflower_subst$React$Context<{ 14 | register(key: string): void, 15 | unregister(key: string): void, 16 | ... 17 | } | void>; 18 | 19 | declare export default function EnsureSingleNavigator(Props): $tsflower_subst$React$JSX$Element; 20 | export {}; 21 | -------------------------------------------------------------------------------- /src/api/subscriptions/getSubscriptionToStream.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import { type UserId } from '../idTypes'; 4 | import { apiGet } from '../apiFetch'; 5 | 6 | type ApiResponseSubscriptionStatus = {| 7 | ...$Exact, 8 | is_subscribed: boolean, 9 | |}; 10 | 11 | /** 12 | * Get whether a user is subscribed to a particular stream. 13 | * 14 | * See https://zulip.com/api/get-subscription-status for 15 | * documentation of this endpoint. 16 | */ 17 | export default ( 18 | auth: Auth, 19 | userId: UserId, 20 | streamId: number, 21 | ): Promise => 22 | apiGet(auth, `users/${userId}/subscriptions/${streamId}`); 23 | -------------------------------------------------------------------------------- /src/common/ViewPlaceholder.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { View } from 'react-native'; 5 | 6 | type Props = $ReadOnly<{| 7 | width?: number, 8 | height?: number, 9 | |}>; 10 | 11 | /** 12 | * An empty layout component used to simplify UI alignment. 13 | * Use when it is easier to use this instead of setting component 14 | * padding and margin. 15 | * 16 | * @prop [width] - Width of the component in pixels. 17 | * @prop [height] - Height of the component in pixels. 18 | */ 19 | export default function ViewPlaceholder(props: Props): Node { 20 | const { width, height } = props; 21 | const style = { width, height }; 22 | return ; 23 | } 24 | -------------------------------------------------------------------------------- /src/api/uploadFile.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from './transportTypes'; 3 | import { apiFile } from './apiFetch'; 4 | import { getFileExtension, getMimeTypeFromFileExtension } from '../utils/url'; 5 | 6 | type ApiResponseUploadFile = {| 7 | ...$Exact, 8 | uri: string, 9 | |}; 10 | 11 | export default (auth: Auth, uri: string, name: string): Promise => { 12 | const formData = new FormData(); 13 | const extension = getFileExtension(name); 14 | const type = getMimeTypeFromFileExtension(extension); 15 | // $FlowFixMe[incompatible-call] 16 | formData.append('file', { uri, name, type, extension }); 17 | return apiFile(auth, 'user_uploads', formData); 18 | }; 19 | -------------------------------------------------------------------------------- /src/api/users/getUserProfile.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth, ApiResponseSuccess } from '../transportTypes'; 3 | import { type UserId } from '../idTypes'; 4 | import { apiGet } from '../apiFetch'; 5 | 6 | type ApiResponseUserProfile = {| 7 | ...$Exact, 8 | client_id: string, 9 | email: string, 10 | full_name: string, 11 | is_admin: boolean, 12 | is_bot: boolean, 13 | max_message_id: number, 14 | short_name: string, 15 | user_id: UserId, 16 | // pointer: number, /* deprecated 2020-02; see zulip/zulip#8994 */ 17 | |}; 18 | 19 | /** See https://zulip.com/api/get-own-user */ 20 | export default (auth: Auth, clientGravatar: boolean = true): Promise => 21 | apiGet(auth, 'users/me'); 22 | -------------------------------------------------------------------------------- /src/webview/js/matchesPolyfill.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | // Official MDN polyfill for Element.matches 3 | // Source: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches 4 | export default ` 5 | if (!Element.prototype.matches) { 6 | Element.prototype.matches = 7 | Element.prototype.matchesSelector || 8 | Element.prototype.mozMatchesSelector || 9 | Element.prototype.msMatchesSelector || 10 | Element.prototype.oMatchesSelector || 11 | Element.prototype.webkitMatchesSelector || 12 | function(s) { 13 | var matches = (this.document || this.ownerDocument).querySelectorAll(s), 14 | i = matches.length; 15 | while (--i >= 0 && matches.item(i) !== this) {} 16 | return i > -1; 17 | }; 18 | } 19 | `; 20 | -------------------------------------------------------------------------------- /src/utils/unread.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { FlagsState, Message, Outbox } from '../types'; 3 | 4 | export const filterUnreadMessageIds = ( 5 | messageIds: $ReadOnlyArray, 6 | flags: FlagsState, 7 | ): number[] => messageIds.filter((msgId: number) => !flags || !flags.read || !flags.read[msgId]); 8 | 9 | export const filterUnreadMessagesInRange = ( 10 | messages: $ReadOnlyArray, 11 | flags: FlagsState, 12 | fromId: number, 13 | toId: number, 14 | ): number[] => { 15 | const messagesInRange = messages 16 | .filter(msg => !msg.isOutbox) 17 | .filter(msg => msg.id >= fromId && msg.id <= toId); 18 | return filterUnreadMessageIds( 19 | messagesInRange.map(x => x.id), 20 | flags, 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # This should be the only .eslintignore file in our tree. 2 | # See apply_eslintignore in tools/test. 3 | 4 | # These are purely type definitions, no runtime code. Most of them 5 | # are third-party code, too, so naturally don't match our style. 6 | **/flow-typed/** 7 | types/react-intl.js.flow 8 | types/@react-native-community/netinfo/** 9 | types/@sentry/react-native.js.flow 10 | types/expo-web-browser/** 11 | types/react-native-webview.js.flow 12 | 13 | # These are type-tests, made up of code that gets type-checked but 14 | # never actually run. They're naturally full of dead code which 15 | # ESLint would complain about; and because the code never runs, other 16 | # things it might complain about don't really matter anyway. 17 | **/__flow-tests__/** 18 | -------------------------------------------------------------------------------- /src/api/subscriptions/subscriptionRemove.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiDelete } from '../apiFetch'; 4 | 5 | /** See https://zulip.com/api/unsubscribe */ 6 | export default ( 7 | auth: Auth, 8 | // TODO(server-future): This should use a stream ID (#3918), not stream name. 9 | // Server issue: https://github.com/zulip/zulip/issues/10744 10 | subscriptions: $ReadOnlyArray, 11 | // TODO(server-3.0): Send numeric user IDs (#3764), not emails. 12 | principals?: $ReadOnlyArray, 13 | ): Promise => 14 | apiDelete(auth, 'users/me/subscriptions', { 15 | subscriptions: JSON.stringify(subscriptions), 16 | principals: JSON.stringify(principals), 17 | }); 18 | -------------------------------------------------------------------------------- /src/api/messages/sendMessage.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import type { ApiResponse, Auth } from '../transportTypes'; 4 | import { apiPost } from '../apiFetch'; 5 | 6 | /** See https://zulip.com/api/send-message */ 7 | export default async ( 8 | auth: Auth, 9 | params: {| 10 | type: 'private' | 'stream', 11 | to: string, 12 | // TODO(server-2.0): Say "topic", not "subject" 13 | subject?: string, 14 | content: string, 15 | localId?: number, 16 | eventQueueId?: string, 17 | |}, 18 | ): Promise => 19 | apiPost(auth, 'messages', { 20 | type: params.type, 21 | to: params.to, 22 | subject: params.subject, 23 | content: params.content, 24 | local_id: params.localId, 25 | queue_id: params.eventQueueId, 26 | }); 27 | -------------------------------------------------------------------------------- /src/utils/networkActivity.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { StatusBar, Platform } from 'react-native'; 3 | 4 | // Network activity indicators should be visible if *any* network activity is occurring 5 | 6 | let activityCounter = 0; 7 | 8 | export const networkActivityStart = (isSilent: boolean) => { 9 | if (isSilent) { 10 | return; 11 | } 12 | 13 | activityCounter++; 14 | if (Platform.OS === 'ios') { 15 | StatusBar.setNetworkActivityIndicatorVisible(true); 16 | } 17 | }; 18 | 19 | export const networkActivityStop = (isSilent: boolean) => { 20 | if (isSilent) { 21 | return; 22 | } 23 | 24 | activityCounter--; 25 | if (activityCounter === 0 && Platform.OS === 'ios') { 26 | StatusBar.setNetworkActivityIndicatorVisible(false); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/boot/__tests__/reducers-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import reducers from '../reducers'; 3 | import { discardKeys, storeKeys, cacheKeys } from '../store'; 4 | import * as eg from '../../__tests__/lib/exampleData'; 5 | 6 | describe('reducers', () => { 7 | test('reducers return the default states on unknown action', () => { 8 | // $FlowFixMe[incompatible-call] bogus action object 9 | expect(() => reducers({}, { type: 'UNKNOWN_ACTION' })).not.toThrow(); 10 | }); 11 | 12 | test('every reducer is listed in config as "discard", "store" or "cache"', () => { 13 | const configKeys = [...discardKeys, ...storeKeys, ...cacheKeys]; 14 | const reducerKeys = Object.keys(eg.baseReduxState); 15 | expect(configKeys.sort()).toEqual(reducerKeys.sort()); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/sharing/types.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | export type SharedFile = {| 4 | name: string, 5 | mimeType: string, 6 | url: string, 7 | |}; 8 | 9 | /** 10 | * The data we get when the user "shares" to Zulip from another app. 11 | * 12 | * On Android, these objects are sent to JS from our platform-native code, 13 | * constructed there by `getParamsFromIntent` in `SharingHelper.kt`. 14 | * The correspondence of that code with this type isn't type-checked. 15 | * 16 | * (On iOS, we don't currently support this feature in the first place.) 17 | */ 18 | // prettier-ignore 19 | export type SharedData = 20 | // Note: Keep these in sync with platform-native code. 21 | | {| type: 'text', sharedText: string |} 22 | | {| type: 'file', files: $ReadOnlyArray |}; 23 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/ServerContainer.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ForwardRefExoticComponent as $tsflower_subst$React$ForwardRefExoticComponent, 6 | ReactNode as $tsflower_subst$React$ReactNode, 7 | RefAttributes as $tsflower_subst$React$RefAttributes, 8 | } from 'tsflower/subst/react'; 9 | 10 | import * as React from 'react'; 11 | import { type ServerContextType } from './ServerContext'; 12 | import { type ServerContainerRef } from './types'; 13 | declare var _default: $tsflower_subst$React$ForwardRefExoticComponent< 14 | ServerContextType & { 15 | children: $tsflower_subst$React$ReactNode, 16 | ... 17 | } & $tsflower_subst$React$RefAttributes, 18 | >; 19 | export default _default; 20 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/specs/NativeSafeAreaView.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ViewProps as $tsflower_subst$RN$ViewProps } from 'tsflower/subst/react-native'; 5 | import type { Readonly } from 'tsflower/subst/lib'; 6 | import { type WithDefault } from 'react-native/Libraries/Types/CodegenTypes'; 7 | import { type HostComponent } from 'react-native'; 8 | 9 | export type NativeProps = { 10 | ...$tsflower_subst$RN$ViewProps, 11 | mode?: WithDefault<'padding' | 'margin', 'padding'>, 12 | edges?: Readonly<{ 13 | top: string, 14 | right: string, 15 | bottom: string, 16 | left: string, 17 | ... 18 | }>, 19 | ... 20 | }; 21 | 22 | declare var _default: HostComponent; 23 | export default _default; 24 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/zulipmobile/notifications/FcmListenerService.kt: -------------------------------------------------------------------------------- 1 | package com.zulipmobile.notifications 2 | 3 | import com.facebook.react.ReactApplication 4 | import com.google.firebase.messaging.FirebaseMessagingService 5 | import com.google.firebase.messaging.RemoteMessage 6 | 7 | class FcmListenerService : FirebaseMessagingService() { 8 | override fun onMessageReceived(message: RemoteMessage) { 9 | onReceived(this, message.data) 10 | } 11 | 12 | override fun onNewToken(token: String) { 13 | super.onNewToken(token) 14 | val reactContext = (application as ReactApplication) 15 | .reactNativeHost 16 | .reactInstanceManager 17 | .currentReactContext 18 | NotificationsModule.emitToken(reactContext, token) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ios/ZulipMobile/UtilManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // UtilManager.m 3 | // ZulipMobile 4 | // 5 | 6 | #import "UtilManager.h" 7 | 8 | @implementation UtilManager 9 | 10 | RCT_EXPORT_MODULE(); 11 | 12 | RCT_EXPORT_METHOD(randomBase64:(NSUInteger)length 13 | resolver:(RCTPromiseResolveBlock)resolve 14 | rejecter:(RCTPromiseRejectBlock)reject) 15 | { 16 | NSMutableData *data = [NSMutableData dataWithLength:length]; 17 | int ret = SecRandomCopyBytes(kSecRandomDefault, length, [data mutableBytes]); 18 | 19 | if (ret != 0) { 20 | NSError *error = [NSError errorWithDomain:@"zulip" code:ret userInfo:nil]; 21 | reject(@"random_failed", @"Could not generate random data", error); 22 | } else { 23 | resolve([data base64EncodedStringWithOptions:0]); 24 | } 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /src/webview/css/cssEmojis.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ServerEmojiData } from '../../api/modelTypes'; 3 | 4 | import { displayCharacterForUnicodeEmojiCode, availableUnicodeEmojiCodes } from '../../emoji/data'; 5 | 6 | const codeToCss = (code, serverEmojiData): string => 7 | `.emoji-${code}:before { content: '${displayCharacterForUnicodeEmojiCode( 8 | code, 9 | serverEmojiData, 10 | )}'; }`; 11 | 12 | const cssEmojis = (serverEmojiData: ServerEmojiData | null): string => { 13 | const availableCodes = serverEmojiData?.code_to_names.keys() ?? availableUnicodeEmojiCodes; 14 | 15 | const chunks = []; 16 | for (const code of availableCodes) { 17 | chunks.push(codeToCss(code, serverEmojiData)); 18 | } 19 | 20 | return chunks.join('\n'); 21 | }; 22 | 23 | export default cssEmojis; 24 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type StackHeaderInterpolationProps, type StackHeaderInterpolatedStyle } from '../types'; 5 | declare export function forUIKit(StackHeaderInterpolationProps): StackHeaderInterpolatedStyle; 6 | declare export function forFade(StackHeaderInterpolationProps): StackHeaderInterpolatedStyle; 7 | declare export function forSlideLeft(StackHeaderInterpolationProps): StackHeaderInterpolatedStyle; 8 | declare export function forSlideRight(StackHeaderInterpolationProps): StackHeaderInterpolatedStyle; 9 | declare export function forSlideUp(StackHeaderInterpolationProps): StackHeaderInterpolatedStyle; 10 | declare export function forNoAnimation(): StackHeaderInterpolatedStyle; 11 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/TouchableItem.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { ViewProps as $tsflower_subst$RN$ViewProps } from 'tsflower/subst/react-native'; 5 | 6 | import type { 7 | ReactNode as $tsflower_subst$React$ReactNode, 8 | JSX$Element as $tsflower_subst$React$JSX$Element, 9 | } from 'tsflower/subst/react'; 10 | 11 | import * as React from 'react'; 12 | import 'react-native'; 13 | 14 | export type Props = $tsflower_subst$RN$ViewProps & { 15 | pressColor?: string, 16 | disabled?: boolean, 17 | borderless?: boolean, 18 | delayPressIn?: number, 19 | onPress?: () => void, 20 | children: $tsflower_subst$React$ReactNode, 21 | ... 22 | }; 23 | 24 | declare export default function TouchableItem(Props): $tsflower_subst$React$JSX$Element; 25 | -------------------------------------------------------------------------------- /types/react-native-tab-view/lib/typescript/src/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | export { default as TabBar } from './TabBar'; 5 | export { Props as TabBarProps } from './TabBar'; 6 | export { default as TabView } from './TabView'; 7 | export { Props as TabViewProps } from './TabView'; 8 | export { default as TabBarIndicator } from './TabBarIndicator'; 9 | export { Props as TabBarIndicatorProps } from './TabBarIndicator'; 10 | export { default as TabBarItem } from './TabBarItem'; 11 | export { Props as TabBarItemProps } from './TabBarItem'; 12 | export { default as TouchableItem } from './TouchableItem'; 13 | export { default as SceneMap } from './SceneMap'; 14 | export { default as ScrollPager } from './ScrollPager'; 15 | export { Route, NavigationState, SceneRendererProps } from './types'; 16 | -------------------------------------------------------------------------------- /src/common/SectionSeparatorBetween.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import SectionSeparator from './SectionSeparator'; 5 | 6 | /* 7 | * Upstream `SectionList` is full of `any`s. This type is incomplete, 8 | * and just captures what we use. 9 | */ 10 | type Props = $ReadOnly<{| 11 | leadingItem: ?{ ... }, 12 | leadingSection: ?{ data: { length: number, ... }, ... }, 13 | |}>; 14 | 15 | /** Can be passed to RN's `SectionList` as `SectionSeparatorComponent`. */ 16 | export default function SectionSeparatorBetween(props: Props): Node { 17 | const { leadingItem, leadingSection } = props; 18 | 19 | if (leadingItem || !leadingSection || leadingSection.data.length === 0) { 20 | return null; 21 | } 22 | 23 | return ; 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/__tests__/DefaultMap-test.js: -------------------------------------------------------------------------------- 1 | // @flow strict-local 2 | 3 | import DefaultMap from '../DefaultMap'; 4 | 5 | describe('DefaultMap', () => { 6 | test('smoke', () => { 7 | const m = new DefaultMap(() => []); 8 | expect([...m.map.entries()].sort()).toEqual([]); 9 | 10 | // Create a value. 11 | m.getOrCreate('a').push(1); 12 | expect([...m.map.entries()].sort()).toEqual([['a', [1]]]); 13 | 14 | // Different key gets a fresh value. 15 | m.getOrCreate('b').push(2); 16 | // prettier-ignore 17 | expect([...m.map.entries()].sort()).toEqual([['a', [1]], ['b', [2]]]); 18 | 19 | // Existing key gets the existing value. 20 | m.getOrCreate('a').push(3); 21 | // prettier-ignore 22 | expect([...m.map.entries()].sort()).toEqual([['a', [1, 3]], ['b', [2]]]); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/firebase.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 1:835904834568:android:19a01c6476449260 14 | 835904834568 15 | 16 | -------------------------------------------------------------------------------- /src/api/subscriptions/subscriptionAdd.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | type SubscriptionObj = {| 6 | // TODO(server-future): This should use a stream ID (#3918), not stream name. 7 | // Server issue: https://github.com/zulip/zulip/issues/10744 8 | name: string, 9 | |}; 10 | 11 | /** See https://zulip.com/api/subscribe */ 12 | export default ( 13 | auth: Auth, 14 | subscriptions: $ReadOnlyArray, 15 | // TODO(server-3.0): Send numeric user IDs (#3764), not emails. 16 | principals?: $ReadOnlyArray, 17 | ): Promise => 18 | apiPost(auth, 'users/me/subscriptions', { 19 | subscriptions: JSON.stringify(subscriptions), 20 | principals: JSON.stringify(principals), 21 | }); 22 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/MaskedView.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import * as React from 'react'; 5 | 6 | type Props = { 7 | maskElement: React$Element, 8 | children: React$Element, 9 | ... 10 | }; 11 | 12 | declare export default function MaskedView( 13 | Props, 14 | ): React$Element< 15 | | string 16 | | (( 17 | props: any, 18 | ) => 19 | | React$Element< 20 | | string 21 | | any 22 | | $FlowFixMe /* new (props: any) => React.Component */ /* tsflower-unimplemented: ConstructorType */, 23 | > 24 | | null 25 | | $FlowFixMe) /* new (props: any) => React.Component */ /* tsflower-unimplemented: ConstructorType */, 26 | >; 27 | export {}; 28 | -------------------------------------------------------------------------------- /src/alertWords/alertWordsReducer.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { AlertWordsState, PerAccountApplicableAction } from '../types'; 3 | import { REGISTER_COMPLETE, EVENT_ALERT_WORDS, RESET_ACCOUNT_DATA } from '../actionConstants'; 4 | import { NULL_ARRAY } from '../nullObjects'; 5 | 6 | const initialState = NULL_ARRAY; 7 | 8 | export default ( 9 | state: AlertWordsState = initialState, // eslint-disable-line default-param-last 10 | action: PerAccountApplicableAction, 11 | ): AlertWordsState => { 12 | switch (action.type) { 13 | case RESET_ACCOUNT_DATA: 14 | return initialState; 15 | 16 | case REGISTER_COMPLETE: 17 | return action.data.alert_words; 18 | 19 | case EVENT_ALERT_WORDS: 20 | return action.alert_words || initialState; 21 | 22 | default: 23 | return state; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/nav/IconUnreadMentions.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import React from 'react'; 4 | import type { Node } from 'react'; 5 | import { View } from 'react-native'; 6 | 7 | import { useSelector } from '../react-redux'; 8 | import { getUnreadMentionsTotal } from '../selectors'; 9 | import { IconMention } from '../common/Icons'; 10 | import CountOverlay from '../common/CountOverlay'; 11 | 12 | type Props = $ReadOnly<{| 13 | color: string, 14 | |}>; 15 | 16 | export default function IconUnreadMentions(props: Props): Node { 17 | const { color } = props; 18 | const unreadMentionsTotal = useSelector(getUnreadMentionsTotal); 19 | 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * These two were added to the RN template file in 4 | * `facebook/react-native@f4d5e8c23` (released in 0.60.5) because of 5 | * conflicts with `eslint-config-react-native-community`. We haven't 6 | * activated that config (we might, it's #4119), and we haven't 7 | * otherwise found a use for these rules; we don't follow them. 8 | */ 9 | // bracketSpacing: false, 10 | // jsxBracketSameLine: true, 11 | 12 | printWidth: 100, 13 | 14 | // Changed to "flow" just because Flow claims it's necessary for 15 | // formatting Flow enums. Unconfirmed…but it doesn't seem to hurt. Doc: 16 | // https://flow.org/en/docs/enums/enabling-enums/#toc-upgrade-tooling 17 | parser: 'flow', 18 | 19 | singleQuote: true, 20 | trailingComma: 'all', 21 | arrowParens: 'avoid', 22 | }; 23 | -------------------------------------------------------------------------------- /src/__tests__/isAppOwnDomain-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import isAppOwnDomain from '../isAppOwnDomain'; 4 | 5 | describe('isAppOwnDomain', () => { 6 | test.each([ 7 | ['https://chat.zulip.org', true], 8 | ['https://zulipchat.com', true], 9 | ['https://zulip.com', true], 10 | ['https://example.zulipchat.com', true], 11 | ['https://example.zulip.com', true], 12 | ['https://example.zulip.com/api/v1/server_settings', true], 13 | ['https://example.zulip.com/avatar/1234', true], 14 | 15 | ['https://zulipchat.org', false], 16 | ['https://www.google.com', false], 17 | ['https://zulipchat.co.uk', false], 18 | ['https://chat.zulip.io', false], 19 | ])('%s should be %p', (urlStr: string, expected: boolean) => { 20 | expect(isAppOwnDomain(new URL(urlStr))).toBe(expected); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/api/subscriptions/setTopicMute.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPatch } from '../apiFetch'; 4 | 5 | /** See https://zulip.com/api/mute-topic */ 6 | export default async ( 7 | auth: Auth, 8 | // TODO(server-2.0): Switch to stream ID (#3918), instead of name. 9 | // (The version that was introduced in isn't documented: 10 | // https://github.com/zulip/zulip/issues/11136#issuecomment-1033046851 11 | // but see: 12 | // https://github.com/zulip/zulip-mobile/issues/3244#issuecomment-840200325 13 | // ) 14 | stream: string, 15 | topic: string, 16 | value: boolean, 17 | ): Promise => 18 | apiPatch(auth, 'users/me/subscriptions/muted_topics', { 19 | stream, 20 | topic, 21 | op: value ? 'add' : 'remove', 22 | }); 23 | -------------------------------------------------------------------------------- /src/common/SearchEmptyState.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { View } from 'react-native'; 5 | 6 | import ZulipTextIntl from './ZulipTextIntl'; 7 | import { createStyleSheet } from '../styles'; 8 | 9 | const styles = createStyleSheet({ 10 | container: { 11 | flex: 1, 12 | padding: 16, 13 | marginTop: 8, 14 | justifyContent: 'center', 15 | }, 16 | text: { 17 | fontSize: 18, 18 | textAlign: 'center', 19 | }, 20 | }); 21 | 22 | type Props = $ReadOnly<{| 23 | text: string, 24 | |}>; 25 | 26 | export default function SearchEmptyState(props: Props): Node { 27 | const { text } = props; 28 | 29 | return ( 30 | 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/zulipmobile/SentryUtils.kt: -------------------------------------------------------------------------------- 1 | package com.zulipmobile 2 | 3 | import io.sentry.Sentry 4 | import io.sentry.SentryLevel 5 | 6 | /** 7 | * A home for things that ought to be static extensions of `Sentry`. 8 | * 9 | * Extending Java classes with static members isn't currently a feature 10 | * available in Kotlin: 11 | * https://youtrack.jetbrains.com/issue/KT-11968 12 | * so this is our substitute. 13 | */ 14 | class SentryX { 15 | companion object { 16 | /** 17 | * Like `Sentry.captureException`, but at level `SentryLevel.WARNING`. 18 | */ 19 | public fun warnException(e: Throwable) { 20 | Sentry.withScope { scope -> 21 | scope.level = SentryLevel.WARNING 22 | Sentry.captureException(e) 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/caughtup/caughtUpSelectors.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { CaughtUp, CaughtUpState, PerAccountState, Narrow } from '../types'; 3 | import { NULL_OBJECT } from '../nullObjects'; 4 | import { keyFromNarrow } from '../utils/narrow'; 5 | 6 | /** The value implicitly represented by a missing entry in CaughtUpState. */ 7 | export const DEFAULT_CAUGHTUP: CaughtUp = { 8 | older: false, 9 | newer: false, 10 | }; 11 | 12 | export const getCaughtUp = (state: PerAccountState): CaughtUpState => state.caughtUp || NULL_OBJECT; 13 | 14 | export const getCaughtUpForNarrowInner = (state: CaughtUpState, narrow: Narrow): CaughtUp => 15 | state[keyFromNarrow(narrow)] || DEFAULT_CAUGHTUP; 16 | 17 | export const getCaughtUpForNarrow = (state: PerAccountState, narrow: Narrow): CaughtUp => 18 | getCaughtUpForNarrowInner(getCaughtUp(state), narrow); 19 | -------------------------------------------------------------------------------- /src/webview/html/__tests__/template-test.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | // $FlowFixMe[untyped-import] 3 | import escape from 'lodash.escape'; 4 | import template from '../template'; 5 | 6 | describe('template', () => { 7 | const evil = '&'; 8 | const escaped = escape(evil); 9 | 10 | test('interpolates', () => { 11 | expect(template``).toEqual(''); 12 | expect(template`a`).toEqual('a'); 13 | expect(template`a${'b'}c`).toEqual('abc'); 14 | }); 15 | 16 | test('escapes HTML', () => { 17 | expect(template`a${evil}c`).toEqual(`a${escaped}c`); 18 | }); 19 | 20 | test('optionally preserves HTML', () => { 21 | expect(template`a$!${evil}c`).toEqual(`a${evil}c`); 22 | }); 23 | 24 | test('has an escape for the option', () => { 25 | expect(template`a$\!${evil}c`).toEqual(`a$!${escaped}c`); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/views/SafeAreaProviderCompat.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ReactNode as $tsflower_subst$React$ReactNode, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | 11 | declare export var initialSafeAreaInsets: 12 | | { 13 | top: number, 14 | bottom: number, 15 | right: number, 16 | left: number, 17 | ... 18 | } 19 | | { 20 | top: number, 21 | right: number, 22 | bottom: number, 23 | left: number, 24 | ... 25 | }; 26 | 27 | type Props = { children: $tsflower_subst$React$ReactNode, ... }; 28 | declare export default function SafeAreaProviderCompat(Props): $tsflower_subst$React$JSX$Element; 29 | export {}; 30 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/BorderlessButton.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ComponentProps as $tsflower_subst$React$ComponentProps, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | import { BaseButton } from 'react-native-gesture-handler'; 11 | type Props = $tsflower_subst$React$ComponentProps & { 12 | pressOpacity: number, 13 | ... 14 | }; 15 | 16 | declare export default class BorderlessButton extends React.Component { 17 | defaultProps: { 18 | activeOpacity: number, 19 | borderless: boolean, 20 | ... 21 | }; 22 | opacity: any; 23 | handleActiveStateChange: any; 24 | render(): $tsflower_subst$React$JSX$Element; 25 | } 26 | 27 | export {}; 28 | -------------------------------------------------------------------------------- /types/expo-modules-core/build/Platform.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | // TODO[tsflower]: From @types/react-native; add to subst/react-native. 5 | type PlatformOSType = 'ios' | 'android' | 'macos' | 'windows' | 'web' | 'native'; 6 | 7 | export type PlatformSelectOSType = PlatformOSType | 'native' | 'electron' | 'default'; 8 | 9 | export type PlatformSelect = ( 10 | specifics: $FlowFixMe /* { 11 | [platform in PlatformSelectOSType]?: T; 12 | } */ /* tsflower-unimplemented: MappedType */, 13 | ) => T; 14 | 15 | declare var Platform: { 16 | OS: 'ios' | 'android' | 'windows' | 'macos' | 'web', 17 | select: PlatformSelect, 18 | isDOMAvailable: boolean, 19 | canUseEventListeners: boolean, 20 | canUseViewport: boolean, 21 | isAsyncDebugging: boolean, 22 | ... 23 | }; 24 | 25 | export default Platform; 26 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/specs/NativeSafeAreaContext.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type TurboModule } from 'react-native/Libraries/TurboModule/RCTExport'; 5 | import { type Double } from 'react-native/Libraries/Types/CodegenTypes'; 6 | 7 | export interface Spec extends TurboModule { 8 | getConstants: () => { 9 | initialWindowMetrics?: { 10 | insets: { 11 | top: Double, 12 | right: Double, 13 | bottom: Double, 14 | left: Double, 15 | ... 16 | }, 17 | frame: { 18 | x: Double, 19 | y: Double, 20 | width: Double, 21 | height: Double, 22 | ... 23 | }, 24 | ... 25 | }, 26 | ... 27 | }; 28 | } 29 | 30 | declare var _default: Spec | null; 31 | export default _default; 32 | -------------------------------------------------------------------------------- /src/api/pollForEvents.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponseSuccess, Auth } from './transportTypes'; 3 | import type { GeneralEvent } from './eventTypes'; 4 | import { apiGet } from './apiFetch'; 5 | 6 | type ApiResponsePollEvents = {| 7 | ...$Exact, 8 | events: $ReadOnlyArray, 9 | |}; 10 | 11 | /** See https://zulip.com/api/get-events */ 12 | // TODO: Handle downgrading server across kThresholdVersion, which we'd hear 13 | // about in `restart` events, by throwing a ServerTooOldError. This case 14 | // seems pretty rare but is possible. 15 | export default (auth: Auth, queueId: string, lastEventId: number): Promise => 16 | apiGet( 17 | auth, 18 | 'events', 19 | { 20 | queue_id: queueId, 21 | last_event_id: lastEventId, 22 | }, 23 | true, 24 | ); 25 | -------------------------------------------------------------------------------- /src/chat/InvalidNarrow.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import React from 'react'; 4 | import type { Node } from 'react'; 5 | import { StyleSheet, View } from 'react-native'; 6 | 7 | import type { Narrow } from '../types'; 8 | import ZulipTextIntl from '../common/ZulipTextIntl'; 9 | 10 | const styles = StyleSheet.create({ 11 | container: { 12 | flex: 1, 13 | alignItems: 'center', 14 | justifyContent: 'center', 15 | }, 16 | text: { 17 | fontSize: 20, 18 | paddingLeft: 10, 19 | padding: 8, 20 | }, 21 | }); 22 | 23 | type Props = $ReadOnly<{| 24 | narrow: Narrow, 25 | |}>; 26 | 27 | export default function InvalidNarrow(props: Props): Node { 28 | return ( 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /types/@react-navigation/bottom-tabs/lib/typescript/src/views/Badge.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | WithAnimatedValue as $tsflower_subst$RN$Animated$WithAnimatedValue, 6 | StyleProp as $tsflower_subst$RN$StyleProp, 7 | TextStyle as $tsflower_subst$RN$TextStyle, 8 | } from 'tsflower/subst/react-native'; 9 | 10 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 11 | import { Animated } from 'react-native'; 12 | 13 | type Props = { 14 | visible: boolean, 15 | children?: string | number, 16 | size?: number, 17 | style?: $tsflower_subst$RN$Animated$WithAnimatedValue< 18 | $tsflower_subst$RN$StyleProp<$tsflower_subst$RN$TextStyle>, 19 | >, 20 | ... 21 | }; 22 | 23 | declare export default function Badge(Props): $tsflower_subst$React$JSX$Element | null; 24 | export {}; 25 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/TouchableItem.ios.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { 5 | ComponentProps as $tsflower_subst$React$ComponentProps, 6 | JSX$Element as $tsflower_subst$React$JSX$Element, 7 | } from 'tsflower/subst/react'; 8 | 9 | import * as React from 'react'; 10 | import { BaseButton } from 'react-native-gesture-handler'; 11 | type Props = $tsflower_subst$React$ComponentProps & { 12 | pressOpacity: number, 13 | ... 14 | }; 15 | 16 | declare export default class TouchableItem extends React.Component { 17 | defaultProps: { 18 | pressOpacity: number, 19 | borderless: boolean, 20 | enabled: boolean, 21 | ... 22 | }; 23 | opacity: any; 24 | handleActiveStateChange: any; 25 | render(): $tsflower_subst$React$JSX$Element; 26 | } 27 | 28 | export {}; 29 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenLocal() 5 | google() 6 | } 7 | } 8 | 9 | rootProject.name = 'ZulipMobile' 10 | 11 | apply from: '../node_modules/expo/scripts/autolinking.gradle' 12 | useExpoModules() 13 | 14 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); 15 | applyNativeModulesSettingsGradle(settings) 16 | 17 | include ':app' 18 | 19 | include ':ReactAndroid' 20 | project(':ReactAndroid').projectDir = new File( 21 | rootProject.projectDir, '../node_modules/react-native/ReactAndroid') 22 | 23 | // The RN Gradle Plugin is needed to build RN from source. 24 | // (We do that to make some changes to RN, with our zulip/react-native fork.) 25 | includeBuild('../node_modules/react-native/packages/react-native-gradle-plugin') 26 | -------------------------------------------------------------------------------- /src/mute/muteModelTypes.js: -------------------------------------------------------------------------------- 1 | // @flow strict-local 2 | import Immutable from 'immutable'; 3 | 4 | import { type UserTopicVisibilityPolicy } from '../api/modelTypes'; 5 | 6 | /** 7 | * The "visibility policy" our user has chosen for each topic. 8 | * 9 | * See jsdoc of UserTopicVisibilityPolicy for background. 10 | * 11 | * In this data structure, the keys are stream ID and then topic name. 12 | * Values of `UserTopicVisibilityPolicy.None` are represented by absence, 13 | * and streams where the map would be empty are also omitted. 14 | */ 15 | // TODO(#5381): Ideally we'd call this UserTopicState and `state.userTopic`. 16 | // But it's currently a pain to actually rename a state subtree: #5381. 17 | export type MuteState = Immutable.Map< 18 | number, // stream ID 19 | Immutable.Map< 20 | string, // topic name 21 | UserTopicVisibilityPolicy, 22 | >, 23 | >; 24 | -------------------------------------------------------------------------------- /types/@react-navigation/material-top-tabs/lib/typescript/src/views/MaterialTopTabView.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { JSX$Element as $tsflower_subst$React$JSX$Element } from 'tsflower/subst/react'; 5 | import { type TabNavigationState, type ParamListBase } from '@react-navigation/native'; 6 | 7 | import { 8 | type MaterialTopTabDescriptorMap, 9 | type MaterialTopTabNavigationConfig, 10 | type MaterialTopTabNavigationHelpers, 11 | } from '../types'; 12 | 13 | type Props = MaterialTopTabNavigationConfig & { 14 | state: TabNavigationState, 15 | navigation: MaterialTopTabNavigationHelpers, 16 | descriptors: MaterialTopTabDescriptorMap, 17 | tabBarPosition?: 'top' | 'bottom', 18 | ... 19 | }; 20 | 21 | declare export default function MaterialTopTabView(Props): $tsflower_subst$React$JSX$Element; 22 | export {}; 23 | -------------------------------------------------------------------------------- /types/@react-navigation/stack/lib/typescript/src/views/MaskedViewNative.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import typeof * as $tsflower_import_typeof$_$_40_react_2d_native_2d_community_2f_masked_2d_view from '@react-native-community/masked-view'; 5 | 6 | import type { 7 | ComponentProps as $tsflower_subst$React$ComponentProps, 8 | JSX$Element as $tsflower_subst$React$JSX$Element, 9 | } from 'tsflower/subst/react'; 10 | 11 | import * as React from 'react'; 12 | type MaskedViewType = $ElementType< 13 | $tsflower_import_typeof$_$_40_react_2d_native_2d_community_2f_masked_2d_view, 14 | 'default', 15 | >; 16 | type Props = $tsflower_subst$React$ComponentProps & { 17 | children: React$Element, 18 | ... 19 | }; 20 | declare export default function MaskedView(Props): $tsflower_subst$React$JSX$Element; 21 | export {}; 22 | -------------------------------------------------------------------------------- /src/styles/miscStyles.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { CONTROL_SIZE } from './constants'; 3 | 4 | export const statics = { 5 | largerText: { 6 | fontSize: 20, 7 | }, 8 | row: { 9 | flexDirection: 'row', 10 | alignItems: 'center', 11 | }, 12 | listItem: { 13 | flexDirection: 'row', 14 | alignItems: 'center', 15 | paddingVertical: 8, 16 | paddingHorizontal: 16, 17 | }, 18 | flexed: { 19 | flex: 1, 20 | }, 21 | rightItem: { 22 | marginLeft: 'auto', 23 | }, 24 | center: { 25 | flex: 1, 26 | justifyContent: 'center', 27 | alignItems: 'center', 28 | }, 29 | field: { 30 | flex: 1, 31 | flexDirection: 'row', 32 | height: CONTROL_SIZE, 33 | marginTop: 5, 34 | marginBottom: 5, 35 | }, 36 | alignBottom: { 37 | flexDirection: 'column', 38 | justifyContent: 'flex-end', 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/zulipmobile/ShareToZulipActivity.kt: -------------------------------------------------------------------------------- 1 | package com.zulipmobile; 2 | 3 | import android.content.ComponentName 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | 8 | /// The activity for when a user shares to Zulip from another app. 9 | /// 10 | /// This is a tiny shim activity, which forwards the user on to our 11 | /// [MainActivity] to get the actual UI for sharing to Zulip. 12 | class ShareToZulipActivity : AppCompatActivity() { 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | intent.component = 16 | ComponentName(applicationContext.packageName, "com.zulipmobile.MainActivity") 17 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 18 | startActivity(intent) 19 | finish() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/api/messages/updateMessageFlags.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponseSuccess, Auth } from '../transportTypes'; 3 | import type { UserMessageFlag } from '../modelTypes'; 4 | import { apiPost } from '../apiFetch'; 5 | 6 | export type ApiResponseUpdateMessageFlags = {| 7 | ...$Exact, 8 | 9 | // The `messages` property is deprecated. See discussion: 10 | // https://chat.zulip.org/#narrow/stream/378-api-design/topic/mark-as-unread.20request/near/1463920 11 | -messages: $ReadOnlyArray, 12 | |}; 13 | 14 | /** https://zulip.com/api/update-message-flags */ 15 | export default ( 16 | auth: Auth, 17 | messageIds: $ReadOnlyArray, 18 | op: 'add' | 'remove', 19 | flag: UserMessageFlag, 20 | ): Promise => 21 | apiPost(auth, 'messages/flags', { messages: JSON.stringify(messageIds), flag, op }); 22 | -------------------------------------------------------------------------------- /src/api/settings/toggleMobilePushSettings.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ApiResponse, Auth } from '../transportTypes'; 3 | import { apiPatch } from '../apiFetch'; 4 | 5 | const getRequestBody = (opp, value) => { 6 | const data = {}; 7 | if (opp === 'offline_notification_change') { 8 | data.enable_offline_push_notifications = value; 9 | } else if (opp === 'online_notification_change') { 10 | data.enable_online_push_notifications = value; 11 | } else if (opp === 'stream_notification_change') { 12 | data.enable_stream_push_notifications = value; 13 | } 14 | return data; 15 | }; 16 | 17 | export default async ({ 18 | auth, 19 | opp, 20 | value, 21 | }: {| 22 | auth: Auth, 23 | opp: string, 24 | value: boolean, 25 | |}): Promise => 26 | apiPatch(auth, 'settings/notifications', { 27 | ...getRequestBody(opp, value), 28 | }); 29 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | const isDevelopment = process.env.NODE_ENV === 'development'; 3 | 4 | type Config = {| 5 | requestLongTimeoutMs: number, 6 | messagesPerRequest: number, 7 | messageListThreshold: number, 8 | enableReduxLogging: boolean, 9 | enableErrorConsoleLogging: boolean, 10 | appOwnDomains: $ReadOnlyArray, 11 | |}; 12 | 13 | const config: Config = { 14 | // A completely unreasonable amount of time for a request, or 15 | // several retries of a request, to take. If this elapses, we're 16 | // better off giving up. 17 | requestLongTimeoutMs: 60 * 1000, 18 | 19 | messagesPerRequest: 100, 20 | messageListThreshold: 4000, 21 | enableReduxLogging: isDevelopment && !!global.btoa, 22 | enableErrorConsoleLogging: true, 23 | appOwnDomains: ['zulip.com', 'zulipchat.com', 'chat.zulip.org'], 24 | }; 25 | 26 | export default config; 27 | -------------------------------------------------------------------------------- /src/api/notifications/savePushToken.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { Auth } from '../transportTypes'; 3 | import { apiPost } from '../apiFetch'; 4 | 5 | /** 6 | * Tell the server our device token for push notifications. 7 | * 8 | * @param mobileOS - Choose the server-side API intended for iOS or Android clients. 9 | */ 10 | export default async (auth: Auth, mobileOS: 'ios' | 'android', token: string): Promise => { 11 | const routeName = mobileOS === 'android' ? 'android_gcm_reg_id' : 'apns_device_token'; 12 | const extraParams = 13 | // The `Object.freeze` is to work around a Flow issue: 14 | // https://github.com/facebook/flow/issues/2386#issuecomment-695064325 15 | mobileOS === 'android' ? Object.freeze({}) : { appid: 'org.zulip.Zulip' }; 16 | return apiPost(auth, `users/me/${routeName}`, { 17 | token, 18 | ...extraParams, 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /types/@react-navigation/routers/lib/typescript/src/index.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import * as CommonActions from './CommonActions'; 5 | export { CommonActions }; 6 | export { default as BaseRouter } from './BaseRouter'; 7 | export { default as StackRouter, StackActions } from './StackRouter'; 8 | export { 9 | StackActionHelpers, 10 | StackActionType, 11 | StackRouterOptions, 12 | StackNavigationState, 13 | } from './StackRouter'; 14 | export { default as TabRouter, TabActions } from './TabRouter'; 15 | export { TabActionHelpers, TabActionType, TabRouterOptions, TabNavigationState } from './TabRouter'; 16 | export { default as DrawerRouter, DrawerActions } from './DrawerRouter'; 17 | export { 18 | DrawerActionHelpers, 19 | DrawerActionType, 20 | DrawerRouterOptions, 21 | DrawerNavigationState, 22 | } from './DrawerRouter'; 23 | export * from './types'; 24 | -------------------------------------------------------------------------------- /docs/howto/forked-rn.md: -------------------------------------------------------------------------------- 1 | # Using a `react-native` with cherry-picked or custom changes 2 | 3 | Since 2024-09, we use a fork of `react-native` to make changes 4 | atop 0.68.7. We prefer to avoid upgrading to later `react-native` 5 | releases because it's laborious and we're eager to retire this 6 | codebase and transition to `zulip-flutter`. 7 | 8 | When there's an issue in React Native that calls for changes in 9 | React Native: 10 | 11 | - Push those changes to our RN fork, `zulip/react-native`, 12 | on the `0.68.7-zulip` branch. 13 | 14 | - Update the `package.json`: 15 | 16 | ```json 17 | "react-native": "zulip/react-native#", 18 | ``` 19 | 20 | - Run `yarn`. 21 | 22 | When building for Android, it will take longer the first time because 23 | React Native is built from source. (`react-native` releases on NPM, 24 | which we've been using until recently, come with a pre-built binary.) 25 | -------------------------------------------------------------------------------- /src/autocomplete/getAutocompletedText.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { InputSelection } from '../types'; 3 | 4 | export default (textWhole: string, autocompleteText: string, selection: InputSelection): string => { 5 | const { start, end } = selection; 6 | let remainder = ''; 7 | let text = textWhole; 8 | if (start === end && start !== text.length) { 9 | // new letter is typed 10 | remainder = text.substring(start, text.length); 11 | text = text.substring(0, start); 12 | } 13 | 14 | const lastIndex: number = Math.max( 15 | text.lastIndexOf(':'), 16 | text.lastIndexOf('#'), 17 | text.lastIndexOf('@'), 18 | ); 19 | 20 | const prefix = text[lastIndex] === ':' ? ':' : `${text[lastIndex]}`; 21 | const suffix = text[lastIndex] === ':' ? ':' : ''; 22 | 23 | return `${text.substring(0, lastIndex)}${prefix}${autocompleteText}${suffix} ${remainder}`; 24 | }; 25 | -------------------------------------------------------------------------------- /src/user-picker/AvatarList.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React from 'react'; 3 | import type { Node } from 'react'; 4 | import { FlatList } from 'react-native'; 5 | 6 | import type { UserId, UserOrBot } from '../types'; 7 | import AvatarItem from './AvatarItem'; 8 | 9 | type Props = $ReadOnly<{| 10 | users: $ReadOnlyArray, 11 | listRef: React$Ref, 12 | onPress: UserId => void, 13 | |}>; 14 | 15 | export default function AvatarList(props: Props): Node { 16 | const { listRef, users, onPress } = props; 17 | 18 | return ( 19 | String(user.user_id)} 26 | renderItem={({ item: user }) => } 27 | /> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /types/@react-navigation/native/lib/typescript/src/useLinkProps.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { MouseEvent as $tsflower_subst$React$MouseEvent } from 'tsflower/subst/react'; 5 | import type { GestureResponderEvent as $tsflower_subst$RN$GestureResponderEvent } from 'tsflower/subst/react-native'; 6 | import * as React from 'react'; 7 | import 'react-native'; 8 | import { type NavigationAction } from '@react-navigation/core'; 9 | 10 | type Props = { 11 | to: string, 12 | action?: NavigationAction, 13 | ... 14 | }; 15 | 16 | declare export default function useLinkProps(Props): { 17 | href: string, 18 | accessibilityRole: 'link', 19 | onPress: ( 20 | e?: 21 | | $tsflower_subst$React$MouseEvent 22 | | $tsflower_subst$RN$GestureResponderEvent 23 | | void, 24 | ) => void, 25 | ... 26 | }; 27 | 28 | export {}; 29 | -------------------------------------------------------------------------------- /src/common/SectionHeader.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import React, { useContext } from 'react'; 3 | import type { Node } from 'react'; 4 | import { View } from 'react-native'; 5 | 6 | import { ThemeContext, createStyleSheet } from '../styles'; 7 | import ZulipTextIntl from './ZulipTextIntl'; 8 | import type { LocalizableReactText } from '../types'; 9 | 10 | const styles = createStyleSheet({ 11 | header: { 12 | padding: 10, 13 | backgroundColor: 'hsla(0, 0%, 50%, 0.75)', 14 | }, 15 | }); 16 | 17 | type Props = $ReadOnly<{| 18 | text: LocalizableReactText, 19 | |}>; 20 | 21 | export default function SectionHeader(props: Props): Node { 22 | const { text } = props; 23 | const themeData = useContext(ThemeContext); 24 | 25 | return ( 26 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/react-native-action-sheet.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { ComponentType, ElementConfig } from 'react'; 3 | // $FlowFixMe[untyped-import] 4 | import { connectActionSheet as connectActionSheetInner } from '@expo/react-native-action-sheet'; 5 | 6 | import type { BoundedDiff } from './generics'; 7 | 8 | export type ShowActionSheetWithOptions = ( 9 | { options: string[], cancelButtonIndex: number, ... }, 10 | (number) => void, 11 | ) => void; 12 | 13 | /** 14 | * Exactly like the `connectActionSheet` in 15 | * `react-native-action-sheet` upstream, but more typed. 16 | */ 17 | export function connectActionSheet>( 18 | WrappedComponent: C, 19 | ): ComponentType< 20 | BoundedDiff< 21 | $Exact>, 22 | {| +showActionSheetWithOptions: ShowActionSheetWithOptions |}, 23 | >, 24 | > { 25 | return connectActionSheetInner(WrappedComponent); 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/keyMirror.js: -------------------------------------------------------------------------------- 1 | // @flow strict-local 2 | 3 | import { objectFromEntries } from '../jsBackport'; 4 | 5 | /** 6 | * Return an object where each property value equals the key. 7 | * 8 | * This is a handy idiom for making objects that function like enums. 9 | * For an example, see: 10 | * https://flow.org/en/docs/enums/migrating-legacy-patterns/#toc-keymirror 11 | * 12 | * The main reason to use this helper rather than just write out the result 13 | * directly is that it lets Flow infer a more specific type. For example: 14 | * 15 | * const Status1 = keyMirror({ on: null, off: null }); 16 | * Status1.on; // type is 'on' 17 | * 18 | * const Status2 = { on: 'on', off: 'off' }; 19 | * Status2.on; // type is string, which is less helpful 20 | */ 21 | export function keyMirror(o: O): $ObjMapi(K) => K> { 22 | return objectFromEntries(Object.keys(o).map(k => [k, k])); 23 | } 24 | -------------------------------------------------------------------------------- /types/@react-navigation/core/lib/typescript/src/getActionFromState.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import { type NavigationState, type PartialState } from '@react-navigation/routers'; 5 | import * as CommonActions from '@react-navigation/routers/lib/typescript/src/CommonActions'; 6 | import { type PathConfigMap, type NavigatorScreenParams } from './types'; 7 | 8 | type Options = { 9 | initialRouteName?: string, 10 | screens: PathConfigMap, 11 | ... 12 | }; 13 | 14 | type NavigateAction> = { 15 | type: 'NAVIGATE', 16 | payload: { 17 | name: string, 18 | params?: NavigatorScreenParams, 19 | ... 20 | }, 21 | ... 22 | }; 23 | 24 | declare export default function getActionFromState( 25 | state: PartialState>, 26 | options?: Options, 27 | ): NavigateAction> | CommonActions.Action | void; 28 | export {}; 29 | -------------------------------------------------------------------------------- /src/title/ActivityText.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | 3 | import React from 'react'; 4 | import type { Node } from 'react'; 5 | import type { TextStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet'; 6 | 7 | import type { UserOrBot } from '../types'; 8 | import { useSelector } from '../react-redux'; 9 | import { getUserLastActiveAsRelativeTimeString } from '../presence/presenceModel'; 10 | import ZulipText from '../common/ZulipText'; 11 | 12 | type Props = $ReadOnly<{| 13 | style: TextStyleProp, 14 | user: UserOrBot, 15 | |}>; 16 | 17 | export default function ActivityText(props: Props): Node { 18 | const { style, user } = props; 19 | 20 | const activeTime = useSelector(state => 21 | getUserLastActiveAsRelativeTimeString(state, user, Date.now()), 22 | ); 23 | if (activeTime == null) { 24 | return null; 25 | } 26 | 27 | return ; 28 | } 29 | -------------------------------------------------------------------------------- /ios/ZulipMobile-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // To use an Objective-C module in a Swift file, first just try importing it 2 | // at the top of your Swift file, like so: 3 | // 4 | // import React.RCTBridgeModule 5 | // 6 | // If you can't find an import line that Xcode understands, instead try 7 | // adding an import line in this file, like so: 8 | // 9 | // #import 10 | // 11 | // That should make the module (plus the modules *it* imports, actually) 12 | // available in all our project's Swift files, without the Swift files 13 | // needing an import line of their own. 14 | // 15 | // The first approach (an import line in the Swift file) is preferred 16 | // because it looks like how imports normally work in Swift. But sometimes 17 | // we can't find an import line that works; not sure why. Discussion: 18 | // https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/ios.2FZulipMobile-Bridging-Header.2Eh/near/1520435 19 | -------------------------------------------------------------------------------- /react-native.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * See https://github.com/react-native-community/cli/blob/master/docs/configuration.md. 3 | * 4 | * To print the full config from the React Native CLI, run 5 | * `react-native config`. 6 | */ 7 | module.exports = { 8 | /** 9 | * See https://github.com/react-native-community/cli/blob/master/docs/dependencies.md. 10 | * 11 | * Currently, we only use this to blacklist some native-code 12 | * libraries, per-platform, that we don't want to be linked with 13 | * "autolinking". 14 | * 15 | * For more about "autolinking", see 16 | * https://github.com/react-native-community/cli/blob/master/docs/autolinking.md. 17 | */ 18 | dependencies: { 19 | 'react-native-vector-icons': { 20 | platforms: { 21 | // We're using a setup that doesn't involve linking 22 | // `VectorIconsPackage` on Android. 23 | android: null, 24 | }, 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/webview/html/messageTypingAsHtml.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import { PixelRatio } from 'react-native'; 3 | 4 | import template from './template'; 5 | import type { UserOrBot } from '../../types'; 6 | 7 | const typingAvatar = (realm: URL, user: UserOrBot): string => template` 8 |
9 | 19 |
20 | `; 21 | 22 | export default (realm: URL, users: $ReadOnlyArray): string => template` 23 | $!${users.map(user => typingAvatar(realm, user)).join('')} 24 |
25 | 26 | 27 | 28 |
29 | `; 30 | -------------------------------------------------------------------------------- /types/@react-native-clipboard/clipboard/dist/Clipboard.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { EmitterSubscription as $tsflower_subst$RN$EmitterSubscription } from 'tsflower/subst/react-native'; 5 | import 'react-native'; 6 | 7 | declare export var Clipboard: { 8 | getString(): Promise, 9 | getStrings(): Promise, 10 | getImagePNG(): Promise, 11 | getImageJPG(): Promise, 12 | setImage(content: string): void, 13 | getImage(): Promise, 14 | setString(content: string): void, 15 | setStrings(content: string[]): void, 16 | hasString(): Promise, 17 | hasImage(): Promise, 18 | hasURL(): Promise | void, 19 | hasNumber(): Promise | void, 20 | hasWebURL(): Promise | void, 21 | addListener(callback: () => void): $tsflower_subst$RN$EmitterSubscription, 22 | removeAllListeners(): void, 23 | ... 24 | }; 25 | -------------------------------------------------------------------------------- /src/webview/html/messageListElementHtml.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | import type { GetText, MessageListElement } from '../../types'; 3 | import { ensureUnreachable } from '../../generics'; 4 | import type { BackgroundData } from '../backgroundData'; 5 | 6 | import message from './message'; 7 | import header from './header'; 8 | import time from './time'; 9 | 10 | export default ({ 11 | backgroundData, 12 | element, 13 | _, 14 | }: {| 15 | backgroundData: BackgroundData, 16 | element: MessageListElement, 17 | _: GetText, 18 | |}): string => { 19 | switch (element.type) { 20 | case 'time': 21 | return time(element); 22 | case 'header': 23 | return header(backgroundData, element, _); 24 | case 'message': 25 | return message(backgroundData, element, _); 26 | default: 27 | ensureUnreachable(element); 28 | throw new Error(`Unidentified element.type: '${element.type}'`); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /types/react-native-safe-area-context/lib/typescript/src/SafeAreaView.js.flow: -------------------------------------------------------------------------------- 1 | /* @flow 2 | * @generated by TsFlower 3 | */ 4 | import type { NativeMethods } from 'react-native/Libraries/Renderer/shims/ReactNativeTypes'; 5 | 6 | import type { 7 | ForwardRefExoticComponent as $tsflower_subst$React$ForwardRefExoticComponent, 8 | RefAttributes as $tsflower_subst$React$RefAttributes, 9 | } from 'tsflower/subst/react'; 10 | 11 | import type { Readonly } from 'tsflower/subst/lib'; 12 | import * as React from 'react'; 13 | import { type NativeSafeAreaViewProps } from './SafeArea.types'; 14 | import { type NativeProps } from './specs/NativeSafeAreaView'; 15 | 16 | export type SafeAreaViewProps = NativeSafeAreaViewProps; 17 | declare export var SafeAreaView: $tsflower_subst$React$ForwardRefExoticComponent< 18 | NativeSafeAreaViewProps & 19 | $tsflower_subst$React$RefAttributes & Readonly>, 20 | >; 21 | -------------------------------------------------------------------------------- /src/styles/constants.js: -------------------------------------------------------------------------------- 1 | /* @flow strict-local */ 2 | // $FlowFixMe[untyped-import] 3 | import Color from 'color'; 4 | 5 | export const CONTROL_SIZE = 44; 6 | export const NAVBAR_SIZE = 58; 7 | 8 | // The value `hsl(222, 99%, 69%)` is chosen to match `rgb(100, 146, 253.5)`, 9 | // which is the sRGB midpoint of the Zulip logo's gradient. 10 | // 11 | // Note this color is also used directly in several other places: 12 | // * in our WebView's CSS; 13 | // * under `android/` (search for "BRAND_COLOR"); 14 | // * in `ios/**/Brand.colorset/Contents.json`. 15 | export const BRAND_COLOR = 'hsl(222, 99%, 69%)'; 16 | export const BORDER_COLOR = BRAND_COLOR; 17 | export const HIGHLIGHT_COLOR: string = Color(BRAND_COLOR).fade(0.5).toString(); 18 | 19 | export const HALF_COLOR = 'hsla(0, 0%, 50%, 0.5)'; 20 | export const QUARTER_COLOR = 'hsla(0, 0%, 50%, 0.25)'; 21 | 22 | // Material warning color 23 | export const kWarningColor = 'hsl(40, 100%, 60%)'; 24 | --------------------------------------------------------------------------------