diff --git a/shared/chat/audio/audio-recorder.native.tsx b/shared/chat/audio/audio-recorder.native.tsx index e244f984f326..517fc30b1190 100644 --- a/shared/chat/audio/audio-recorder.native.tsx +++ b/shared/chat/audio/audio-recorder.native.tsx @@ -22,9 +22,10 @@ import logger from '@/logger' import * as Haptics from 'expo-haptics' import * as FileSystem from 'expo-file-system' import AudioSend from './audio-send.native' +import {scheduleOnRN} from 'react-native-worklets' const {useSharedValue, Extrapolation, useAnimatedStyle} = Reanimated -const {interpolate, withSequence, withSpring, runOnJS} = Reanimated +const {interpolate, withSequence, withSpring} = Reanimated const {useAnimatedReaction, withDelay, withTiming, interpolateColor, default: Animated} = Reanimated type SVN = Reanimated.SharedValue @@ -80,7 +81,7 @@ const useTooltip = () => { const flashTip = React.useCallback(() => { 'worklet' - runOnJS(setShowTooltip)(true) + scheduleOnRN(setShowTooltip, true) }, [setShowTooltip]) return {flashTip, tooltip} @@ -113,11 +114,11 @@ const useIconAndOverlay = (p: { if (f === 0) { if (fadeSyncedSV.value !== 0) { fadeSyncedSV.set(0) - runOnJS(setVisible)(Visible.HIDDEN) + scheduleOnRN(setVisible, Visible.HIDDEN) } } else if (fadeSyncedSV.value !== 1) { fadeSyncedSV.set(1) - runOnJS(setVisible)(Visible.SHOW) + scheduleOnRN(setVisible, Visible.SHOW) } } ) @@ -192,7 +193,7 @@ const useIconAndOverlay = (p: { .maxPointers(1) .onTouchesDown(() => { 'worklet' - runOnJS(setupOverlayTimeout)() + scheduleOnRN(setupOverlayTimeout) if (!panStartSV.value) { panStartSV.set(Date.now()) } @@ -202,22 +203,22 @@ const useIconAndOverlay = (p: { const diff = Date.now() - panStartSV.value startedSV.set(0) panStartSV.set(0) - runOnJS(cleanupOverlayTimeout)() + scheduleOnRN(cleanupOverlayTimeout) const needTip = diff < 200 const wasCancel = canceledSV.value === 1 const panLocked = lockedSV.value === 1 if (wasCancel) { - runOnJS(onCancelRecording)() + scheduleOnRN(onCancelRecording) return } if (needTip) { - runOnJS(onFlashTip)() + scheduleOnRN(onFlashTip) return } if (!panLocked) { - runOnJS(sendRecording)() + scheduleOnRN(sendRecording) onReset() fadeSV.set(withTiming(0, {duration: 200})) } diff --git a/shared/common-adapters/zoomable-image.native.tsx b/shared/common-adapters/zoomable-image.native.tsx index 49c99c978dcf..dd2e1291af85 100644 --- a/shared/common-adapters/zoomable-image.native.tsx +++ b/shared/common-adapters/zoomable-image.native.tsx @@ -3,7 +3,8 @@ import * as Styles from '@/styles' import * as React from 'react' import Image2 from './image2.native' import {View, type LayoutChangeEvent} from 'react-native' -import {useSharedValue, runOnJS} from 'react-native-reanimated' +import {useSharedValue} from 'react-native-reanimated' +import {scheduleOnRN} from 'react-native-worklets' import { fitContainer, ResumableZoom, @@ -37,12 +38,13 @@ const ZoomableImage = React.memo(function ZoomableImage(p: Props) { x: left, y: top, } - runOnJS(onZoom)(z) + scheduleOnRN(onZoom, z) } }, [currentZoomSV, onZoom, resolution] ) + // not a worklet const onSwipe = React.useCallback( (dir: SwipeDirection) => { if (Math.abs(currentZoomSV.get() - 1) < 0.1) { diff --git a/shared/ios/Keybase/AppDelegate.swift b/shared/ios/Keybase/AppDelegate.swift index 67f0802df4f8..50c7f9c74e0f 100644 --- a/shared/ios/Keybase/AppDelegate.swift +++ b/shared/ios/Keybase/AppDelegate.swift @@ -12,22 +12,22 @@ import Keybasego @UIApplicationMain public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UIDropInteractionDelegate { var window: UIWindow? - + var reactNativeDelegate: ExpoReactNativeFactoryDelegate? var reactNativeFactory: RCTReactNativeFactory? - + var resignImageView: UIImageView? var fsPaths: [String: String] = [:] var shutdownTask: UIBackgroundTaskIdentifier = .invalid var iph: ItemProviderHelper? var hwKeyEvent: RNHWKeyboardEvent? - + public override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { self.didLaunchSetupBefore() - + NotificationCenter.default.addObserver(forName: UIApplication.didReceiveMemoryWarningNotification, object: nil, queue: .main) { notification in NSLog("Memory warning received - deferring GC during React Native initialization") // see if this helps avoid this crash @@ -37,15 +37,15 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID } } } - + let delegate = ReactNativeDelegate() let factory = ExpoReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() - + reactNativeDelegate = delegate reactNativeFactory = factory bindReactNativeFactory(factory) - + #if os(iOS) || os(tvOS) window = UIWindow(frame: UIScreen.main.bounds) factory.startReactNative( @@ -53,17 +53,17 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID in: window, launchOptions: launchOptions) #endif - + _ = super.application(application, didFinishLaunchingWithOptions: launchOptions) - + if let rootView = self.window?.rootViewController?.view { self.addDrop(rootView) self.didLaunchSetupAfter(application: application, rootView: rootView) } - + return true } - + // Linking API public override func application( _ app: UIApplication, @@ -72,7 +72,7 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID ) -> Bool { return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options) } - + // Universal Links public override func application( _ application: UIApplication, @@ -82,9 +82,9 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler) return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result } - + /////// KB specific - + func setupGo() { // set to true to see logs in xcode let skipLogFile = false @@ -92,18 +92,18 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID // RCTSetLogThreshold(RCTLogLevel.info.rawValue - 1) self.fsPaths = FsHelper().setupFs(skipLogFile, setupSharedHome: true) FsPathsHolder.shared().fsPaths = self.fsPaths - - + + let systemVer = UIDevice.current.systemVersion let isIPad = UIDevice.current.userInterfaceIdiom == .pad let isIOS = true - + #if targetEnvironment(simulator) let securityAccessGroupOverride = true #else let securityAccessGroupOverride = false #endif - + DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } var err: NSError? @@ -111,7 +111,7 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID if let err { NSLog("KeybaseInit fail?: \(err)") } } } - + func notifyAppState(_ application: UIApplication) { let state = application.applicationState NSLog("notifyAppState: notifying service with new appState: \(state.rawValue)") @@ -122,18 +122,18 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID default: Keybasego.KeybaseSetAppStateForeground() } } - + func didLaunchSetupBefore() { try? AVAudioSession.sharedInstance().setCategory(.ambient) UNUserNotificationCenter.current().delegate = self } - + func didLaunchSetupAfter(application: UIApplication, rootView: UIView) { setupGo() notifyAppState(application) - + rootView.backgroundColor = .systemBackground - + // Snapshot resizing workaround for iPad var dim = UIScreen.main.bounds.width if UIScreen.main.bounds.height > dim { @@ -146,28 +146,28 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID self.resignImageView?.backgroundColor = rootView.backgroundColor self.resignImageView?.image = UIImage(named: "LaunchImage") self.window?.addSubview(self.resignImageView!) - + UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum) } - + func addDrop(_ rootView: UIView) { let dropInteraction = UIDropInteraction(delegate: self) dropInteraction.allowsSimultaneousDropSessions = true rootView.addInteraction(dropInteraction) } - + public func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool { return true } - + public func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal { return UIDropProposal(operation: .copy) } - + public func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) { var items: [NSItemProvider] = [] session.items.forEach { item in items.append(item.itemProvider) } - + self.iph = ItemProviderHelper(forShare: false, withItems: [items]) { [weak self] in guard let self else { return } let url = URL(string: "keybase://incoming-share")! @@ -176,7 +176,7 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID } self.iph?.startProcessing() } - + public override func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { NSLog("Background fetch started...") DispatchQueue.global(qos: .default).async { @@ -185,15 +185,15 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID NSLog("Background fetch completed...") } } - + func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) { RNCPushNotificationIOS.didRegister(notificationSettings) } - + public override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { RNCPushNotificationIOS.didRegisterForRemoteNotifications(withDeviceToken: deviceToken) } - + public override func application(_ application: UIApplication, didReceiveRemoteNotification notification: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { guard let type = notification["type"] as? String else { return } if type == "chat.newmessageSilent_2" { @@ -209,7 +209,7 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID let membersType = (notification["t"] as? NSNumber)?.intValue ?? 0 let sender = notification["u"] as? String let pusher = PushNotifier() - + var err: NSError? Keybasego.KeybaseHandleBackgroundNotification(convID, body, "", sender, membersType, displayPlaintext, messageID, pushID, badgeCount, unixTime, soundName, pusher, false, &err) if let err { NSLog("Failed to handle in engine: \(err)") } @@ -221,16 +221,16 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID completionHandler(.newData) } } - + public override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { RNCPushNotificationIOS.didFailToRegisterForRemoteNotificationsWithError(error) } - + public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { RNCPushNotificationIOS.didReceive(response) completionHandler() } - + public func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, @@ -238,18 +238,18 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID ) { completionHandler([]) } - + public override func applicationWillTerminate(_ application: UIApplication) { self.window?.rootViewController?.view.isHidden = true Keybasego.KeybaseAppWillExit(PushNotifier()) } - + func hideCover() { NSLog("hideCover: cancelling outstanding animations...") self.resignImageView?.layer.removeAllAnimations() self.resignImageView?.alpha = 0 } - + public override func applicationWillResignActive(_ application: UIApplication) { NSLog("applicationWillResignActive: cancelling outstanding animations...") self.resignImageView?.layer.removeAllAnimations() @@ -262,18 +262,18 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID } Keybasego.KeybaseSetAppStateInactive() } - + public override func applicationDidEnterBackground(_ application: UIApplication) { application.ignoreSnapshotOnNextApplicationLaunch() NSLog("applicationDidEnterBackground: cancelling outstanding animations...") self.resignImageView?.layer.removeAllAnimations() NSLog("applicationDidEnterBackground: setting keyz screen alpha to 1.") self.resignImageView?.alpha = 1 - + NSLog("applicationDidEnterBackground: notifying go.") let requestTime = Keybasego.KeybaseAppDidEnterBackground() NSLog("applicationDidEnterBackground: after notifying go.") - + if requestTime && (self.shutdownTask == UIBackgroundTaskIdentifier.invalid) { let app = UIApplication.shared self.shutdownTask = app.beginBackgroundTask { @@ -285,7 +285,7 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID self.shutdownTask = .invalid } } - + DispatchQueue.global(qos: .default).async { Keybasego.KeybaseAppBeginBackgroundTask(PushNotifier()) let task = self.shutdownTask @@ -296,19 +296,19 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID } } } - + public override func applicationDidBecomeActive(_ application: UIApplication) { NSLog("applicationDidBecomeActive: hiding keyz screen.") hideCover() NSLog("applicationDidBecomeActive: notifying service.") notifyAppState(application) } - + public override func applicationWillEnterForeground(_ application: UIApplication) { NSLog("applicationWillEnterForeground: hiding keyz screen.") hideCover() } - + func keyCommands() -> [UIKeyCommand]? { var keys = [UIKeyCommand]() if hwKeyEvent == nil { @@ -320,11 +320,11 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID } return keys } - + @objc func sendEnter(_ sender: UIKeyCommand) { (hwKeyEvent)?.sendHWKeyEvent("enter") } - + @objc func sendShiftEnter(_ sender: UIKeyCommand) { (hwKeyEvent)?.sendHWKeyEvent("shift-enter") } @@ -332,12 +332,12 @@ public class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate, UID class ReactNativeDelegate: ExpoReactNativeFactoryDelegate { // Extension point for config-plugins - + override func sourceURL(for bridge: RCTBridge) -> URL? { // needed to return the correct URL for expo-dev-client. bridge.bundleURL ?? bundleURL() } - + override func bundleURL() -> URL? { #if DEBUG return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry") diff --git a/shared/ios/Keybase/Info.plist b/shared/ios/Keybase/Info.plist index e33f5da0bec0..9b1c0e22a66d 100644 --- a/shared/ios/Keybase/Info.plist +++ b/shared/ios/Keybase/Info.plist @@ -114,5 +114,7 @@ UIDesignRequiresCompatibility + ReactNativeReleaseLevel + experimental diff --git a/shared/ios/ReanimatedFeatures.h b/shared/ios/ReanimatedFeatures.h new file mode 100644 index 000000000000..a0c7372a199a --- /dev/null +++ b/shared/ios/ReanimatedFeatures.h @@ -0,0 +1,6 @@ +#ifndef REANIMATED_FEATURES_H +#define REANIMATED_FEATURES_H + +#define DISABLE_COMMIT_PAUSING_MECHANISM 1 + +#endif // REANIMATED_FEATURES_H diff --git a/shared/team-building/filtered-service-tab-bar.tsx b/shared/team-building/filtered-service-tab-bar.tsx index 14171ac3546f..e0317adcde0d 100644 --- a/shared/team-building/filtered-service-tab-bar.tsx +++ b/shared/team-building/filtered-service-tab-bar.tsx @@ -9,7 +9,7 @@ export const FilteredServiceTabBar = ( } ) => { const {selectedService, onChangeService} = props - const {servicesShown, minimalBorder, offset, filterServices} = props + const {servicesShown, minimalBorder, filterServices} = props const services = React.useMemo( () => @@ -25,7 +25,6 @@ export const FilteredServiceTabBar = ( onChangeService={onChangeService} servicesShown={servicesShown} minimalBorder={minimalBorder} - offset={offset} /> ) } diff --git a/shared/team-building/index.tsx b/shared/team-building/index.tsx index 9bc2fcf20876..dc33b5ed4716 100644 --- a/shared/team-building/index.tsx +++ b/shared/team-building/index.tsx @@ -13,7 +13,6 @@ import {ListBody} from './list-body' import {serviceIdToSearchPlaceholder} from './shared' import {FilteredServiceTabBar} from './filtered-service-tab-bar' import {modalHeaderProps} from './modal-header-props' -import {useSharedValue} from '@/common-adapters/reanimated' const deriveTeamSoFar = (teamSoFar: ReadonlySet): Array => [...teamSoFar].map(userInfo => { @@ -166,8 +165,6 @@ const TeamBuilding = (p: OwnProps) => { const waitingForCreate = C.Waiting.useAnyWaiting(C.Chat.waitingKeyCreating) - const offset = useSharedValue(0) - C.useOnMountOnce(() => { fetchUserRecs() }) @@ -213,7 +210,6 @@ const TeamBuilding = (p: OwnProps) => { onChangeService={onChangeService} servicesShown={5} // wider bar, show more services minimalBorder={true} // only show bottom border on icon when active - offset={offset} /> )} { teamSoFar={teamSoFar} onChangeText={onChangeText} onSearchForMore={onSearchForMore} - offset={offset} onFinishTeamBuilding={onFinishTeamBuilding} /> {waitingForCreate && ( @@ -279,7 +274,6 @@ const TeamBuilding = (p: OwnProps) => { filterServices={filterServices} selectedService={selectedService} onChangeService={onChangeService} - offset={offset} /> )} {showContactsBanner && ( diff --git a/shared/team-building/list-body.tsx b/shared/team-building/list-body.tsx index 897c1057e8a5..d2af4a0f47e2 100644 --- a/shared/team-building/list-body.tsx +++ b/shared/team-building/list-body.tsx @@ -212,7 +212,6 @@ export const ListBody = ( | 'onChangeText' | 'onFinishTeamBuilding' > & { - offset: unknown enterInputCounter: number } ) => { @@ -221,7 +220,7 @@ export const ListBody = ( const teamID = params.teamID const {searchString, selectedService} = props const {onAdd, onRemove, teamSoFar, onSearchForMore, onChangeText} = props - const {namespace, highlightedIndex, /*offset, */ enterInputCounter, onFinishTeamBuilding} = props + const {namespace, highlightedIndex, enterInputCounter, onFinishTeamBuilding} = props const contactsImported = C.useSettingsContactsState(s => s.importEnabled) const contactsPermissionStatus = C.useSettingsContactsState(s => s.permissionStatus) diff --git a/shared/team-building/service-tab-bar.d.ts b/shared/team-building/service-tab-bar.d.ts index 6dc77c28bbd2..ae1803494085 100644 --- a/shared/team-building/service-tab-bar.d.ts +++ b/shared/team-building/service-tab-bar.d.ts @@ -1,6 +1,5 @@ import type * as React from 'react' import type * as T from '@/constants/types' -import type {SharedValue} from '@/common-adapters/reanimated' export type Props = { services: Array @@ -8,7 +7,6 @@ export type Props = { onChangeService: (newService: T.TB.ServiceIdWithContact) => void servicesShown?: number minimalBorder?: boolean - offset?: SharedValue } export type IconProps = { @@ -17,7 +15,6 @@ export type IconProps = { onClick: (s: T.TB.ServiceIdWithContact) => void isActive: boolean minimalBorder?: boolean - offset?: SharedValue } export declare const ServiceTabBar: (p: Props) => React.ReactNode diff --git a/shared/team-building/service-tab-bar.native.tsx b/shared/team-building/service-tab-bar.native.tsx index 93b3d5f6bb39..f59e526f830f 100644 --- a/shared/team-building/service-tab-bar.native.tsx +++ b/shared/team-building/service-tab-bar.native.tsx @@ -2,118 +2,43 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import {serviceIdToIconFont, serviceIdToAccentColor, serviceIdToLongLabel, serviceIdToBadge} from './shared' import type * as T from '@/constants/types' -import {ScrollView} from 'react-native' import type {Props, IconProps} from './service-tab-bar' import { + default as Animated, useSharedValue, useAnimatedStyle, - interpolate, withSpring, withDelay, - withTiming, - Extrapolation, - type SharedValue, - createAnimatedComponent, } from '@/common-adapters/reanimated' export const labelHeight = 34 -const serviceMinWidthWhenSmall = (containerWidth: number) => { - const minWidth = 70 - if (containerWidth <= minWidth) { - return minWidth - } - const p = containerWidth / minWidth // count that would fit onscreen at ideal size - let n = Math.floor(p) + 0.5 - if (p % 1 < 0.5) { - n -= 1 - } - // n = count that will fit onscreen at returned size - return containerWidth / n -} - -const smallWidth = serviceMinWidthWhenSmall(Kb.Styles.dimensionWidth) -const bigWidth = Math.max(smallWidth, 92) -const AnimatedBox2 = Kb.Box2Animated -const AnimatedScrollView = createAnimatedComponent(ScrollView) - // On tablet add an additional "service" item that is only a bottom border that extends to the end of the ScrollView -const TabletBottomBorderExtension = React.memo(function TabletBottomBorderExtension(props: { - offset?: SharedValue - servicesCount: number -}) { - 'use no memo' - const {offset} = props - - const borderColor = Kb.Styles.undynamicColor(Kb.Styles.globalColors.black_10) - const animatedStyles = useAnimatedStyle(() => { - const translateY = offset - ? interpolate(offset.value, [0, 100], [0, -8], { - extrapolateLeft: Extrapolation.CLAMP, - extrapolateRight: Extrapolation.CLAMP, - }) - : 0 - return {borderColor, transform: [{translateY}]} - }) - +const TabletBottomBorderExtension = React.memo(function TabletBottomBorderExtension() { return ( - ) }) const ServiceIcon = React.memo(function ServiceIcon(props: IconProps) { - 'use no memo' - const {offset, isActive, service, label, onClick} = props + const {isActive, service, label, onClick} = props const color = isActive ? serviceIdToAccentColor(service) : Kb.Styles.globalColors.black - const animatedWidth = useAnimatedStyle(() => { - const width = offset - ? withTiming( - interpolate(offset.value, [-100, 0, 100], [bigWidth + 5, bigWidth, smallWidth], { - extrapolateLeft: Extrapolation.CLAMP, - extrapolateRight: Extrapolation.CLAMP, - }), - {duration: 10} - ) - : 0 - return {width} - }) - const animatedOpacity = useAnimatedStyle(() => { - const opacity = offset - ? interpolate(offset.value, [0, 40], [1, 0], { - extrapolateLeft: Extrapolation.CLAMP, - extrapolateRight: Extrapolation.CLAMP, - }) - : 0 - return {opacity} - }) - const animatedTransform = useAnimatedStyle(() => { - const translateY = offset - ? interpolate(offset.value, [0, 100], [0, -8], { - extrapolateLeft: Extrapolation.CLAMP, - extrapolateRight: Extrapolation.CLAMP, - }) - : 0 - return {transform: [{translateY}]} - }) - return ( onClick(service)} style={{position: 'relative'}}> - + {serviceIdToBadge(service) && ( - + {label.map((label, i) => ( @@ -136,16 +61,15 @@ const ServiceIcon = React.memo(function ServiceIcon(props: IconProps) { ))} - - - + + @@ -154,7 +78,7 @@ const ServiceIcon = React.memo(function ServiceIcon(props: IconProps) { export const ServiceTabBar = (props: Props) => { 'use no memo' - const {onChangeService, offset, services, selectedService} = props + const {onChangeService, services, selectedService} = props const bounceX = useSharedValue(40) const onClick = React.useCallback( (service: T.TB.ServiceIdWithContact) => { @@ -169,28 +93,12 @@ export const ServiceTabBar = (props: Props) => { const animatedStyles = useAnimatedStyle(() => { const translateX = withDelay(100, withSpring(bounceX.value, {})) - const translateY = offset - ? interpolate(offset.value, [0, 100], [0, 8], { - extrapolateLeft: Extrapolation.CLAMP, - extrapolateRight: Extrapolation.CLAMP, - }) - : 0 - // withTiming workaround due to https://github.com/software-mansion/react-native-reanimated/issues/1947#issuecomment-942413134 - const height = offset - ? withTiming( - interpolate(offset.value, [0, 100], [72, 48], { - extrapolateLeft: Extrapolation.CLAMP, - extrapolateRight: Extrapolation.CLAMP, - }), - {duration: 10} - ) - : 0 - return {height, transform: [{translateX}, {translateY}]} + return {transform: [{translateX}]} }) return ( - { {services.map(service => ( ))} - {Kb.Styles.isTablet ? ( - - ) : null} - + {Kb.Styles.isTablet ? : null} + ) } @@ -254,7 +159,7 @@ const styles = Kb.Styles.styleSheetCreate( }, serviceIconContainer: { alignSelf: 'center', - height: '100%', + paddingBottom: Kb.Styles.globalMargins.tiny, paddingTop: Kb.Styles.globalMargins.tiny, position: 'relative', },