From fe4e9156c0fc9b94a0be03f922d32c298aeb70be Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Thu, 4 May 2023 12:59:18 +0200
Subject: [PATCH 01/10] migrate switch to PressableWithFeedback, add
 accessibility props

---
 src/components/Switch.js | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/components/Switch.js b/src/components/Switch.js
index e4de23650556..4496bfa4266b 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -1,7 +1,8 @@
 import React, {Component} from 'react';
-import {TouchableOpacity, Animated} from 'react-native';
+import {Animated} from 'react-native';
 import PropTypes from 'prop-types';
 import styles from '../styles/styles';
+import * as Pressables from './Pressable';
 
 const propTypes = {
     /** Whether the switch is toggled to the on position */
@@ -11,6 +12,7 @@ const propTypes = {
     onToggle: PropTypes.func.isRequired,
 };
 
+const PressableWithFeedback = Pressables.PressableWithFeedback;
 class Switch extends Component {
     constructor(props) {
         super(props);
@@ -40,13 +42,15 @@ class Switch extends Component {
     render() {
         const switchTransform = {transform: [{translateX: this.offsetX}]};
         return (
-            <TouchableOpacity
+            <PressableWithFeedback
                 style={[styles.switchTrack, !this.props.isOn && styles.switchInactive]}
-                activeOpacity={0.8}
                 onPress={() => this.props.onToggle(!this.props.isOn)}
+                accessibilityRole="switch"
+                accessibilityState={{checked: this.props.isOn}}
+                aria-checked={this.props.isOn}
             >
                 <Animated.View style={[styles.switchThumb, switchTransform]} />
-            </TouchableOpacity>
+            </PressableWithFeedback>
         );
     }
 }

From a2f35e1b26f2ea834dc85bbd93d034d8167dfebc Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Sat, 6 May 2023 00:42:11 +0200
Subject: [PATCH 02/10] fix warnings which come from OpacityView

---
 src/components/OpacityView.js                     | 2 +-
 src/components/Pressable/PressableWithFeedback.js | 2 +-
 src/components/Switch.js                          | 4 ++++
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/components/OpacityView.js b/src/components/OpacityView.js
index f9deb1184d72..17d05e42dbb6 100644
--- a/src/components/OpacityView.js
+++ b/src/components/OpacityView.js
@@ -21,7 +21,7 @@ const propTypes = {
      * @default []
      */
     // eslint-disable-next-line react/forbid-prop-types
-    style: PropTypes.arrayOf(PropTypes.object),
+    style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
 
     /**
      * The value to use for the opacity when the view is dimmed
diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js
index 66401fc1d974..341755c5aaf7 100644
--- a/src/components/Pressable/PressableWithFeedback.js
+++ b/src/components/Pressable/PressableWithFeedback.js
@@ -29,7 +29,7 @@ const PressableWithFeedback = forwardRef((props, ref) => {
         <GenericPressable ref={ref} style={props.wrapperStyle} {...propsWithoutStyling}>
             {state => (
                 <OpacityView
-                    shouldDim={state.pressed || state.hovered}
+                    shouldDim={state.pressed || state.hovered || false}
                     dimmingValue={state.pressed ? props.pressDimmingValue : props.hoverDimmingValue}
                     style={[
                         StyleUtils.parseStyleFromFunction(props.style, state),
diff --git a/src/components/Switch.js b/src/components/Switch.js
index 4496bfa4266b..febd42ddfeba 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -10,6 +10,9 @@ const propTypes = {
 
     /** Callback to fire when the switch is toggled */
     onToggle: PropTypes.func.isRequired,
+
+    /** Accessibility label for the switch */
+    accessibilityLabel: PropTypes.string.isRequired,
 };
 
 const PressableWithFeedback = Pressables.PressableWithFeedback;
@@ -48,6 +51,7 @@ class Switch extends Component {
                 accessibilityRole="switch"
                 accessibilityState={{checked: this.props.isOn}}
                 aria-checked={this.props.isOn}
+                accessibilityLabel={this.props.accessibilityLabel}
             >
                 <Animated.View style={[styles.switchThumb, switchTransform]} />
             </PressableWithFeedback>

From d5d38f594ae66d2f3583d338cd5efc625ebd03d9 Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Mon, 8 May 2023 23:49:15 +0200
Subject: [PATCH 03/10] remove dimming from switch component

---
 src/components/Switch.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/components/Switch.js b/src/components/Switch.js
index febd42ddfeba..ef070768fe7a 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -52,6 +52,9 @@ class Switch extends Component {
                 accessibilityState={{checked: this.props.isOn}}
                 aria-checked={this.props.isOn}
                 accessibilityLabel={this.props.accessibilityLabel}
+
+                // disable hover dim for switch
+                hoverDimmingValue={1}
             >
                 <Animated.View style={[styles.switchThumb, switchTransform]} />
             </PressableWithFeedback>

From d6238f2fc889b51c07548d51e3e51b695245e051 Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Mon, 8 May 2023 23:49:41 +0200
Subject: [PATCH 04/10] add required accessibility labels for all switches

---
 src/components/TestToolMenu.js                    | 3 +++
 src/pages/settings/Preferences/PreferencesPage.js | 1 +
 2 files changed, 4 insertions(+)

diff --git a/src/components/TestToolMenu.js b/src/components/TestToolMenu.js
index 7a056ac48565..1d432eaec1b5 100644
--- a/src/components/TestToolMenu.js
+++ b/src/components/TestToolMenu.js
@@ -48,6 +48,7 @@ const TestToolMenu = props => (
         {!CONFIG.IS_USING_LOCAL_WEB && (
             <TestToolRow title="Use Staging Server">
                 <Switch
+                    accessibilityLabel="Use Staging Server"
                     isOn={lodashGet(props, 'user.shouldUseStagingServer', ApiUtils.isUsingStagingApi())}
                     onToggle={() => User.setShouldUseStagingServer(
                         !lodashGet(props, 'user.shouldUseStagingServer', ApiUtils.isUsingStagingApi()),
@@ -59,6 +60,7 @@ const TestToolMenu = props => (
         {/* When toggled the app will be forced offline. */}
         <TestToolRow title="Force offline">
             <Switch
+                accessibilityLabel="Force offline"
                 isOn={Boolean(props.network.shouldForceOffline)}
                 onToggle={() => Network.setShouldForceOffline(!props.network.shouldForceOffline)}
             />
@@ -67,6 +69,7 @@ const TestToolMenu = props => (
         {/* When toggled all network requests will fail. */}
         <TestToolRow title="Simulate failing network requests">
             <Switch
+                accessibilityLabel="Simulate failing network requests"
                 isOn={Boolean(props.network.shouldFailAllRequests)}
                 onToggle={() => Network.setShouldFailAllRequests(!props.network.shouldFailAllRequests)}
             />
diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js
index 3594e37d6deb..904593d0bdb4 100755
--- a/src/pages/settings/Preferences/PreferencesPage.js
+++ b/src/pages/settings/Preferences/PreferencesPage.js
@@ -70,6 +70,7 @@ const PreferencesPage = (props) => {
                         </View>
                         <View style={[styles.flex1, styles.alignItemsEnd]}>
                             <Switch
+                                accessibilityLabel={props.translate('preferencesPage.receiveRelevantFeatureUpdatesAndExpensifyNews')}
                                 isOn={lodashGet(props.user, 'isSubscribedToNewsletter', true)}
                                 onToggle={User.updateNewsletterSubscription}
                             />

From fd4e931b1bc624bb1c57f23180bef6e6f9158baa Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Tue, 9 May 2023 13:06:11 +0200
Subject: [PATCH 05/10] Add remaining accessibilityLabel for switch in
 TimezoneInitialPage.js

---
 src/pages/settings/Profile/TimezoneInitialPage.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js
index c2162af65118..ba7a3491387a 100644
--- a/src/pages/settings/Profile/TimezoneInitialPage.js
+++ b/src/pages/settings/Profile/TimezoneInitialPage.js
@@ -59,6 +59,7 @@ const TimezoneInitialPage = (props) => {
                             {props.translate('timezonePage.getLocationAutomatically')}
                         </Text>
                         <Switch
+                            accessibilityLabel={props.translate('timezonePage.getLocationAutomatically')}
                             isOn={timezone.automatic}
                             onToggle={updateAutomaticTimezone}
                         />

From 5bf6f9adf0f4a6d2cc7c292fe4cbb5086faf2ecb Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Tue, 9 May 2023 13:53:24 +0200
Subject: [PATCH 06/10] fix error when GenericPressable tries to call onPress
 when disabled

---
 .../Pressable/GenericPressable/BaseGenericPressable.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
index 7566272abbc2..b4c2cd796e28 100644
--- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js
+++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
@@ -121,11 +121,11 @@ const GenericPressable = forwardRef((props, ref) => {
             hitSlop={shouldUseAutoHitSlop && hitSlop}
             onLayout={onLayout}
             ref={ref}
-            onPress={!isDisabled && onPressHandler}
-            onLongPress={!isDisabled && onLongPressHandler}
-            onKeyPress={!isDisabled && onKeyPressHandler}
-            onPressIn={!isDisabled && onPressIn}
-            onPressOut={!isDisabled && onPressOut}
+            onPress={!isDisabled ? onPressHandler : undefined}
+            onLongPress={!isDisabled ? onLongPressHandler : undefined}
+            onKeyPress={!isDisabled ? onKeyPressHandler : undefined}
+            onPressIn={!isDisabled ? onPressIn : undefined}
+            onPressOut={!isDisabled ? onPressOut : undefined}
             style={state => [
                 getCursorStyle(isDisabled, [props.accessibilityRole, props.role].includes('text')),
                 props.style,

From cb7eef601bcdfc3f5de5434f90594273cc1082ee Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Wed, 10 May 2023 11:34:27 +0200
Subject: [PATCH 07/10] press dim value for switch is set to 0.8

---
 src/components/Switch.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/components/Switch.js b/src/components/Switch.js
index ef070768fe7a..1120e2e1ae6a 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -55,6 +55,7 @@ class Switch extends Component {
 
                 // disable hover dim for switch
                 hoverDimmingValue={1}
+                pressDimmingValue={0.8}
             >
                 <Animated.View style={[styles.switchThumb, switchTransform]} />
             </PressableWithFeedback>

From 611e44df14fbeedcf30c76d20bc7169ed82ee8b6 Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Wed, 10 May 2023 12:30:36 +0200
Subject: [PATCH 08/10] trigger the same callback on press and longPress for
 switch

---
 src/components/Switch.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/components/Switch.js b/src/components/Switch.js
index 1120e2e1ae6a..7ab83bed70cb 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -24,6 +24,7 @@ class Switch extends Component {
         this.offsetX = new Animated.Value(props.isOn ? this.onPosition : this.offPosition);
 
         this.toggleSwitch = this.toggleSwitch.bind(this);
+        this.toggleAction = this.toggleAction.bind(this);
     }
 
     componentDidUpdate(prevProps) {
@@ -34,6 +35,7 @@ class Switch extends Component {
         this.toggleSwitch();
     }
 
+    // animates the switch to the on or off position
     toggleSwitch() {
         Animated.timing(this.offsetX, {
             toValue: this.props.isOn ? this.onPosition : this.offPosition,
@@ -42,12 +44,18 @@ class Switch extends Component {
         }).start();
     }
 
+    // executes the callback passed in as a prop
+    toggleAction() {
+        this.props.onToggle(!this.props.isOn);
+    }
+
     render() {
         const switchTransform = {transform: [{translateX: this.offsetX}]};
         return (
             <PressableWithFeedback
                 style={[styles.switchTrack, !this.props.isOn && styles.switchInactive]}
-                onPress={() => this.props.onToggle(!this.props.isOn)}
+                onPress={this.toggleAction}
+                onLongPress={this.toggleAction}
                 accessibilityRole="switch"
                 accessibilityState={{checked: this.props.isOn}}
                 aria-checked={this.props.isOn}

From ccbe9a938e6842613ba3db16f53d7905a76c2170 Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Wed, 10 May 2023 23:07:28 +0200
Subject: [PATCH 09/10] disable dimming of PressableWithFeedback when is
 disabled

---
 .../Pressable/PressableWithFeedback.js        | 39 +++++++++----------
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js
index 33e557e39ab1..704f2c6c60a6 100644
--- a/src/components/Pressable/PressableWithFeedback.js
+++ b/src/components/Pressable/PressableWithFeedback.js
@@ -25,26 +25,25 @@ const PressableWithFeedbackDefaultProps = {
 const PressableWithFeedback = forwardRef((props, ref) => {
     const propsWithoutStyling = _.omit(props, omittedProps);
     return (
-        <GenericPressable
-            ref={ref}
-            style={props.wrapperStyle}
-            // eslint-disable-next-line react/jsx-props-no-spreading
-            {...propsWithoutStyling}
-        >
-            {(state) => (
-                <OpacityView
-                    shouldDim={state.pressed || state.hovered || false}
-                    dimmingValue={state.pressed ? props.pressDimmingValue : props.hoverDimmingValue}
-                    style={[
-                        StyleUtils.parseStyleFromFunction(props.style, state),
-                        state.pressed && StyleUtils.parseStyleFromFunction(props.pressStyle, state),
-                        state.hovered && StyleUtils.parseStyleAsArray(props.hoverStyle, state),
-                        state.focused && StyleUtils.parseStyleAsArray(props.focusStyle, state),
-                    ]}
-                >
-                    {props.children}
-                </OpacityView>
-            )}
+        // eslint-disable-next-line react/jsx-props-no-spreading
+        <GenericPressable ref={ref} style={props.wrapperStyle} {...propsWithoutStyling}>
+            {(state) => {
+                const shouldDim = !props.disabled && (!!state.pressed || !!state.hovered);
+                return (
+                    <OpacityView
+                        shouldDim={shouldDim}
+                        dimmingValue={state.pressed ? props.pressDimmingValue : props.hoverDimmingValue}
+                        style={[
+                            StyleUtils.parseStyleFromFunction(props.style, state),
+                            state.pressed && StyleUtils.parseStyleFromFunction(props.pressStyle, state),
+                            state.hovered && StyleUtils.parseStyleAsArray(props.hoverStyle, state),
+                            state.focused && StyleUtils.parseStyleAsArray(props.focusStyle, state),
+                        ]}
+                    >
+                        {props.children}
+                    </OpacityView>
+                );
+            }}
         </GenericPressable>
     );
 });

From b2b4d0db22b5a56e7c3f61a519ee2d71556fd0f2 Mon Sep 17 00:00:00 2001
From: Robert Kozik <robert.kozik@swmansion.com>
Date: Wed, 10 May 2023 23:14:05 +0200
Subject: [PATCH 10/10] run prettier on changed files

---
 .../Pressable/GenericPressable/BaseGenericPressable.js    | 2 +-
 src/components/Pressable/PressableWithFeedback.js         | 8 ++++++--
 src/components/Switch.js                                  | 1 -
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
index 231a023818d6..5de5e8774ebb 100644
--- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js
+++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
@@ -124,7 +124,7 @@ const GenericPressable = forwardRef((props, ref) => {
             onKeyPress={!isDisabled ? onKeyPressHandler : undefined}
             onPressIn={!isDisabled ? onPressIn : undefined}
             onPressOut={!isDisabled ? onPressOut : undefined}
-            style={state => [
+            style={(state) => [
                 getCursorStyle(isDisabled, [props.accessibilityRole, props.role].includes('text')),
                 props.style,
                 isScreenReaderActive && StyleUtils.parseStyleFromFunction(props.screenReaderActiveStyle, state),
diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js
index 704f2c6c60a6..1e2ee03666a1 100644
--- a/src/components/Pressable/PressableWithFeedback.js
+++ b/src/components/Pressable/PressableWithFeedback.js
@@ -25,8 +25,12 @@ const PressableWithFeedbackDefaultProps = {
 const PressableWithFeedback = forwardRef((props, ref) => {
     const propsWithoutStyling = _.omit(props, omittedProps);
     return (
-        // eslint-disable-next-line react/jsx-props-no-spreading
-        <GenericPressable ref={ref} style={props.wrapperStyle} {...propsWithoutStyling}>
+        <GenericPressable
+            ref={ref}
+            style={props.wrapperStyle}
+            // eslint-disable-next-line react/jsx-props-no-spreading
+            {...propsWithoutStyling}
+        >
             {(state) => {
                 const shouldDim = !props.disabled && (!!state.pressed || !!state.hovered);
                 return (
diff --git a/src/components/Switch.js b/src/components/Switch.js
index 7ab83bed70cb..f0fd20f7af48 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -60,7 +60,6 @@ class Switch extends Component {
                 accessibilityState={{checked: this.props.isOn}}
                 aria-checked={this.props.isOn}
                 accessibilityLabel={this.props.accessibilityLabel}
-
                 // disable hover dim for switch
                 hoverDimmingValue={1}
                 pressDimmingValue={0.8}
