diff --git a/CHANGELOG.md b/CHANGELOG.md index 12f533b1977..c52f218ee4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - fixed: ramps: Various Infinite UI/UX issues - fixed: Search keyboard not dismissing when submitting search - fixed: Auto-correct not disabled for search input +- fixed: In-app review for iOS 18+ ## 4.41.1 (2025-12-29) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 20b865b9109..2988b82b12e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3475,7 +3475,7 @@ SPEC CHECKSUMS: RNSentry: 19b4ee2a31886bcc5a64698a27cf8495cb8f5d17 RNShare: 6300b941668273d502ecee9122cade0d5ea966bd RNSound: cfeaf6c6a734303c887e04b946cbb7e294bff123 - RNStoreReview: 8b47d208282c23296d2466a488a8d9ca1979d79b + RNStoreReview: b3cb7df1405d56afd51301ada4660f6c9b970055 RNSVG: ca807495c5219c05c747254200b89a4e3078db31 RNVectorIcons: f1bc9e04b6f67ec09ea54e6f092e75a9e205c1d7 RNWorklets: b1faafefb82d9f29c4018404a0fb33974b494a7b diff --git a/package.json b/package.json index 748a6fecfc6..8d0a849b088 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ "react-native-securerandom": "^1.0.1", "react-native-share": "^12.0.11", "react-native-sound": "^0.12.0", - "react-native-store-review": "^0.4.3", + "react-native-store-review": "https://github.com/dylancom/react-native-store-review#575f49229de2439095205b3cd17babea31972c95", "react-native-svg": "^15.12.1", "react-native-vector-icons": "^10.1.0", "react-native-vision-camera": "^4.7.2", diff --git a/patches/react-native-store-review+0.4.3.patch b/patches/react-native-store-review+0.4.3.patch new file mode 100644 index 00000000000..187e35681c8 --- /dev/null +++ b/patches/react-native-store-review+0.4.3.patch @@ -0,0 +1,27 @@ +diff --git a/node_modules/react-native-store-review/RNStoreReview.podspec b/node_modules/react-native-store-review/RNStoreReview.podspec +index 1234567..abcdefg 100644 +--- a/node_modules/react-native-store-review/RNStoreReview.podspec ++++ b/node_modules/react-native-store-review/RNStoreReview.podspec +@@ -14,6 +14,10 @@ Pod::Spec.new do |s| + s.preserve_paths = "**/*.js" + s.ios.framework = 'StoreKit' + s.requires_arc = true ++ s.pod_target_xcconfig = { ++ 'DEFINES_MODULE' => 'YES', ++ 'SWIFT_VERSION' => '5.0' ++ } + + s.dependency "React-Core" + +diff --git a/node_modules/react-native-store-review/ios/RNStoreReview.mm b/node_modules/react-native-store-review/ios/RNStoreReview.mm +index 2345678..bcdefgh 100644 +--- a/node_modules/react-native-store-review/ios/RNStoreReview.mm ++++ b/node_modules/react-native-store-review/ios/RNStoreReview.mm +@@ -1,6 +1,6 @@ + #import "RNStoreReview.h" + +-#import "RNStoreReview-Swift.h" ++#import + + @implementation RNStoreReview + diff --git a/src/components/modals/ScanModal.tsx b/src/components/modals/ScanModal.tsx index 60dd347a7aa..242bd5475f6 100644 --- a/src/components/modals/ScanModal.tsx +++ b/src/components/modals/ScanModal.tsx @@ -35,7 +35,7 @@ import { checkAndRequestPermission } from '../services/PermissionsManager' import { cacheStyles, type Theme, useTheme } from '../services/ThemeContext' import { EdgeText, Paragraph } from '../themed/EdgeText' import { ModalFooter } from '../themed/ModalParts' -import { SceneHeader } from '../themed/SceneHeader' +import { SceneHeaderUi4 } from '../themed/SceneHeaderUi4' import { EdgeModal } from './EdgeModal' interface Props { @@ -52,7 +52,7 @@ interface Props { textModalTitle?: string } -export const ScanModal = (props: Props) => { +export const ScanModal: React.FC = props => { const { bridge, textModalAutoFocus, @@ -75,11 +75,14 @@ export const ScanModal = (props: Props) => { handleBarCodeRead(codes) } }) - const cameraPermission = useSelector(state => state.permissions.camera) + const reduxCameraPermission = useSelector(state => state.permissions.camera) + const [cameraPermission, setCameraPermission] = React.useState( + reduxCameraPermission + ) const [torchEnabled, setTorchEnabled] = React.useState(false) const [scanEnabled, setScanEnabled] = React.useState(false) - const handleFlash = () => { + const handleFlash = (): void => { triggerHaptic('impactLight') setTorchEnabled(!torchEnabled) } @@ -87,26 +90,28 @@ export const ScanModal = (props: Props) => { // Mount effects React.useEffect(() => { setScanEnabled(true) - checkAndRequestPermission('camera').catch(err => { - showError(err) - }) + checkAndRequestPermission('camera') + .then(status => { + setCameraPermission(status) + }) + .catch(showError) return () => { setScanEnabled(false) } }, []) - const handleBarCodeRead = (codes: Code[]) => { + const handleBarCodeRead = (codes: Code[]): void => { setScanEnabled(false) triggerHaptic('impactLight') bridge.resolve(codes[0].value) } - const handleSettings = async () => { + const handleSettings = async (): Promise => { triggerHaptic('impactLight') await Linking.openSettings() } - const handleTextInput = async () => { + const handleTextInput = async (): Promise => { triggerHaptic('impactLight') const uri = await Airship.show(bridge => ( { } } - const handleAlbum = () => { + const handleAlbum = (): void => { triggerHaptic('impactLight') launchImageLibrary( { mediaType: 'photo' }, result => { - if (result.didCancel) return + if (result.didCancel === true) return - if (result.errorMessage) { + if (result.errorMessage != null && result.errorMessage !== '') { showDevError(result.errorMessage) return } @@ -157,18 +162,14 @@ export const ScanModal = (props: Props) => { logActivity(`QR code read from photo library.`) bridge.resolve(response.values[0]) }) - .catch(error => { - showDevError(error) - }) + .catch(showDevError) } - ).catch(err => { - showError(err) - }) + ).catch(showError) } - const handleClose = () => { + const handleClose = (): void => { triggerHaptic('impactLight') - // @ts-expect-error + // @ts-expect-error - AirshipBridge expects string | undefined but resolve() with no args is valid bridge.resolve() } @@ -186,7 +187,7 @@ export const ScanModal = (props: Props) => { headerContainerLayout.height + (peepholeSpaceLayout.height - holeSize) / 2 - const renderModalContent = () => { + const renderModalContent = (): React.JSX.Element | null => { if (!scanEnabled) { return null } @@ -223,7 +224,9 @@ export const ScanModal = (props: Props) => { style={styles.headerContainer} onLayout={handleLayoutHeaderContainer} > - + {/* This isn't technically a scene, so just using SceneHeaderUi4 directly for simplicity. */} + {/* eslint-disable-next-line @typescript-eslint/no-deprecated */} + ({ }, headerContainer: { justifyContent: 'flex-end', - marginBottom: theme.rem(0.5), - marginTop: theme.rem(1) + marginTop: theme.rem(2), + marginLeft: theme.rem(0.5) }, peepholeSpace: { flex: 2 diff --git a/src/components/scenes/HomeScene.tsx b/src/components/scenes/HomeScene.tsx index 36b1376b564..a6306b9c405 100644 --- a/src/components/scenes/HomeScene.tsx +++ b/src/components/scenes/HomeScene.tsx @@ -4,6 +4,7 @@ import { View } from 'react-native' import FastImage from 'react-native-fast-image' import Animated from 'react-native-reanimated' import { useSafeAreaFrame } from 'react-native-safe-area-context' +import { requestReview } from 'react-native-store-review/src' import { SCROLL_INDICATOR_INSET_FIX } from '../../constants/constantSettings' import { ENV } from '../../env' @@ -146,6 +147,8 @@ export const HomeScene: React.FC = props => { setVideoPosts( filterContentPosts(infoServerData.rollup?.videoPosts, countryCode) ) + + requestReview() }, [countryCode]) const buyCryptoIcon = React.useMemo( diff --git a/yarn.lock b/yarn.lock index 384da653ce0..f87e8b0629c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16241,10 +16241,9 @@ react-native-sound@^0.12.0: resolved "https://registry.yarnpkg.com/react-native-sound/-/react-native-sound-0.12.0.tgz#c1502e7760efa7ca06c38b8ae0435518eae33ef8" integrity sha512-uOtM/PJ8+xmuXwgS2WMYEcokE/oFE8MV6glZHmB5RYHZ+yzD/0Z7cDL+QJpetTYBbEFOirfcE42o6YfPMJfJfg== -react-native-store-review@^0.4.3: +"react-native-store-review@https://github.com/dylancom/react-native-store-review#575f49229de2439095205b3cd17babea31972c95": version "0.4.3" - resolved "https://registry.yarnpkg.com/react-native-store-review/-/react-native-store-review-0.4.3.tgz#a524374b1a897b1de1b05d6257640296f1693e3c" - integrity sha512-RSQ6vx2j4p41GwTqNv2VV7yold62j5qDbGEBAjFi6gkXMrMpxFMg+82FPjbh6012tqv6Ebzwfqw6S4m4d7sddw== + resolved "https://github.com/dylancom/react-native-store-review#575f49229de2439095205b3cd17babea31972c95" react-native-svg-transformer@^1.5.1: version "1.5.1"