diff --git a/examples/SampleApp/ios/SampleApp.xcodeproj/project.pbxproj b/examples/SampleApp/ios/SampleApp.xcodeproj/project.pbxproj
index 51996b9be4..ab2d68ba57 100644
--- a/examples/SampleApp/ios/SampleApp.xcodeproj/project.pbxproj
+++ b/examples/SampleApp/ios/SampleApp.xcodeproj/project.pbxproj
@@ -284,10 +284,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp/Pods-SampleApp-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp/Pods-SampleApp-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SampleApp/Pods-SampleApp-frameworks.sh\"\n";
@@ -302,6 +306,8 @@
"$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = "[CP-User] [RNFB] Core Configuration";
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n";
@@ -336,10 +342,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp/Pods-SampleApp-resources-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp/Pods-SampleApp-resources-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SampleApp/Pods-SampleApp-resources.sh\"\n";
@@ -353,10 +363,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp-SampleAppTests/Pods-SampleApp-SampleAppTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp-SampleAppTests/Pods-SampleApp-SampleAppTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SampleApp-SampleAppTests/Pods-SampleApp-SampleAppTests-resources.sh\"\n";
@@ -370,10 +384,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp-SampleAppTests/Pods-SampleApp-SampleAppTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SampleApp-SampleAppTests/Pods-SampleApp-SampleAppTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SampleApp-SampleAppTests/Pods-SampleApp-SampleAppTests-frameworks.sh\"\n";
@@ -532,8 +550,8 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = SampleApp/SampleAppRelease.entitlements;
- CODE_SIGN_IDENTITY = "iPhone Distribution";
- CODE_SIGN_STYLE = Manual;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 926;
DEVELOPMENT_TEAM = EHV7XZLAHA;
INFOPLIST_FILE = SampleApp/Info.plist;
@@ -548,7 +566,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = io.getstream.reactnative.SampleApp;
PRODUCT_NAME = SampleApp;
- PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.reactnative.SampleApp";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -688,10 +706,7 @@
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
- OTHER_LDFLAGS = (
- "$(inherited)",
- " ",
- );
+ OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
@@ -823,10 +838,7 @@
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
- OTHER_LDFLAGS = (
- "$(inherited)",
- " ",
- );
+ OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
diff --git a/examples/SampleApp/src/components/AttachmentPickerContent.tsx b/examples/SampleApp/src/components/AttachmentPickerContent.tsx
new file mode 100644
index 0000000000..a7a56e13ef
--- /dev/null
+++ b/examples/SampleApp/src/components/AttachmentPickerContent.tsx
@@ -0,0 +1,53 @@
+import React, { useCallback, useState } from 'react';
+import {
+ useAttachmentPickerState,
+ AttachmentPickerContentProps,
+ AttachmentPickerContent,
+ AttachmentPickerGenericContent,
+ useStableCallback,
+ useTheme,
+ useTranslationContext,
+} from 'stream-chat-react-native';
+import { ShareLocationIcon } from '../icons/ShareLocationIcon.tsx';
+import { LiveLocationCreateModal } from './LocationSharing/CreateLocationModal.tsx';
+
+export const CustomAttachmentPickerContent = (props: AttachmentPickerContentProps) => {
+ const [modalVisible, setModalVisible] = useState(false);
+ const { selectedPicker } = useAttachmentPickerState();
+ const { t } = useTranslationContext();
+ const {
+ theme: { semantics },
+ } = useTheme();
+
+ const Icon = useCallback(
+ () => ,
+ [semantics.textTertiary],
+ );
+
+ const onRequestClose = () => {
+ setModalVisible(false);
+ };
+
+ const onOpenModal = useStableCallback(() => {
+ setModalVisible(true);
+ });
+
+ if (selectedPicker === 'location') {
+ return (
+ <>
+
+ {modalVisible ? (
+
+ ) : null}
+ >
+ );
+ }
+
+ return ;
+};
diff --git a/examples/SampleApp/src/components/AttachmentPickerSelectionBar.tsx b/examples/SampleApp/src/components/AttachmentPickerSelectionBar.tsx
index 0b858bcb1c..9cc2b3f3d6 100644
--- a/examples/SampleApp/src/components/AttachmentPickerSelectionBar.tsx
+++ b/examples/SampleApp/src/components/AttachmentPickerSelectionBar.tsx
@@ -1,36 +1,52 @@
-import { useState } from 'react';
-import { Pressable, StyleSheet, View } from 'react-native';
-import { AttachmentPickerSelectionBar, useMessageInputContext } from 'stream-chat-react-native';
+import React, { useState } from 'react';
+import { StyleSheet, View } from 'react-native';
+import {
+ AttachmentTypePickerButton,
+ useAttachmentPickerState,
+ CameraPickerButton,
+ CommandsPickerButton,
+ FilePickerButton,
+ MediaPickerButton,
+ PollPickerButton,
+ useAttachmentPickerContext,
+ useStableCallback,
+} from 'stream-chat-react-native';
import { ShareLocationIcon } from '../icons/ShareLocationIcon';
import { LiveLocationCreateModal } from './LocationSharing/CreateLocationModal';
export const CustomAttachmentPickerSelectionBar = () => {
const [modalVisible, setModalVisible] = useState(false);
- const { closeAttachmentPicker } = useMessageInputContext();
+ const { attachmentPickerStore } = useAttachmentPickerContext();
+ const { selectedPicker } = useAttachmentPickerState();
const onRequestClose = () => {
setModalVisible(false);
- closeAttachmentPicker();
};
- const onOpenModal = () => {
+ const onOpenModal = useStableCallback(() => {
+ attachmentPickerStore.setSelectedPicker('location');
setModalVisible(true);
- };
+ });
return (
-
-
-
-
-
+
+
+
+
+
+
+ {modalVisible ? (
+
+ ) : null}
);
};
const styles = StyleSheet.create({
- selectionBar: { flexDirection: 'row', alignItems: 'center' },
- liveLocationButton: {
- paddingLeft: 4,
- },
+ selectionBar: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingBottom: 12, },
});
diff --git a/examples/SampleApp/src/icons/ShareLocationIcon.tsx b/examples/SampleApp/src/icons/ShareLocationIcon.tsx
index 79c1e13584..2680f19261 100644
--- a/examples/SampleApp/src/icons/ShareLocationIcon.tsx
+++ b/examples/SampleApp/src/icons/ShareLocationIcon.tsx
@@ -1,24 +1,19 @@
import Svg, { Path } from 'react-native-svg';
-import { useTheme } from 'stream-chat-react-native';
+import { ColorValue } from 'react-native';
// Icon for "Share Location" button, next to input box.
-export const ShareLocationIcon = () => {
- const {
- theme: {
- colors: { grey },
- },
- } = useTheme();
+export const ShareLocationIcon = ({ stroke }: { stroke: ColorValue }) => {
return (
-
);
diff --git a/package/src/icons/CommandsIcon.tsx b/package/src/icons/CommandsIcon.tsx
new file mode 100644
index 0000000000..3d507072b1
--- /dev/null
+++ b/package/src/icons/CommandsIcon.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
+
+export const CommandsIcon = (props: IconProps) => (
+
+
+
+);
diff --git a/package/src/icons/FilePickerIcon.tsx b/package/src/icons/FilePickerIcon.tsx
new file mode 100644
index 0000000000..06055c879d
--- /dev/null
+++ b/package/src/icons/FilePickerIcon.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
+
+export const FilePickerIcon = (props: IconProps) => (
+
+
+
+);
diff --git a/package/src/icons/Flag.tsx b/package/src/icons/Flag.tsx
index 45f5f3378b..505631add3 100644
--- a/package/src/icons/Flag.tsx
+++ b/package/src/icons/Flag.tsx
@@ -1,12 +1,17 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const Flag = (props: IconProps) => (
-
-
+
-
+
);
diff --git a/package/src/icons/GiphyIcon.tsx b/package/src/icons/GiphyIcon.tsx
index be574f3a77..c28f6875e7 100644
--- a/package/src/icons/GiphyIcon.tsx
+++ b/package/src/icons/GiphyIcon.tsx
@@ -1,18 +1,23 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const GiphyIcon = (props: IconProps) => (
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
diff --git a/package/src/icons/Imgur.tsx b/package/src/icons/Imgur.tsx
index dc708c9b16..55532374ad 100644
--- a/package/src/icons/Imgur.tsx
+++ b/package/src/icons/Imgur.tsx
@@ -1,26 +1,18 @@
import React from 'react';
-import { Circle } from 'react-native-svg';
+import Svg, { Path, Rect } from 'react-native-svg';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import { IconProps } from './utils/base';
export const Imgur = (props: IconProps) => (
-
-
+
+
-
-
-
+
);
diff --git a/package/src/icons/Mute.tsx b/package/src/icons/Mute.tsx
index 9aae840baf..f25292bacb 100644
--- a/package/src/icons/Mute.tsx
+++ b/package/src/icons/Mute.tsx
@@ -1,12 +1,23 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Mask, Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const Mute = (props: IconProps) => (
-
-
+
+
+
+
+
-
+
);
diff --git a/package/src/icons/Picture.tsx b/package/src/icons/Picture.tsx
index 7f2ad55e1b..a00e23b6e1 100644
--- a/package/src/icons/Picture.tsx
+++ b/package/src/icons/Picture.tsx
@@ -1,16 +1,22 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
-export const Picture = (props: IconProps) => (
-
-
-
-
-);
+import { IconProps } from './utils/base';
+
+// TODO V9: This SVG relies on path fill instead of stroke. We need to refactor how
+// SVGs are resolved before we remove the hack of applying the pathFill
+// directly.
+export const Picture = (props: IconProps) => {
+ const { stroke, ...rest } = props;
+ return (
+
+
+
+ );
+};
diff --git a/package/src/icons/PollThumbnail.tsx b/package/src/icons/PollThumbnail.tsx
index 1eec10add2..47765a735c 100644
--- a/package/src/icons/PollThumbnail.tsx
+++ b/package/src/icons/PollThumbnail.tsx
@@ -1,12 +1,14 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const PollThumbnail = (props: IconProps) => (
-
-
+
-
+
);
diff --git a/package/src/icons/Recorder.tsx b/package/src/icons/Recorder.tsx
index 10e57efc60..d051dc2295 100644
--- a/package/src/icons/Recorder.tsx
+++ b/package/src/icons/Recorder.tsx
@@ -3,9 +3,9 @@ import React from 'react';
import { IconProps, RootPath, RootSvg } from './utils/base';
export const Recorder = ({ ...rest }: IconProps) => (
-
+
diff --git a/package/src/icons/Sound.tsx b/package/src/icons/Sound.tsx
index 330a0af159..22741f62fe 100644
--- a/package/src/icons/Sound.tsx
+++ b/package/src/icons/Sound.tsx
@@ -1,12 +1,17 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const Sound = (props: IconProps) => (
-
-
+
-
+
);
diff --git a/package/src/icons/UserAdd.tsx b/package/src/icons/UserAdd.tsx
index 6c1aa2f268..a8441421af 100644
--- a/package/src/icons/UserAdd.tsx
+++ b/package/src/icons/UserAdd.tsx
@@ -1,13 +1,17 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const UserAdd = (props: IconProps) => (
-
-
-
+
-
+
);
diff --git a/package/src/icons/UserDelete.tsx b/package/src/icons/UserDelete.tsx
index d7f97cff03..192f0f56d6 100644
--- a/package/src/icons/UserDelete.tsx
+++ b/package/src/icons/UserDelete.tsx
@@ -1,13 +1,17 @@
import React from 'react';
-import { IconProps, RootPath, RootSvg } from './utils/base';
+import Svg, { Path } from 'react-native-svg';
+
+import { IconProps } from './utils/base';
export const UserDelete = (props: IconProps) => (
-
-
-
+
-
+
);
diff --git a/package/src/icons/index.ts b/package/src/icons/index.ts
index 9e17a0568a..d48ca39796 100644
--- a/package/src/icons/index.ts
+++ b/package/src/icons/index.ts
@@ -102,3 +102,5 @@ export * from './DragHandle';
export * from './Back';
export * from './SendPoll';
export * from './UnreadIndicator';
+export * from './FilePickerIcon';
+export * from './CommandsIcon';
diff --git a/package/src/state-store/attachment-picker-store.ts b/package/src/state-store/attachment-picker-store.ts
new file mode 100644
index 0000000000..7c88feda4d
--- /dev/null
+++ b/package/src/state-store/attachment-picker-store.ts
@@ -0,0 +1,33 @@
+import { StateStore } from 'stream-chat';
+
+export type SelectedPickerType =
+ | 'images'
+ | 'files'
+ | 'camera-photo'
+ | 'camera-video'
+ | 'polls'
+ | 'commands'
+ | string
+ | undefined;
+
+export type AttachmentPickerState = {
+ selectedPicker: SelectedPickerType;
+};
+
+const INITIAL_STATE: AttachmentPickerState = {
+ selectedPicker: undefined,
+};
+
+export class AttachmentPickerStore {
+ public state = new StateStore(INITIAL_STATE);
+ private lastChanged: number = -1;
+
+ setSelectedPicker(value: SelectedPickerType, debounceClose?: boolean) {
+ const now = Date.now();
+ if (debounceClose && !value && now - this.lastChanged < 500) {
+ return;
+ }
+ this.lastChanged = now;
+ this.state.partialNext({ selectedPicker: value });
+ }
+}
diff --git a/package/src/utils/utils.ts b/package/src/utils/utils.ts
index 5d54f00b65..4f8b8c26e5 100644
--- a/package/src/utils/utils.ts
+++ b/package/src/utils/utils.ts
@@ -225,7 +225,7 @@ export const getDurationLabelFromDuration = (duration: number) => {
const ONE_HOUR_IN_MILLISECONDS = ONE_HOUR_IN_SECONDS * 1000;
let durationLabel = '00:00';
const isDurationLongerThanHour = duration / ONE_HOUR_IN_MILLISECONDS >= 1;
- const formattedDurationParam = isDurationLongerThanHour ? 'HH:mm:ss' : 'mm:ss';
+ const formattedDurationParam = isDurationLongerThanHour ? 'HH:mm:ss' : 'm:ss';
const formattedVideoDuration = dayjs
.duration(duration, 'milliseconds')
.format(formattedDurationParam);
@@ -240,7 +240,7 @@ export const formatMsToMinSec = (ms: number) => {
const seconds = totalSeconds % 60;
const mm = minutes; // no padding for minutes
- const ss = String(seconds).padStart(2, '0');
+ const ss = minutes ? String(seconds).padStart(2, '0') : String(seconds);
return `${mm}m ${ss}s`.replace(/^0m\s/, '');
};