From d4f9eaa54e7f3995ffebc77c575578a273d28b56 Mon Sep 17 00:00:00 2001 From: Khushal Agarwal Date: Thu, 2 Jan 2025 16:13:07 +0530 Subject: [PATCH 1/4] feat: add support for video recording take and upload on iOS --- examples/ExpoMessaging/app.json | 3 +- examples/ExpoMessaging/package.json | 13 +- examples/ExpoMessaging/yarn.lock | 390 ++++++++++-------- .../src/optionalDependencies/takePhoto.ts | 19 +- .../src/optionalDependencies/takePhoto.ts | 32 +- .../MessageInputContext.tsx | 6 +- 6 files changed, 276 insertions(+), 187 deletions(-) diff --git a/examples/ExpoMessaging/app.json b/examples/ExpoMessaging/app.json index 32df3d0ad3..4e9029e1df 100644 --- a/examples/ExpoMessaging/app.json +++ b/examples/ExpoMessaging/app.json @@ -39,7 +39,8 @@ "expo-image-picker", { "photosPermission": "The app accesses your photos to let them share with others.", - "cameraPermission": "The app accesses your camera to let you take photos and share with others." + "cameraPermission": "The app accesses your camera to let you take photos and share with others.", + "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone for video recording." } ], [ diff --git a/examples/ExpoMessaging/package.json b/examples/ExpoMessaging/package.json index 16cad3e85b..5ae99c43bc 100644 --- a/examples/ExpoMessaging/package.json +++ b/examples/ExpoMessaging/package.json @@ -13,27 +13,28 @@ "@op-engineering/op-sqlite": "^9.3.0", "@react-native-community/netinfo": "11.4.1", "@react-navigation/elements": "^1.3.30", - "expo": "^52.0.0", + "expo": "~52.0.20", "expo-av": "~15.0.1", "expo-clipboard": "~7.0.0", "expo-constants": "~17.0.3", "expo-document-picker": "~13.0.1", - "expo-file-system": "~18.0.4", + "expo-file-system": "~18.0.6", "expo-haptics": "~14.0.0", "expo-image-manipulator": "~13.0.5", "expo-image-picker": "^16.0.3", "expo-linking": "~7.0.3", - "expo-router": "~4.0.11", + "expo-media-library": "~17.0.4", + "expo-router": "~4.0.15", "expo-sharing": "~13.0.0", - "expo-splash-screen": "~0.29.13", + "expo-splash-screen": "~0.29.18", "expo-status-bar": "~2.0.0", "react": "18.3.1", "react-dom": "18.3.1", - "react-native": "0.76.3", + "react-native": "0.76.5", "react-native-gesture-handler": "~2.20.2", "react-native-reanimated": "~3.16.1", "react-native-safe-area-context": "4.12.0", - "react-native-screens": "~4.1.0", + "react-native-screens": "~4.4.0", "react-native-svg": "15.8.0", "react-native-web": "~0.19.13", "stream-chat-expo": "link:../../package/expo-package", diff --git a/examples/ExpoMessaging/yarn.lock b/examples/ExpoMessaging/yarn.lock index 9c73512b79..d930ece301 100644 --- a/examples/ExpoMessaging/yarn.lock +++ b/examples/ExpoMessaging/yarn.lock @@ -1540,10 +1540,10 @@ mv "~2" safe-json-stringify "~1" -"@expo/cli@0.22.1": - version "0.22.1" - resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.22.1.tgz#57144215073d2da10e783c3b8a24c34c4405894b" - integrity sha512-tpkFzlTYb/sNh8WqeTCa2ZVKMDkPgMggvY3tZeTfxeAO5olVXddKV+0U5zhHSd7pGM2w2fhEJNKI4Ub7IfyDmA== +"@expo/cli@0.22.7": + version "0.22.7" + resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.22.7.tgz#c6501e6ff5162eacba9d027c0e09c91b8db32cee" + integrity sha512-aNrUPVFPdIX42Q6UM6qygrN4DUqnXMDS1CnkTfNFVIZWRiJ1TUA05Zk6aF35M674CKd/c/dWHFjmbgjsyN/hEA== dependencies: "@0no-co/graphql.web" "^1.0.8" "@babel/runtime" "^7.20.0" @@ -1554,15 +1554,15 @@ "@expo/env" "~0.4.0" "@expo/image-utils" "^0.6.0" "@expo/json-file" "^9.0.0" - "@expo/metro-config" "~0.19.0" + "@expo/metro-config" "~0.19.8" "@expo/osascript" "^2.0.31" "@expo/package-manager" "^1.5.0" "@expo/plist" "^0.2.0" - "@expo/prebuild-config" "^8.0.17" + "@expo/prebuild-config" "^8.0.23" "@expo/rudder-sdk-node" "^1.1.1" "@expo/spawn-async" "^1.7.2" "@expo/xcpretty" "^4.3.0" - "@react-native/dev-middleware" "0.76.3" + "@react-native/dev-middleware" "0.76.5" "@urql/core" "^5.0.6" "@urql/exchange-retry" "^1.3.0" accepts "^1.3.8" @@ -1625,7 +1625,7 @@ node-forge "^1.2.1" nullthrows "^1.1.1" -"@expo/config-plugins@~9.0.10", "@expo/config-plugins@~9.0.11": +"@expo/config-plugins@~9.0.10": version "9.0.11" resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-9.0.11.tgz#7aec3663a783706ded3b6c7f3859221e17c9122a" integrity sha512-zufuPQWkeEpXfMWFx2lWStoN43p6cO13p8n2KMIEK6jJMC/kkfldYyl8gYtEEYAL1nFfOf/W2pIXXPQ2sggnSw== @@ -1645,6 +1645,26 @@ xcode "^3.0.1" xml2js "0.6.0" +"@expo/config-plugins@~9.0.12": + version "9.0.12" + resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-9.0.12.tgz#f122b2dca22e135eadf6e73442da3ced0ce8aa0a" + integrity sha512-/Ko/NM+GzvJyRkq8PITm8ms0KY5v0wmN1OQFYRMkcJqOi3PjlhndW+G6bHpJI9mkQXBaUnHwAiGLqIC3+MQ5Wg== + dependencies: + "@expo/config-types" "^52.0.0" + "@expo/json-file" "~9.0.0" + "@expo/plist" "^0.2.0" + "@expo/sdk-runtime-versions" "^1.0.0" + chalk "^4.1.2" + debug "^4.3.5" + getenv "^1.0.0" + glob "^10.4.2" + resolve-from "^5.0.0" + semver "^7.5.4" + slash "^3.0.0" + slugify "^1.6.6" + xcode "^3.0.1" + xml2js "0.6.0" + "@expo/config-types@^52.0.0": version "52.0.1" resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-52.0.1.tgz#327af1b72a3a9d4556f41e083e0e284dd8198b96" @@ -1698,10 +1718,10 @@ dotenv-expand "~11.0.6" getenv "^1.0.0" -"@expo/fingerprint@0.11.3": - version "0.11.3" - resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.11.3.tgz#e370ae8f83e0642f752b058e2102e984a0a5bc98" - integrity sha512-9lgXmcIePvZ7Wef63XtvuN3HfCUevF4E4tQPdEbH9/dUWwpOvvwQ3KT4OJ9jdh8JJ3nTdO9eDQ/8k8xr1aQ5Kg== +"@expo/fingerprint@0.11.6": + version "0.11.6" + resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.11.6.tgz#7e01d436c1610c7dc1fc6898b2d90adaa19a39a0" + integrity sha512-hlVIfMEJYZIqIFMjeGRN5GhK/h6vJ3M4QVc1ZD8F0Bh7gMeI+jZkEyZdL5XT29jergQrksP638e2qFwgrGTw/w== dependencies: "@expo/spawn-async" "^1.7.2" arg "^5.0.2" @@ -1748,10 +1768,10 @@ json5 "^2.2.3" write-file-atomic "^2.3.0" -"@expo/metro-config@0.19.5", "@expo/metro-config@~0.19.0": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.19.5.tgz#121817ac85cfc055686daafb8c85afb4f5d6a2d0" - integrity sha512-wl5lVgXq4FN4kBJHNyU5U9J5hH8S8rYXrp/pgbwA+J/smQfiElYKMYomTGbHUb4LQ0VnmlX6/kI4x/zJk+mq7w== +"@expo/metro-config@0.19.8", "@expo/metro-config@~0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.19.8.tgz#f1ea552b6fa5217093fe364ff5ca78a7e261a28b" + integrity sha512-dVAOetouQYuOTEJ2zR0OTLNPOH6zPkeEt5fY53TK0Wxi1QmtsmH6vEWg05U4zkSJ6f1aXmQ0Za77R8QxuukESA== dependencies: "@babel/core" "^7.20.0" "@babel/generator" "^7.20.5" @@ -1812,17 +1832,17 @@ base64-js "^1.2.3" xmlbuilder "^14.0.0" -"@expo/prebuild-config@^8.0.17": - version "8.0.21" - resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-8.0.21.tgz#cd91fcd8d58af94885666284f4872bd51a279852" - integrity sha512-PVvt7+2dLzmf1X4HaoibnTtfoxnor0YEdu396eLv1SG+KacmN5lMz81yO/2MXvv0SDA6THomgBNvA/uzWV5twA== +"@expo/prebuild-config@^8.0.23": + version "8.0.23" + resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-8.0.23.tgz#2ec6d5464f35d308bdb94ba75b7e6aba0ebb507d" + integrity sha512-Zf01kFiN2PISmLb0DhIAJh76v3J2oYUKSjiAtGZLOH0HUz59by/qdyU4mGHWdeyRdCCrLUA21Rct2MBykvRMsg== dependencies: "@expo/config" "~10.0.4" "@expo/config-plugins" "~9.0.10" "@expo/config-types" "^52.0.0" "@expo/image-utils" "^0.6.0" "@expo/json-file" "^9.0.0" - "@react-native/normalize-colors" "0.76.3" + "@react-native/normalize-colors" "0.76.5" debug "^4.3.1" fs-extra "^9.0.0" resolve-from "^5.0.0" @@ -2128,22 +2148,22 @@ resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-11.4.1.tgz#a3c247aceab35f75dd0aa4bfa85d2be5a4508688" integrity sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg== -"@react-native/assets-registry@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.76.3.tgz#c31e91b6f60fed7b0bfc1af617e3a61218d1ec08" - integrity sha512-7Fnc3lzCFFpnoyL1egua6d/qUp0KiIpeSLbfOMln4nI2g2BMzyFHdPjJnpLV2NehmS0omOOkrfRqK5u1F/MXzA== +"@react-native/assets-registry@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.76.5.tgz#3343338813aa6354df9fec52af50d0b5f7f3d013" + integrity sha512-MN5dasWo37MirVcKWuysRkRr4BjNc81SXwUtJYstwbn8oEkfnwR9DaqdDTo/hHOnTdhafffLIa2xOOHcjDIGEw== -"@react-native/babel-plugin-codegen@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.76.3.tgz#331f1afb4fe744b135979f0d0db62b1cd07cb5bf" - integrity sha512-mZ7jmIIg4bUnxCqY3yTOkoHvvzsDyrZgfnIKiTGm5QACrsIGa5eT3pMFpMm2OpxGXRDrTMsYdPXE2rCyDX52VQ== +"@react-native/babel-plugin-codegen@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.76.5.tgz#a7c32274351e51db9c0a7849ce8059940448c087" + integrity sha512-xe7HSQGop4bnOLMaXt0aU+rIatMNEQbz242SDl8V9vx5oOTI0VbZV9yLy6yBc6poUlYbcboF20YVjoRsxX4yww== dependencies: - "@react-native/codegen" "0.76.3" + "@react-native/codegen" "0.76.5" -"@react-native/babel-preset@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/babel-preset/-/babel-preset-0.76.3.tgz#f1a839b0b2ced0399148ada5e1e152136109b940" - integrity sha512-zi2nPlQf9q2fmfPyzwWEj6DU96v8ziWtEfG7CTAX2PG/Vjfsr94vn/wWrCdhBVvLRQ6Kvd/MFAuDYpxmQwIiVQ== +"@react-native/babel-preset@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/babel-preset/-/babel-preset-0.76.5.tgz#794ca17e1107e46712153f296a4930de2048e20e" + integrity sha512-1Nu5Um4EogOdppBLI4pfupkteTjWfmI0hqW8ezWTg7Bezw0FtBj8yS8UYVd3wTnDFT9A5mA2VNoNUqomJnvj2A== dependencies: "@babel/core" "^7.25.2" "@babel/plugin-proposal-export-default-from" "^7.24.7" @@ -2186,15 +2206,15 @@ "@babel/plugin-transform-typescript" "^7.25.2" "@babel/plugin-transform-unicode-regex" "^7.24.7" "@babel/template" "^7.25.0" - "@react-native/babel-plugin-codegen" "0.76.3" + "@react-native/babel-plugin-codegen" "0.76.5" babel-plugin-syntax-hermes-parser "^0.25.1" babel-plugin-transform-flow-enums "^0.0.2" react-refresh "^0.14.0" -"@react-native/codegen@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.76.3.tgz#a94664601bb60797dd1042972bffdd1b2bfe008c" - integrity sha512-oJCH/jbYeGmFJql8/y76gqWCCd74pyug41yzYAjREso1Z7xL88JhDyKMvxEnfhSdMOZYVl479N80xFiXPy3ZYA== +"@react-native/codegen@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.76.5.tgz#4d89ec14a023d6946dbc44537c39b03bd006db7b" + integrity sha512-FoZ9VRQ5MpgtDAnVo1rT9nNRfjnWpE40o1GeJSDlpUMttd36bVXvsDm8W/NhX8BKTWXSX+CPQJsRcvN1UPYGKg== dependencies: "@babel/parser" "^7.25.3" glob "^7.1.1" @@ -2205,13 +2225,13 @@ nullthrows "^1.1.1" yargs "^17.6.2" -"@react-native/community-cli-plugin@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/community-cli-plugin/-/community-cli-plugin-0.76.3.tgz#64e1209959103c4ef60a5edb7d7db94329f35ed5" - integrity sha512-vgsLixHS24jR0d0QqPykBWFaC+V8x9cM3cs4oYXw3W199jgBNGP9MWcUJLazD2vzrT/lUTVBVg0rBeB+4XR6fg== +"@react-native/community-cli-plugin@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/community-cli-plugin/-/community-cli-plugin-0.76.5.tgz#e701a9f99565504a2510d1b54713b1c5dd0f1bb4" + integrity sha512-3MKMnlU0cZOWlMhz5UG6WqACJiWUrE3XwBEumzbMmZw3Iw3h+fIsn+7kLLE5EhzqLt0hg5Y4cgYFi4kOaNgq+g== dependencies: - "@react-native/dev-middleware" "0.76.3" - "@react-native/metro-babel-transformer" "0.76.3" + "@react-native/dev-middleware" "0.76.5" + "@react-native/metro-babel-transformer" "0.76.5" chalk "^4.0.0" execa "^5.1.1" invariant "^2.2.4" @@ -2222,18 +2242,18 @@ readline "^1.3.0" semver "^7.1.3" -"@react-native/debugger-frontend@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/debugger-frontend/-/debugger-frontend-0.76.3.tgz#531e616f6dad159a58117efc69cec20422d15b0d" - integrity sha512-pMHQ3NpPB28RxXciSvm2yD+uDx3pkhzfuWkc7VFgOduyzPSIr0zotUiOJzsAtrj8++bPbOsAraCeQhCqoOTWQw== +"@react-native/debugger-frontend@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/debugger-frontend/-/debugger-frontend-0.76.5.tgz#0e89940543fb5029506690b83f12547d0bf42cc4" + integrity sha512-5gtsLfBaSoa9WP8ToDb/8NnDBLZjv4sybQQj7rDKytKOdsXm3Pr2y4D7x7GQQtP1ZQRqzU0X0OZrhRz9xNnOqA== -"@react-native/dev-middleware@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/dev-middleware/-/dev-middleware-0.76.3.tgz#52edc76c88e0c2c436eb989551b827bf69f2a56f" - integrity sha512-b+2IpW40z1/S5Jo5JKrWPmucYU/PzeGyGBZZ/SJvmRnBDaP3txb9yIqNZAII1EWsKNhedh8vyRO5PSuJ9Juqzw== +"@react-native/dev-middleware@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/dev-middleware/-/dev-middleware-0.76.5.tgz#10d02fcc6c3c9d24f6dc147c2ef95d6fa6bd3787" + integrity sha512-f8eimsxpkvMgJia7POKoUu9uqjGF6KgkxX4zqr/a6eoR1qdEAWUd6PonSAqtag3PAqvEaJpB99gLH2ZJI1nDGg== dependencies: "@isaacs/ttlcache" "^1.4.1" - "@react-native/debugger-frontend" "0.76.3" + "@react-native/debugger-frontend" "0.76.5" chrome-launcher "^0.15.2" chromium-edge-launcher "^0.2.0" connect "^3.6.5" @@ -2244,60 +2264,60 @@ serve-static "^1.13.1" ws "^6.2.3" -"@react-native/gradle-plugin@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.76.3.tgz#f9cd1c17433811349fff1cab48393b6e9dd7bfe1" - integrity sha512-t0aYZ8ND7+yc+yIm6Yp52bInneYpki6RSIFZ9/LMUzgMKvEB62ptt/7sfho9QkKHCNxE1DJSWIqLIGi/iHHkyg== +"@react-native/gradle-plugin@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.76.5.tgz#90d55ec3a99c609358db97b2d7444b28fdc35bc0" + integrity sha512-7KSyD0g0KhbngITduC8OABn0MAlJfwjIdze7nA4Oe1q3R7qmAv+wQzW+UEXvPah8m1WqFjYTkQwz/4mK3XrQGw== -"@react-native/js-polyfills@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.76.3.tgz#9ac9838b814cf6623797c5118fa4542eb46f410e" - integrity sha512-pubJFArMMrdZiytH+W95KngcSQs+LsxOBsVHkwgMnpBfRUxXPMK4fudtBwWvhnwN76Oe+WhxSq7vOS5XgoPhmw== +"@react-native/js-polyfills@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.76.5.tgz#8f35696d96f804de589cd38382c4f0ffbbc248d5" + integrity sha512-ggM8tcKTcaqyKQcXMIvcB0vVfqr9ZRhWVxWIdiFO1mPvJyS6n+a+lLGkgQAyO8pfH0R1qw6K9D0nqbbDo865WQ== -"@react-native/metro-babel-transformer@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.76.3.tgz#9accefdb77c509329f7272f4ab0676b11d870257" - integrity sha512-b2zQPXmW7avw/7zewc9nzMULPIAjsTwN03hskhxHUJH5pzUf7pIklB3FrgYPZrRhJgzHiNl3tOPu7vqiKzBYPg== +"@react-native/metro-babel-transformer@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.76.5.tgz#ed5a05fff34c47af43eba4069e50be7c486f77bd" + integrity sha512-Cm9G5Sg5BDty3/MKa3vbCAJtT3YHhlEaPlQALLykju7qBS+pHZV9bE9hocfyyvc5N/osTIGWxG5YOfqTeMu1oQ== dependencies: "@babel/core" "^7.25.2" - "@react-native/babel-preset" "0.76.3" + "@react-native/babel-preset" "0.76.5" hermes-parser "0.23.1" nullthrows "^1.1.1" -"@react-native/normalize-colors@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.76.3.tgz#8d4de4a8671385c53b2d202ef0137632abcf747d" - integrity sha512-Yrpmrh4IDEupUUM/dqVxhAN8QW1VEUR3Qrk2lzJC1jB2s46hDe0hrMP2vs12YJqlzshteOthjwXQlY0TgIzgbg== +"@react-native/normalize-colors@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.76.5.tgz#a33560736311aefcf1d3cb594597befe81a9a53c" + integrity sha512-6QRLEok1r55gLqj+94mEWUENuU5A6wsr2OoXpyq/CgQ7THWowbHtru/kRGRr6o3AQXrVnZheR60JNgFcpNYIug== "@react-native/normalize-colors@^0.74.1": version "0.74.88" resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.74.88.tgz#46f4c7270c8e6853281d7dd966e0eb362068e41a" integrity sha512-He5oTwPBxvXrxJ91dZzpxR7P+VYmc9IkJfhuH8zUiU50ckrt+xWNjtVugPdUv4LuVjmZ36Vk2EX8bl1gVn2dVA== -"@react-native/virtualized-lists@0.76.3": - version "0.76.3" - resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.76.3.tgz#9865f9e3770c101476564dc2436018f82adfb4b3" - integrity sha512-wTGv9pVh3vAOWb29xFm+J9VRe9dUcUcb9FyaMLT/Hxa88W4wqa5ZMe1V9UvrrBiA1G5DKjv8/1ZcDsJhyugVKA== +"@react-native/virtualized-lists@0.76.5": + version "0.76.5" + resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.76.5.tgz#394c2d48687db30c79278d183fda8a129a2d24d3" + integrity sha512-M/fW1fTwxrHbcx0OiVOIxzG6rKC0j9cR9Csf80o77y1Xry0yrNPpAlf8D1ev3LvHsiAUiRNFlauoPtodrs2J1A== dependencies: invariant "^2.2.4" nullthrows "^1.1.1" -"@react-navigation/bottom-tabs@^7.0.0": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.1.3.tgz#a3241596147d023e9ffbec42cf85a04ee743f82e" - integrity sha512-cK5zE7OpZAgZLpFBnoH9AhZbSZfH9Qavdi3kIRd2vpQDtCfnnG5bQ2eM2u/IKHDLdI50Mhsf+srqYJgG2VcmVQ== +"@react-navigation/bottom-tabs@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.2.0.tgz#5b336b823226647a263b4fe743655462796b6aaf" + integrity sha512-1LxjgnbPyFINyf9Qr5d1YE0pYhuJayg5TCIIFQmbcX4PRhX7FKUXV7cX8OzrKXEdZi/UE/VNXugtozPAR9zgvA== dependencies: - "@react-navigation/elements" "^2.2.4" + "@react-navigation/elements" "^2.2.5" color "^4.2.3" -"@react-navigation/core@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.3.0.tgz#7a03bf726e2c579c376f31c15874c14b2596a158" - integrity sha512-mfUPRdFCuHkaC+uU5iczqevn0PCTKzf6ApxFwgG9E8DfAVbAT7/piZEzFye2inaIRkipBwyNW40h+mEvYqE1og== +"@react-navigation/core@^7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.3.1.tgz#c6d4857fa2dd321d12ca87e200478c38c420f157" + integrity sha512-S3KCGvNsoqVk8ErAtQI2EAhg9185lahF5OY01ofrrD4Ij/uk3QEHHjoGQhR5l5DXSCSKr1JbMQA7MEKMsBiWZA== dependencies: - "@react-navigation/routers" "^7.1.1" + "@react-navigation/routers" "^7.1.2" escape-string-regexp "^4.0.0" - nanoid "3.3.7" + nanoid "3.3.8" query-string "^7.1.3" react-is "^18.2.0" use-latest-callback "^0.2.1" @@ -2308,38 +2328,38 @@ resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.30.tgz#a81371f599af1070b12014f05d6c09b1a611fd9a" integrity sha512-plhc8UvCZs0UkV+sI+3bisIyn78wz9O/BiWZXpounu72k/R/Sj5PuZYFJ1fi6psvriUveMCGh4LeZckAZu2qiQ== -"@react-navigation/elements@^2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.2.4.tgz#b7ce5711298de72577a613e2e7a0c5be2dbf2fe5" - integrity sha512-/H6Gu/Hn2E/pBQTkZEMbP5SDi7C2q96PrHGvsDJiFtxFgOJusA3+ygUguqTeTP402s/5KvJm47g0UloCMiECwA== +"@react-navigation/elements@^2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.2.5.tgz#0e2ca76e2003e96b417a3d7c2829bf1afd69193f" + integrity sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg== dependencies: color "^4.2.3" -"@react-navigation/native-stack@^7.0.0": - version "7.1.14" - resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.1.14.tgz#179a6efdbeff7a2da36102cb04fe43cb7ff5c48e" - integrity sha512-MH3iktneSL8JSttcgJBIb6zmDpaurbtMSQcYwCcsGoyq4fJ2pBIwJaViSa0KrNkMsWAMZEOY9O72rf1umu7VKw== +"@react-navigation/native-stack@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.2.0.tgz#8aa489f88d662b3543a931b9cb934bb2e09a4893" + integrity sha512-mw7Nq9qQrGsmJmCTwIIWB7yY/3tWYXvQswx+HJScGAadIjemvytJXm1fcl3+YZ9T9Ym0aERcVe5kDs+ny3X4vA== dependencies: - "@react-navigation/elements" "^2.2.4" + "@react-navigation/elements" "^2.2.5" warn-once "^0.1.1" -"@react-navigation/native@^7.0.0": - version "7.0.13" - resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.0.13.tgz#6b2be58232117aa8ea43edae9fd255c25e3f53d1" - integrity sha512-HLoMyp453qIDGjG72cJ2xLeGHHpP4PQve5gQvSn3o/6r2+DAmDuIcd/jXTMJGCHd2LeR9LfuqIvpiIlihg1iBg== +"@react-navigation/native@^7.0.14": + version "7.0.14" + resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.0.14.tgz#b3ee2879038dcf0523d26516af88d3adc549ce5e" + integrity sha512-Gi6lLw4VOGSWAhmUdJOMauOKGK51/YA1CprjXm91sNfgERWvznqEMw8QmUQx9SEqYfi0LfZhbzpMst09SJ00lw== dependencies: - "@react-navigation/core" "^7.3.0" + "@react-navigation/core" "^7.3.1" escape-string-regexp "^4.0.0" fast-deep-equal "^3.1.3" - nanoid "3.3.7" + nanoid "3.3.8" use-latest-callback "^0.2.1" -"@react-navigation/routers@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-7.1.1.tgz#2544453bdeecc77d01099173a1eb102b39eca92f" - integrity sha512-OycWRj95p+/zENl9HU6tvvT6IUuxgVJirgsA0W9rQn3RC+9Hb0UVYA0+8avdt+WpMoWdrvwTxTXneB5mjYzHrw== +"@react-navigation/routers@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-7.1.2.tgz#647a63e383673de0c4fc10c64a17f551d5da0a17" + integrity sha512-emdEjpVDK8zbiu2GChC8oYIAub9i/OpNuQJekVsbyFCBz4/TzaBzms38Q53YaNhdIFNmiYLfHv/Y1Ub7KYfm3w== dependencies: - nanoid "3.3.7" + nanoid "3.3.8" "@remix-run/node@^2.12.0": version "2.15.0" @@ -2959,10 +2979,10 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" -babel-preset-expo@~12.0.3: - version "12.0.3" - resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-12.0.3.tgz#2ad62fe007517704841788cfea38b333e307663f" - integrity sha512-1695e8y3U/HjifKx33vcNnFMSUSXwPWwhFxRlL6NRx2TENN6gySH82gPOWgxcra6gi+EJgXx52xG3PcqTjwW6w== +babel-preset-expo@~12.0.4: + version "12.0.4" + resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-12.0.4.tgz#ec965530d866c8905aac1fa478562cb08ab32a55" + integrity sha512-SAzAwqpyjA+/OFrU95OOioj6oTeCv4+rRfrNmBTy5S/gJswrZKBSPJioFudIaJBy43W+BL7HA5AspBIF6tO/aA== dependencies: "@babel/plugin-proposal-decorators" "^7.12.9" "@babel/plugin-transform-export-namespace-from" "^7.22.11" @@ -2970,7 +2990,7 @@ babel-preset-expo@~12.0.3: "@babel/plugin-transform-parameters" "^7.22.15" "@babel/preset-react" "^7.22.15" "@babel/preset-typescript" "^7.23.0" - "@react-native/babel-preset" "0.76.3" + "@react-native/babel-preset" "0.76.5" babel-plugin-react-native-web "~0.19.13" react-refresh "^0.14.2" @@ -3945,17 +3965,17 @@ expo-document-picker@~13.0.1: resolved "https://registry.yarnpkg.com/expo-document-picker/-/expo-document-picker-13.0.1.tgz#f8c70d11cd59d7e57d5065667893c277b1a8869e" integrity sha512-M3O3SDqubsRbVyY+Xu6V45K0/G1S1IqEdmVAnPkOiUU2eIEFfF5oP4KON4CsvEhO9IIunnpRr/oq9NQxb3SrEA== -expo-file-system@~18.0.4: - version "18.0.4" - resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-18.0.4.tgz#eecf8dc0b3b545e9ac5cd00352665afe2d57732f" - integrity sha512-aAWEDwnu0XHOBYvQ9Q0+QIa+483vYJaC4IDsXyWQ73Rtsg273NZh5kYowY+cAocvoSmA99G6htrLBn11ax2bTQ== +expo-file-system@~18.0.6: + version "18.0.6" + resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-18.0.6.tgz#43f7718530d0e2aa1f49bca7ccb721007acabf2c" + integrity sha512-gGEwIJCXV3/wpIJ/wRyhmieLOSAY7HeFFjb+wEfHs04aE63JYR+rXXV4b7rBpEh1ZgNV9U91zfet/iQG7J8HBQ== dependencies: web-streams-polyfill "^3.3.2" -expo-font@~13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-13.0.1.tgz#3a7eed7a4238a352fc74a425fd8c020c5f122382" - integrity sha512-8JE47B+6cLeKWr5ql8gU6YsPHjhrz1vMrTqYMm72No/8iW8Sb/uL4Oc0dpmbjq3hLLXBY0xPBQOgU7FQ6Y04Vg== +expo-font@~13.0.2: + version "13.0.2" + resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-13.0.2.tgz#efd3e91714c040a0cf38db91920bce2e0331ff6e" + integrity sha512-H9FaXM7ZW5+EfV38w80BgJG3H17kB7CuVXwHoiszIYyoPfWz9bWesFe4QwNZjTq3pzKes28sSd8irFuflIrSIA== dependencies: fontfaceobserver "^2.1.0" @@ -3996,10 +4016,15 @@ expo-linking@~7.0.3: expo-constants "~17.0.0" invariant "^2.2.4" -expo-modules-autolinking@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-2.0.3.tgz#c0de0129bedf1b6f9aa36093e435d00509f27fcd" - integrity sha512-Q/ALJ54eS7Cr7cmbP+unEDTkHFQivQerWWrqZxuXOrSFYGCYU22+/xAZXaJOpZwseOVsP74zSkoRY/wBimVs7w== +expo-media-library@~17.0.4: + version "17.0.4" + resolved "https://registry.yarnpkg.com/expo-media-library/-/expo-media-library-17.0.4.tgz#428db62aa21777ab3cc2859cd8c7c147666dc531" + integrity sha512-5Fbv3dTlswO6ZcSYDF7zrCzsGly14rA0uKo+wyn3H4gEVgmLOZEzvAkLT4ELFq4RfT+zEuYCKPG1Sb1Q41e5kg== + +expo-modules-autolinking@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-2.0.4.tgz#28fcd12fb0d066a2933cca3bf3b597da0f6b2f2a" + integrity sha512-e0p+19NhmD50U7s7BV7kWIypWmTNC9n/VlJKlXS05hM/zX7pe6JKmXyb+BFnXJq3SLBalLCUY0tu2gEUF3XeVg== dependencies: "@expo/spawn-async" "^1.7.2" chalk "^4.1.0" @@ -4010,24 +4035,24 @@ expo-modules-autolinking@2.0.3: require-from-string "^2.0.2" resolve-from "^5.0.0" -expo-modules-core@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-2.1.1.tgz#970af4cfd70c8aa6fc0096dd0a6578aa003a479f" - integrity sha512-yQzYCLR2mre4BNMXuqkeJ0oSNgmGEMI6BcmIzeNZbC2NFEjiaDpKvlV9bclYCtyVhUEVNbJcEPYMr6c1Y4eR4w== +expo-modules-core@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-2.1.2.tgz#258be4fbd162b69eb4ad2789131ac2dc7e85fc08" + integrity sha512-0OhMU5S8zf9c/CRh1MwiXfOInI9wzz6yiIh5RuR/9J7N6xHRum68hInsPbaSc1UQpo08ZZLM4MPsbpoNRUoqIg== dependencies: invariant "^2.2.4" -expo-router@~4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/expo-router/-/expo-router-4.0.11.tgz#324364534fc7837a99a7894c611b3cd75e4470c5" - integrity sha512-2Qrd/fk98kC+CTg1umbuUaBaGkpdGStPpkSR99SoAjX6KWC1WhNMCv0hGFn7cRmSNOWQzgIfLGLERhRY1o4myw== +expo-router@~4.0.15: + version "4.0.15" + resolved "https://registry.yarnpkg.com/expo-router/-/expo-router-4.0.15.tgz#bdc00b90bd60ab5ccb35ae51f31dcbc96c179949" + integrity sha512-5MDy7iVzgi8lheRunsR4lTKEKTNqukC3uYSWhY370Nakdd+E/Woz+Vw1M67/KrnvefTV5hF97bNUUMzY+fyojw== dependencies: "@expo/metro-runtime" "4.0.0" "@expo/server" "^0.5.0" "@radix-ui/react-slot" "1.0.1" - "@react-navigation/bottom-tabs" "^7.0.0" - "@react-navigation/native" "^7.0.0" - "@react-navigation/native-stack" "^7.0.0" + "@react-navigation/bottom-tabs" "^7.2.0" + "@react-navigation/native" "^7.0.14" + "@react-navigation/native-stack" "^7.2.0" client-only "^0.0.1" react-helmet-async "^1.3.0" react-native-helmet-async "2.0.4" @@ -4041,38 +4066,38 @@ expo-sharing@~13.0.0: resolved "https://registry.yarnpkg.com/expo-sharing/-/expo-sharing-13.0.0.tgz#fbc46f4afdaa265a2811fe88c2a589aae2d2de0f" integrity sha512-b23ymicRmYn/Pjj05sl9tFZHN5cH9I1f0yiqY1Yk8Q3oCx0Aznri82DnTYA4T/J6D9vrkraX0wQ4jWVMOffmlg== -expo-splash-screen@~0.29.13: - version "0.29.13" - resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.29.13.tgz#2a9083cdb4f7d3e5e4427b625a5249eaae71de7a" - integrity sha512-OTaW6v2ErKTlguFDNi4PN+qrEFRA4TIEyFag4204CiFIpAB+13PqQiW4Ovt29aYlLERIjWD++PyoHeSdLSiZwg== +expo-splash-screen@~0.29.18: + version "0.29.18" + resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.29.18.tgz#96ccce3d5a03389a9061743903b0a77c22a16796" + integrity sha512-bTBY+LF6YtYen2j60yGNh2SX/tG4UXZAyBCMMriOSiZZ7LSCs3ARyEufaSiWk+ckWShTeMqItOnaAN/CAF8MJA== dependencies: - "@expo/prebuild-config" "^8.0.17" + "@expo/prebuild-config" "^8.0.23" expo-status-bar@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/expo-status-bar/-/expo-status-bar-2.0.0.tgz#dd99adc2ace12a24c92718cd0f97b93347103393" integrity sha512-vxxdpvpNDMTEc5uTiIrbTvySKKUsOACmfl8OZuUdjNle05oGqwtq3v5YObwym/njSByjoyuZX8UpXBZnxvarwQ== -expo@^52.0.0: - version "52.0.15" - resolved "https://registry.yarnpkg.com/expo/-/expo-52.0.15.tgz#488cb4f5e95b6985999106453a8dcbb8a28a6988" - integrity sha512-7eGv8y/aslaHvKH8XVvx0XpvJIQiJZ63kBHcdjtAmy+7KCMQp4lwmrnCzYhVdROe1i/GmHF2UwYfHXIYgC1WEw== +expo@~52.0.20: + version "52.0.23" + resolved "https://registry.yarnpkg.com/expo/-/expo-52.0.23.tgz#68b79da2206afdce9c68f45f519f812bab9a2cfe" + integrity sha512-DR36Vkpz/ZLPci4fxDBG/pLk26nGK63vcZ+X4RZJfNBzi14DXZ939loP8YzWGV78Qp23qdPINczpo2727tqLxg== dependencies: "@babel/runtime" "^7.20.0" - "@expo/cli" "0.22.1" + "@expo/cli" "0.22.7" "@expo/config" "~10.0.6" - "@expo/config-plugins" "~9.0.11" - "@expo/fingerprint" "0.11.3" - "@expo/metro-config" "0.19.5" + "@expo/config-plugins" "~9.0.12" + "@expo/fingerprint" "0.11.6" + "@expo/metro-config" "0.19.8" "@expo/vector-icons" "^14.0.0" - babel-preset-expo "~12.0.3" + babel-preset-expo "~12.0.4" expo-asset "~11.0.1" expo-constants "~17.0.3" - expo-file-system "~18.0.4" - expo-font "~13.0.1" + expo-file-system "~18.0.6" + expo-font "~13.0.2" expo-keep-awake "~14.0.1" - expo-modules-autolinking "2.0.3" - expo-modules-core "2.1.1" + expo-modules-autolinking "2.0.4" + expo-modules-core "2.1.2" fbemitter "^3.0.0" web-streams-polyfill "^3.3.2" whatwg-url-without-unicode "8.0.0-3" @@ -5697,16 +5722,21 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@3.3.7, nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +nanoid@3.3.8: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== nanoid@^3.3.1: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + ncp@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" @@ -6380,10 +6410,10 @@ react-native-safe-area-context@4.12.0: resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.12.0.tgz#17868522a55bbc6757418c94a1b4abdda6b045d9" integrity sha512-ukk5PxcF4p3yu6qMZcmeiZgowhb5AsKRnil54YFUUAXVIS7PJcMHGGC+q44fCiBg44/1AJk5njGMez1m9H0BVQ== -react-native-screens@~4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.1.0.tgz#3f703a1bb4fd65fd7963e616ddc373a97809c254" - integrity sha512-tCBwe7fRMpoi/nIgZxE86N8b2SH8d5PlfGaQO8lgqlXqIyvwqm3u1HJCaA0tsacPyzhW7vVtRfQyq9e1j0S2gA== +react-native-screens@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.4.0.tgz#3fcbcdf1bbb1be2736b10d43edc3d4e69c37b5aa" + integrity sha512-c7zc7Zwjty6/pGyuuvh9gK3YBYqHPOxrhXfG1lF4gHlojQSmIx2piNbNaV+Uykj+RDTmFXK0e/hA+fucw/Qozg== dependencies: react-freeze "^1.0.0" warn-once "^0.1.0" @@ -6418,19 +6448,19 @@ react-native-web@~0.19.13: postcss-value-parser "^4.2.0" styleq "^0.1.3" -react-native@0.76.3: - version "0.76.3" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.76.3.tgz#18b79949c58932e9fd8d04b205e5c0a46bc46d8f" - integrity sha512-0TUhgmlouRNf6yuDIIAdbQl0g1VsONgCMsLs7Et64hjj5VLMCA7np+4dMrZvGZ3wRNqzgeyT9oWJsUm49AcwSQ== +react-native@0.76.5: + version "0.76.5" + resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.76.5.tgz#3ce43d3c31f46cfd98e56ef2dfc70866c04ad185" + integrity sha512-op2p2kB+lqMF1D7AdX4+wvaR0OPFbvWYs+VBE7bwsb99Cn9xISrLRLAgFflZedQsa5HvnOGrULhtnmItbIKVVw== dependencies: "@jest/create-cache-key-function" "^29.6.3" - "@react-native/assets-registry" "0.76.3" - "@react-native/codegen" "0.76.3" - "@react-native/community-cli-plugin" "0.76.3" - "@react-native/gradle-plugin" "0.76.3" - "@react-native/js-polyfills" "0.76.3" - "@react-native/normalize-colors" "0.76.3" - "@react-native/virtualized-lists" "0.76.3" + "@react-native/assets-registry" "0.76.5" + "@react-native/codegen" "0.76.5" + "@react-native/community-cli-plugin" "0.76.5" + "@react-native/gradle-plugin" "0.76.5" + "@react-native/js-polyfills" "0.76.5" + "@react-native/normalize-colors" "0.76.5" + "@react-native/virtualized-lists" "0.76.5" abort-controller "^3.0.0" anser "^1.4.9" ansi-regex "^5.0.0" @@ -7026,6 +7056,24 @@ stream-buffers@2.2.x, stream-buffers@~2.2.0: version "0.0.0" uid "" +stream-chat-react-native-core@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.1.0.tgz#eaf2afb65832c77de4577fae24c2fc6bbcd5ece5" + integrity sha512-W4gbRb8Bq1IzzL026GudIxD8Rtlhr3WrKukt4g8zucJVL5iTR4PFxWWmQH081XF5qCS+tYnJSiZFdd4ot7LKwA== + dependencies: + "@gorhom/bottom-sheet" "^5.0.6" + dayjs "1.10.5" + emoji-regex "^10.3.0" + i18next "^21.6.14" + intl-pluralrules "^2.0.1" + linkifyjs "^4.1.1" + lodash-es "4.17.21" + mime-types "^2.1.34" + path "0.12.7" + react-native-markdown-package "1.8.2" + react-native-url-polyfill "^1.3.0" + stream-chat "8.46.0" + "stream-chat-react-native-core@link:../../package": version "0.0.0" uid "" diff --git a/package/expo-package/src/optionalDependencies/takePhoto.ts b/package/expo-package/src/optionalDependencies/takePhoto.ts index d7744fd18d..ee81ce52ee 100644 --- a/package/expo-package/src/optionalDependencies/takePhoto.ts +++ b/package/expo-package/src/optionalDependencies/takePhoto.ts @@ -36,13 +36,29 @@ export const takePhoto = ImagePicker if (permissionGranted) { const imagePickerSuccessResult = await ImagePicker.launchCameraAsync({ + mediaTypes: Platform.OS === 'ios' ? ['images', 'videos'] : 'images', quality: Math.min(Math.max(0, compressImageQuality), 1), }); const canceled = imagePickerSuccessResult.canceled; const assets = imagePickerSuccessResult.assets; // since we only support single photo upload for now we will only be focusing on 0'th element. const photo = assets && assets[0]; - + if (Platform.OS === 'ios') { + if (photo.mimeType.includes('video')) { + const clearFilter = new RegExp('[.:]', 'g'); + const date = new Date().toISOString().replace(clearFilter, '_'); + return { + ...photo, + cancelled: false, + duration: photo.duration, + source: 'camera', + name: 'video_recording_' + date + photo.uri.split('.').pop(), + size: photo.fileSize, + type: photo.mimeType, + uri: photo.uri, + }; + } + } if (canceled === false && photo && photo.height && photo.width && photo.uri) { let size: Size = {}; if (Platform.OS === 'android') { @@ -70,6 +86,7 @@ export const takePhoto = ImagePicker return { cancelled: false, size: photo.fileSize, + type: photo.mimeType, source: 'camera', uri: photo.uri, ...size, diff --git a/package/native-package/src/optionalDependencies/takePhoto.ts b/package/native-package/src/optionalDependencies/takePhoto.ts index d6c82a6566..05013949ff 100644 --- a/package/native-package/src/optionalDependencies/takePhoto.ts +++ b/package/native-package/src/optionalDependencies/takePhoto.ts @@ -29,6 +29,7 @@ export const takePhoto = ImagePicker } try { const result = await ImagePicker.launchCamera({ + mediaType: Platform.OS === 'ios' ? 'mixed' : 'images', quality: Math.min(Math.max(0, compressImageQuality), 1), }); if (!result.assets.length) { @@ -36,14 +37,30 @@ export const takePhoto = ImagePicker cancelled: true, }; } - const photo = result.assets[0]; - if (photo.height && photo.width && photo.uri) { + const asset = result.assets[0]; + if (Platform.OS === 'ios') { + if (asset.type.includes('video')) { + const clearFilter = new RegExp('[.:]', 'g'); + const date = new Date().toISOString().replace(clearFilter, '_'); + return { + ...asset, + cancelled: false, + duration: asset.duration ? asset.duration * 1000 : undefined, // in milliseconds + source: 'camera', + name: 'video_recording_' + date + asset.fileName.split('.').pop(), + size: asset.fileSize, + type: asset.type, + uri: asset.uri, + }; + } + } + if (asset.height && asset.width && asset.uri) { let size: { height?: number; width?: number } = {}; if (Platform.OS === 'android') { // Height and width returned by ImagePicker are incorrect on Android. const getSize = (): Promise<{ height: number; width: number }> => new Promise((resolve) => { - Image.getSize(photo.uri, (width, height) => { + Image.getSize(asset.uri, (width, height) => { resolve({ height, width }); }); }); @@ -58,15 +75,16 @@ export const takePhoto = ImagePicker } } else { size = { - height: photo.height, - width: photo.width, + height: asset.height, + width: asset.width, }; } return { cancelled: false, - size: photo.size, + type: asset.type, + size: asset.size, source: 'camera', - uri: photo.uri, + uri: asset.uri, ...size, }; } diff --git a/package/src/contexts/messageInputContext/MessageInputContext.tsx b/package/src/contexts/messageInputContext/MessageInputContext.tsx index 0e0bef23f6..5983f33343 100644 --- a/package/src/contexts/messageInputContext/MessageInputContext.tsx +++ b/package/src/contexts/messageInputContext/MessageInputContext.tsx @@ -701,7 +701,11 @@ export const MessageInputProvider = < ); } if (!photo.cancelled) { - await uploadNewImage(photo); + if (photo.type.includes('image')) { + await uploadNewImage(photo); + } else { + await uploadNewFile({ ...photo, mimeType: photo.type, type: FileTypes.Video }); + } } }; From 9d02d863c67b7c72e3ba093884eee0b97d5deff6 Mon Sep 17 00:00:00 2001 From: Khushal Agarwal Date: Thu, 2 Jan 2025 16:15:26 +0530 Subject: [PATCH 2/4] fix: add better warning log --- package/expo-package/src/optionalDependencies/takePhoto.ts | 2 +- package/native-package/src/optionalDependencies/takePhoto.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/expo-package/src/optionalDependencies/takePhoto.ts b/package/expo-package/src/optionalDependencies/takePhoto.ts index ee81ce52ee..cc64f8df6e 100644 --- a/package/expo-package/src/optionalDependencies/takePhoto.ts +++ b/package/expo-package/src/optionalDependencies/takePhoto.ts @@ -10,7 +10,7 @@ try { if (!ImagePicker) { console.log( - 'expo-image-picker is not installed. Installing this package will enable campturing photos through the app, and thereby send it.', + 'expo-image-picker is not installed. Installing this package will enable capturing photos and videos(for iOS) through the app, and thereby send it.', ); } diff --git a/package/native-package/src/optionalDependencies/takePhoto.ts b/package/native-package/src/optionalDependencies/takePhoto.ts index 05013949ff..5dcf3f8403 100644 --- a/package/native-package/src/optionalDependencies/takePhoto.ts +++ b/package/native-package/src/optionalDependencies/takePhoto.ts @@ -6,7 +6,7 @@ try { ImagePicker = require('react-native-image-picker'); } catch (e) { console.log( - 'The package react-native-image-picker is not installed. Please install the same so as to take photo through camera and upload it.', + 'The package react-native-image-picker is not installed. Installing this package will enable capturing photos and videos(for iOS) through the app, and thereby send it.', ); } From 521ea88d5d6fd1238365e260720ea1bd5f6cd2b7 Mon Sep 17 00:00:00 2001 From: Khushal Agarwal Date: Fri, 3 Jan 2025 21:32:51 +0530 Subject: [PATCH 3/4] feat: add video recording support for android --- .../src/optionalDependencies/takePhoto.ts | 96 ++++++++++--------- .../src/optionalDependencies/takePhoto.ts | 92 +++++++++--------- .../AttachmentPickerSelectionBar.tsx | 19 +++- .../components/NativeAttachmentPicker.tsx | 12 ++- .../MessageInputContext.tsx | 7 +- package/src/native.ts | 6 +- 6 files changed, 137 insertions(+), 95 deletions(-) diff --git a/package/expo-package/src/optionalDependencies/takePhoto.ts b/package/expo-package/src/optionalDependencies/takePhoto.ts index cc64f8df6e..157a738bc9 100644 --- a/package/expo-package/src/optionalDependencies/takePhoto.ts +++ b/package/expo-package/src/optionalDependencies/takePhoto.ts @@ -19,8 +19,15 @@ type Size = { width?: number; }; +// Media type mapping for iOS and Android +const mediaTypeMap = { + mixed: ['images', 'videos'], + image: 'images', + video: 'videos', +}; + export const takePhoto = ImagePicker - ? async ({ compressImageQuality = 1 }) => { + ? async ({ compressImageQuality = 1, mediaType = Platform.OS === 'ios' ? 'mixed' : 'image' }) => { try { const permissionCheck = await ImagePicker.getCameraPermissionsAsync(); const canRequest = permissionCheck.canAskAgain; @@ -36,61 +43,64 @@ export const takePhoto = ImagePicker if (permissionGranted) { const imagePickerSuccessResult = await ImagePicker.launchCameraAsync({ - mediaTypes: Platform.OS === 'ios' ? ['images', 'videos'] : 'images', + mediaTypes: Platform.OS === 'ios' ? mediaTypeMap[mediaType] : mediaType[mediaType], quality: Math.min(Math.max(0, compressImageQuality), 1), }); const canceled = imagePickerSuccessResult.canceled; const assets = imagePickerSuccessResult.assets; // since we only support single photo upload for now we will only be focusing on 0'th element. const photo = assets && assets[0]; - if (Platform.OS === 'ios') { - if (photo.mimeType.includes('video')) { - const clearFilter = new RegExp('[.:]', 'g'); - const date = new Date().toISOString().replace(clearFilter, '_'); - return { - ...photo, - cancelled: false, - duration: photo.duration, - source: 'camera', - name: 'video_recording_' + date + photo.uri.split('.').pop(), - size: photo.fileSize, - type: photo.mimeType, - uri: photo.uri, - }; - } + console.log('photo', photo); + if (canceled) { + return { cancelled: true }; } - if (canceled === false && photo && photo.height && photo.width && photo.uri) { - let size: Size = {}; - if (Platform.OS === 'android') { - const getSize = (): Promise => - new Promise((resolve) => { - Image.getSize(photo.uri, (width, height) => { - resolve({ height, width }); - }); - }); - - try { - const { height, width } = await getSize(); - size.height = height; - size.width = width; - } catch (e) { - console.warn('Error get image size of picture caputred from camera ', e); - } - } else { - size = { - height: photo.height, - width: photo.width, - }; - } - + if (photo.mimeType.includes('video')) { + const clearFilter = new RegExp('[.:]', 'g'); + const date = new Date().toISOString().replace(clearFilter, '_'); return { + ...photo, cancelled: false, + duration: photo.duration, // in milliseconds + source: 'camera', + name: 'video_recording_' + date + photo.uri.split('.').pop(), size: photo.fileSize, type: photo.mimeType, - source: 'camera', uri: photo.uri, - ...size, }; + } else { + if (photo && photo.height && photo.width && photo.uri) { + let size: Size = {}; + if (Platform.OS === 'android') { + const getSize = (): Promise => + new Promise((resolve) => { + Image.getSize(photo.uri, (width, height) => { + resolve({ height, width }); + }); + }); + + try { + const { height, width } = await getSize(); + size.height = height; + size.width = width; + } catch (e) { + console.warn('Error get image size of picture caputred from camera ', e); + } + } else { + size = { + height: photo.height, + width: photo.width, + }; + } + + return { + cancelled: false, + size: photo.fileSize, + type: photo.mimeType, + source: 'camera', + uri: photo.uri, + ...size, + }; + } } } } catch (error) { diff --git a/package/native-package/src/optionalDependencies/takePhoto.ts b/package/native-package/src/optionalDependencies/takePhoto.ts index 5dcf3f8403..673cc368ce 100644 --- a/package/native-package/src/optionalDependencies/takePhoto.ts +++ b/package/native-package/src/optionalDependencies/takePhoto.ts @@ -11,7 +11,10 @@ try { } export const takePhoto = ImagePicker - ? async ({ compressImageQuality = Platform.OS === 'ios' ? 0.8 : 1 }) => { + ? async ({ + compressImageQuality = Platform.OS === 'ios' ? 0.8 : 1, + mediaType = Platform.OS === 'ios' ? 'mixed' : 'image', + }) => { if (Platform.OS === 'android') { const cameraPermissions = await PermissionsAndroid.check( PermissionsAndroid.PERMISSIONS.CAMERA, @@ -29,7 +32,7 @@ export const takePhoto = ImagePicker } try { const result = await ImagePicker.launchCamera({ - mediaType: Platform.OS === 'ios' ? 'mixed' : 'images', + mediaType: mediaType, quality: Math.min(Math.max(0, compressImageQuality), 1), }); if (!result.assets.length) { @@ -38,56 +41,55 @@ export const takePhoto = ImagePicker }; } const asset = result.assets[0]; - if (Platform.OS === 'ios') { - if (asset.type.includes('video')) { - const clearFilter = new RegExp('[.:]', 'g'); - const date = new Date().toISOString().replace(clearFilter, '_'); + if (asset.type.includes('video')) { + const clearFilter = new RegExp('[.:]', 'g'); + const date = new Date().toISOString().replace(clearFilter, '_'); + return { + ...asset, + cancelled: false, + duration: asset.duration * 1000, + source: 'camera', + name: 'video_recording_' + date + asset.fileName.split('.').pop(), + size: asset.fileSize, + type: asset.type, + uri: asset.uri, + }; + } else { + if (asset.height && asset.width && asset.uri) { + let size: { height?: number; width?: number } = {}; + if (Platform.OS === 'android') { + // Height and width returned by ImagePicker are incorrect on Android. + const getSize = (): Promise<{ height: number; width: number }> => + new Promise((resolve) => { + Image.getSize(asset.uri, (width, height) => { + resolve({ height, width }); + }); + }); + + try { + const { height, width } = await getSize(); + size.height = height; + size.width = width; + } catch (e) { + // do nothing + console.warn('Error get image size of picture caputred from camera ', e); + } + } else { + size = { + height: asset.height, + width: asset.width, + }; + } return { - ...asset, cancelled: false, - duration: asset.duration ? asset.duration * 1000 : undefined, // in milliseconds - source: 'camera', - name: 'video_recording_' + date + asset.fileName.split('.').pop(), - size: asset.fileSize, type: asset.type, + size: asset.size, + source: 'camera', uri: asset.uri, + ...size, }; } } - if (asset.height && asset.width && asset.uri) { - let size: { height?: number; width?: number } = {}; - if (Platform.OS === 'android') { - // Height and width returned by ImagePicker are incorrect on Android. - const getSize = (): Promise<{ height: number; width: number }> => - new Promise((resolve) => { - Image.getSize(asset.uri, (width, height) => { - resolve({ height, width }); - }); - }); - - try { - const { height, width } = await getSize(); - size.height = height; - size.width = width; - } catch (e) { - // do nothing - console.warn('Error get image size of picture caputred from camera ', e); - } - } else { - size = { - height: asset.height, - width: asset.width, - }; - } - return { - cancelled: false, - type: asset.type, - size: asset.size, - source: 'camera', - uri: asset.uri, - ...size, - }; - } } catch (e: unknown) { if (e instanceof Error) { // on iOS: if it was in inactive state, then the user had just denied the permissions diff --git a/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx b/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx index a86cea012d..74c9751fc5 100644 --- a/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx +++ b/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx @@ -7,6 +7,7 @@ import { useMessageInputContext } from '../../../contexts/messageInputContext/Me import { useMessagesContext } from '../../../contexts/messagesContext/MessagesContext'; import { useOwnCapabilitiesContext } from '../../../contexts/ownCapabilitiesContext/OwnCapabilitiesContext'; import { useTheme } from '../../../contexts/themeContext/ThemeContext'; +import { Recorder } from '../../../icons'; const styles = StyleSheet.create({ container: { @@ -48,6 +49,7 @@ export const AttachmentPickerSelectionBar = () => { const { theme: { attachmentSelectionBar: { container, icon }, + colors: { grey }, }, } = useTheme(); @@ -105,7 +107,9 @@ export const AttachmentPickerSelectionBar = () => { {hasCameraPicker ? ( { + takeAndUploadImage(); + }} testID='take-photo-touchable' > @@ -116,6 +120,19 @@ export const AttachmentPickerSelectionBar = () => { ) : null} + {hasCameraPicker ? ( + { + takeAndUploadImage('video'); + }} + testID='take-photo-touchable' + > + + + + + ) : null} {!threadList && hasCreatePoll && ownCapabilities.sendPoll ? ( // do not allow poll creation in threads void; @@ -28,10 +29,10 @@ export const NativeAttachmentPicker = ({ }: NativeAttachmentPickerProps) => { const size = attachButtonLayoutRectangle?.width ?? 0; const attachButtonItemSize = 40; - const NUMBER_OF_BUTTONS = 3; + const NUMBER_OF_BUTTONS = 5; const { theme: { - colors: { grey_whisper }, + colors: { grey, grey_whisper }, messageInput: { nativeAttachmentPicker: { buttonContainer, @@ -149,6 +150,13 @@ export const NativeAttachmentPicker = ({ id: 'Camera', onPressHandler: takeAndUploadImage, }); + buttons.push({ + icon: , + id: 'Video', + onPressHandler: () => { + takeAndUploadImage('video'); + }, + }); } return ( diff --git a/package/src/contexts/messageInputContext/MessageInputContext.tsx b/package/src/contexts/messageInputContext/MessageInputContext.tsx index 5983f33343..fca2861439 100644 --- a/package/src/contexts/messageInputContext/MessageInputContext.tsx +++ b/package/src/contexts/messageInputContext/MessageInputContext.tsx @@ -57,6 +57,7 @@ import type { Emoji } from '../../emoji-data'; import { isDocumentPickerAvailable, isImageMediaLibraryAvailable, + MediaTypes, pickDocument, pickImage, takePhoto, @@ -232,7 +233,7 @@ export type LocalMessageInputContext< /** * Function for taking a photo and uploading it */ - takeAndUploadImage: () => Promise; + takeAndUploadImage: (mediaType?: MediaTypes) => Promise; text: string; toggleAttachmentPicker: () => void; /** @@ -686,10 +687,10 @@ export const MessageInputProvider = < /** * Function for capturing a photo and uploading it */ - const takeAndUploadImage = async () => { + const takeAndUploadImage = async (mediaType?: MediaTypes) => { setSelectedPicker(undefined); closePicker(); - const photo = await takePhoto({ compressImageQuality: value.compressImageQuality }); + const photo = await takePhoto({ compressImageQuality: value.compressImageQuality, mediaType }); if (photo.askToOpenSettings) { Alert.alert( t('Allow camera access in device settings'), diff --git a/package/src/native.ts b/package/src/native.ts index 59a053a099..6bc60cb7aa 100644 --- a/package/src/native.ts +++ b/package/src/native.ts @@ -85,7 +85,11 @@ type Photo = Omit & { askToOpenSettings?: boolean; cancelled?: boolean; }; -type TakePhoto = (options: { compressImageQuality?: number }) => Promise | never; +export type MediaTypes = 'image' | 'video' | 'mixed'; +type TakePhoto = (options: { + compressImageQuality?: number; + mediaType?: MediaTypes; +}) => Promise | never; export let takePhoto: TakePhoto = fail; type HapticFeedbackMethod = From 8f8d17b94216ccf0a335609102af35578f1ce0c9 Mon Sep 17 00:00:00 2001 From: Khushal Agarwal Date: Mon, 6 Jan 2025 13:01:43 +0530 Subject: [PATCH 4/4] fix: refine the android video recording handler --- .../src/optionalDependencies/takePhoto.ts | 3 +- .../src/optionalDependencies/takePhoto.ts | 2 +- .../components/AttachmentPickerItem.tsx | 2 +- .../AttachmentPickerSelectionBar.tsx | 16 ++++++---- .../components/VideoRecorderSelectorIcon.tsx | 14 ++++++++ .../components/NativeAttachmentPicker.tsx | 32 ++++++++++--------- package/src/components/index.ts | 1 + .../AttachmentPickerContext.tsx | 9 +++++- .../overlayContext/OverlayContext.tsx | 1 + .../overlayContext/OverlayProvider.tsx | 3 ++ package/src/icons/Recorder.tsx | 12 +++---- 11 files changed, 60 insertions(+), 35 deletions(-) create mode 100644 package/src/components/AttachmentPicker/components/VideoRecorderSelectorIcon.tsx diff --git a/package/expo-package/src/optionalDependencies/takePhoto.ts b/package/expo-package/src/optionalDependencies/takePhoto.ts index 157a738bc9..d23ba47f9b 100644 --- a/package/expo-package/src/optionalDependencies/takePhoto.ts +++ b/package/expo-package/src/optionalDependencies/takePhoto.ts @@ -43,14 +43,13 @@ export const takePhoto = ImagePicker if (permissionGranted) { const imagePickerSuccessResult = await ImagePicker.launchCameraAsync({ - mediaTypes: Platform.OS === 'ios' ? mediaTypeMap[mediaType] : mediaType[mediaType], + mediaTypes: mediaTypeMap[mediaType], quality: Math.min(Math.max(0, compressImageQuality), 1), }); const canceled = imagePickerSuccessResult.canceled; const assets = imagePickerSuccessResult.assets; // since we only support single photo upload for now we will only be focusing on 0'th element. const photo = assets && assets[0]; - console.log('photo', photo); if (canceled) { return { cancelled: true }; } diff --git a/package/native-package/src/optionalDependencies/takePhoto.ts b/package/native-package/src/optionalDependencies/takePhoto.ts index 673cc368ce..d91a01d0b0 100644 --- a/package/native-package/src/optionalDependencies/takePhoto.ts +++ b/package/native-package/src/optionalDependencies/takePhoto.ts @@ -35,7 +35,7 @@ export const takePhoto = ImagePicker mediaType: mediaType, quality: Math.min(Math.max(0, compressImageQuality), 1), }); - if (!result.assets.length) { + if (!result.assets.length || result.didCancel) { return { cancelled: true, }; diff --git a/package/src/components/AttachmentPicker/components/AttachmentPickerItem.tsx b/package/src/components/AttachmentPicker/components/AttachmentPickerItem.tsx index dbac8be91d..8d82932b79 100644 --- a/package/src/components/AttachmentPicker/components/AttachmentPickerItem.tsx +++ b/package/src/components/AttachmentPicker/components/AttachmentPickerItem.tsx @@ -113,7 +113,7 @@ const AttachmentVideo = (props: AttachmentVideoProps) => { )} - + {videoDuration ? ( {durationLabel} diff --git a/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx b/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx index 74c9751fc5..31e0c8c59a 100644 --- a/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx +++ b/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { StyleSheet, TouchableOpacity, View } from 'react-native'; +import { Platform, StyleSheet, TouchableOpacity, View } from 'react-native'; import { useAttachmentPickerContext } from '../../../contexts/attachmentPickerContext/AttachmentPickerContext'; import { useChannelContext } from '../../../contexts/channelContext/ChannelContext'; @@ -7,7 +7,6 @@ import { useMessageInputContext } from '../../../contexts/messageInputContext/Me import { useMessagesContext } from '../../../contexts/messagesContext/MessagesContext'; import { useOwnCapabilitiesContext } from '../../../contexts/ownCapabilitiesContext/OwnCapabilitiesContext'; import { useTheme } from '../../../contexts/themeContext/ThemeContext'; -import { Recorder } from '../../../icons'; const styles = StyleSheet.create({ container: { @@ -30,6 +29,7 @@ export const AttachmentPickerSelectionBar = () => { ImageSelectorIcon, selectedPicker, setSelectedPicker, + VideoRecorderSelectorIcon, } = useAttachmentPickerContext(); const { @@ -49,7 +49,6 @@ export const AttachmentPickerSelectionBar = () => { const { theme: { attachmentSelectionBar: { container, icon }, - colors: { grey }, }, } = useTheme(); @@ -108,7 +107,7 @@ export const AttachmentPickerSelectionBar = () => { { - takeAndUploadImage(); + takeAndUploadImage(Platform.OS === 'android' ? 'image' : 'mixed'); }} testID='take-photo-touchable' > @@ -120,7 +119,7 @@ export const AttachmentPickerSelectionBar = () => { ) : null} - {hasCameraPicker ? ( + {hasCameraPicker && Platform.OS === 'android' ? ( { @@ -128,8 +127,11 @@ export const AttachmentPickerSelectionBar = () => { }} testID='take-photo-touchable' > - - + + ) : null} diff --git a/package/src/components/AttachmentPicker/components/VideoRecorderSelectorIcon.tsx b/package/src/components/AttachmentPicker/components/VideoRecorderSelectorIcon.tsx new file mode 100644 index 0000000000..d1e675f854 --- /dev/null +++ b/package/src/components/AttachmentPicker/components/VideoRecorderSelectorIcon.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +import { useTheme } from '../../../contexts/themeContext/ThemeContext'; +import { Recorder } from '../../../icons'; + +export const VideoRecorderSelectorIcon = () => { + const { + theme: { + colors: { grey }, + }, + } = useTheme(); + + return ; +}; diff --git a/package/src/components/MessageInput/components/NativeAttachmentPicker.tsx b/package/src/components/MessageInput/components/NativeAttachmentPicker.tsx index 0541aa66aa..650a48cc37 100644 --- a/package/src/components/MessageInput/components/NativeAttachmentPicker.tsx +++ b/package/src/components/MessageInput/components/NativeAttachmentPicker.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useRef } from 'react'; -import { Animated, Easing, LayoutRectangle, Pressable, StyleSheet } from 'react-native'; +import { Animated, Easing, LayoutRectangle, Platform, Pressable, StyleSheet } from 'react-native'; import { + useAttachmentPickerContext, useChannelContext, useMessagesContext, useOwnCapabilitiesContext, @@ -9,11 +10,7 @@ import { import { useMessageInputContext } from '../../../contexts/messageInputContext/MessageInputContext'; import { useTheme } from '../../../contexts/themeContext/ThemeContext'; -import { CameraSelectorIcon } from '../../AttachmentPicker/components/CameraSelectorIcon'; -import { FileSelectorIcon } from '../../AttachmentPicker/components/FileSelectorIcon'; -import { ImageSelectorIcon } from '../../AttachmentPicker/components/ImageSelectorIcon'; import { CreatePollIcon } from '../../Poll/components/CreatePollIcon'; -import { Recorder } from '../../../icons'; type NativeAttachmentPickerProps = { onRequestedClose: () => void; @@ -29,10 +26,9 @@ export const NativeAttachmentPicker = ({ }: NativeAttachmentPickerProps) => { const size = attachButtonLayoutRectangle?.width ?? 0; const attachButtonItemSize = 40; - const NUMBER_OF_BUTTONS = 5; const { theme: { - colors: { grey, grey_whisper }, + colors: { grey_whisper }, messageInput: { nativeAttachmentPicker: { buttonContainer, @@ -55,14 +51,16 @@ export const NativeAttachmentPicker = ({ const { threadList } = useChannelContext(); const { hasCreatePoll } = useMessagesContext(); const ownCapabilities = useOwnCapabilitiesContext(); + const { CameraSelectorIcon, FileSelectorIcon, ImageSelectorIcon, VideoRecorderSelectorIcon } = + useAttachmentPickerContext(); const popupHeight = // the top padding TOP_PADDING + // take margins into account - ATTACH_MARGIN_BOTTOM * NUMBER_OF_BUTTONS + + ATTACH_MARGIN_BOTTOM + // the size of the attachment icon items (same size as attach button * amount of attachment button types) - attachButtonItemSize * NUMBER_OF_BUTTONS; + attachButtonItemSize; const containerPopupStyle = { borderTopEndRadius: size / 2, @@ -148,15 +146,19 @@ export const NativeAttachmentPicker = ({ buttons.push({ icon: , id: 'Camera', - onPressHandler: takeAndUploadImage, - }); - buttons.push({ - icon: , - id: 'Video', onPressHandler: () => { - takeAndUploadImage('video'); + takeAndUploadImage(Platform.OS === 'android' ? 'image' : 'mixed'); }, }); + if (Platform.OS === 'android') { + buttons.push({ + icon: , + id: 'Video', + onPressHandler: () => { + takeAndUploadImage('video'); + }, + }); + } } return ( diff --git a/package/src/components/index.ts b/package/src/components/index.ts index 942641fb33..53530161a5 100644 --- a/package/src/components/index.ts +++ b/package/src/components/index.ts @@ -17,6 +17,7 @@ export * from './AttachmentPicker/components/AttachmentPickerErrorImage'; export * from './AttachmentPicker/components/AttachmentPickerSelectionBar'; export * from './AttachmentPicker/components/CameraSelectorIcon'; export * from './AttachmentPicker/components/FileSelectorIcon'; +export * from './AttachmentPicker/components/VideoRecorderSelectorIcon'; export * from './AttachmentPicker/components/ImageOverlaySelectedComponent'; export * from './AttachmentPicker/components/ImageSelectorIcon'; diff --git a/package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx b/package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx index be89752c64..0e7fdf13ee 100644 --- a/package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx +++ b/package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx @@ -8,7 +8,7 @@ import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue'; import { isTestEnvironment } from '../utils/isTestEnvironment'; export type AttachmentPickerIconProps = { - numberOfImageUploads: number; + numberOfImageUploads?: number; selectedPicker?: 'images'; }; @@ -90,6 +90,12 @@ export type AttachmentPickerContextValue = { setSelectedPicker: React.Dispatch>; setTopInset: React.Dispatch>; topInset: number; + /** + * Custom UI component for Android's video recorder selector icon. + * + * **Default: ** [VideoRecorderSelectorIcon](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/AttachmentPicker/components/VideoRecorderSelectorIcon.tsx) + */ + VideoRecorderSelectorIcon: React.ComponentType; selectedPicker?: 'images'; }; @@ -109,6 +115,7 @@ export const AttachmentPickerProvider = ({ | 'FileSelectorIcon' | 'ImageSelectorIcon' | 'openPicker' + | 'VideoRecorderSelectorIcon' > & Partial>; }>) => { diff --git a/package/src/contexts/overlayContext/OverlayContext.tsx b/package/src/contexts/overlayContext/OverlayContext.tsx index 5e8de871ef..b0e9769c8b 100644 --- a/package/src/contexts/overlayContext/OverlayContext.tsx +++ b/package/src/contexts/overlayContext/OverlayContext.tsx @@ -44,6 +44,7 @@ export type OverlayProviderProps< | 'FileSelectorIcon' | 'ImageSelectorIcon' | 'topInset' + | 'VideoRecorderSelectorIcon' > > & ImageGalleryCustomComponents & { diff --git a/package/src/contexts/overlayContext/OverlayProvider.tsx b/package/src/contexts/overlayContext/OverlayProvider.tsx index dd812f6ce6..7a9e4fcf7c 100644 --- a/package/src/contexts/overlayContext/OverlayProvider.tsx +++ b/package/src/contexts/overlayContext/OverlayProvider.tsx @@ -19,6 +19,7 @@ import { CameraSelectorIcon as DefaultCameraSelectorIcon } from '../../component import { FileSelectorIcon as DefaultFileSelectorIcon } from '../../components/AttachmentPicker/components/FileSelectorIcon'; import { ImageOverlaySelectedComponent as DefaultImageOverlaySelectedComponent } from '../../components/AttachmentPicker/components/ImageOverlaySelectedComponent'; import { ImageSelectorIcon as DefaultImageSelectorIcon } from '../../components/AttachmentPicker/components/ImageSelectorIcon'; +import { VideoRecorderSelectorIcon as DefaultVideoRecorderSelectorIcon } from '../../components/AttachmentPicker/components/VideoRecorderSelectorIcon'; import { ImageGallery } from '../../components/ImageGallery/ImageGallery'; import { CreatePollIcon as DefaultCreatePollIcon } from '../../components/Poll/components/CreatePollIcon'; import { useStreami18n } from '../../hooks/useStreami18n'; @@ -116,6 +117,7 @@ export const OverlayProvider = < }, topInset, value, + VideoRecorderSelectorIcon = DefaultVideoRecorderSelectorIcon, } = props; const attachmentPickerProps = { @@ -192,6 +194,7 @@ export const OverlayProvider = < ImageSelectorIcon, openPicker: () => openPicker(bottomSheetRef), topInset, + VideoRecorderSelectorIcon, }; const overlayContext = { diff --git a/package/src/icons/Recorder.tsx b/package/src/icons/Recorder.tsx index c1ac26b9c8..a902113e92 100644 --- a/package/src/icons/Recorder.tsx +++ b/package/src/icons/Recorder.tsx @@ -2,15 +2,11 @@ import React from 'react'; import { IconProps, RootPath, RootSvg } from './utils/base'; -export const Recorder = (props: IconProps) => ( - +export const Recorder = ({ ...rest }: IconProps) => ( + - );