Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile Web Safari: Adds auto scroll back - Issue 5894 #6413

Merged
merged 7 commits into from
Nov 30, 2021
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"react-web-config": "^1.0.0",
"rn-fetch-blob": "^0.12.0",
"save": "^2.4.0",
"smoothscroll-polyfill": "^0.4.4",
"underscore": "^1.13.1",
"urbanairship-react-native": "^11.0.2"
},
Expand Down
1 change: 1 addition & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import OnyxProvider from './components/OnyxProvider';
import HTMLEngineProvider from './components/HTMLEngineProvider';
import ComposeProviders from './components/ComposeProviders';
import SafeArea from './components/SafeArea';
import './libs/autoScrollback';

LogBox.ignoreLogs([
// Basically it means that if the app goes in the background and back to foreground on Android,
Expand Down
4 changes: 4 additions & 0 deletions src/libs/autoScrollback/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* autoScrollBack address Mobile Safari-specific issues when the user overscrolls the window while the keyboard is visible */
sidferreira marked this conversation as resolved.
Show resolved Hide resolved
/* it has no effect to other platforms */

export default () => {};
102 changes: 102 additions & 0 deletions src/libs/autoScrollback/index.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* autoScrollBack address Mobile Safari-specific issues when the user overscrolls the window while the keyboard is visible */

/* allows smooth scroll when programmatic scrolling */
import smoothscroll from 'smoothscroll-polyfill';
import Str from 'expensify-common/lib/str';

import getBrowser from '../getBrowser';

const init = () => {
sidferreira marked this conversation as resolved.
Show resolved Hide resolved
sidferreira marked this conversation as resolved.
Show resolved Hide resolved
if (getBrowser() !== 'safari') {
sidferreira marked this conversation as resolved.
Show resolved Hide resolved
return;
}
const userAgent = navigator.userAgent.toLowerCase();

if (Str.contains(userAgent, 'iphone os 1')) {
sidferreira marked this conversation as resolved.
Show resolved Hide resolved
const baseInnerHeight = window.innerHeight;

sidferreira marked this conversation as resolved.
Show resolved Hide resolved
/* minimum acceptable innerHeight, less than that, scroll back */
let minimumInnerHeight = 0;

sidferreira marked this conversation as resolved.
Show resolved Hide resolved
const isIos15 = Str.contains(userAgent, 'iphone os 15_');

sidferreira marked this conversation as resolved.
Show resolved Hide resolved
switch (window.outerHeight) {
case 926: { // iPhone 12/13 Pro Max
minimumInnerHeight = 440;
break;
}
case 896: {
if (window.devicePixelRatio === 3) { // iPhone 11 Pro Max
minimumInnerHeight = 425;
} else { // iPhone 11
minimumInnerHeight = isIos15 ? 460 : 420;
}
break;
}
case 844: {
if (window.devicePixelRatio === 3) { // iPhone 13 / iPhone 12/13 Pro
minimumInnerHeight = 370;
} else { // iPhone 12
minimumInnerHeight = 412;
}
break;
}
case 812: {
if (window.devicePixelRatio === 3) { // iPhone 11 Pro / iPhone 12/13 Mini
minimumInnerHeight = 340;
} else { // iPhone 11
minimumInnerHeight = 420;
}
break;
}
default: {
//
}
}

if (!minimumInnerHeight) {
return;
}

let isTouching = false;
let timeout;
smoothscroll.polyfill();

const scrollBack = () => {
window.requestAnimationFrame(() => {
window.scrollTo({
top: baseInnerHeight - minimumInnerHeight,
behavior: 'smooth',
});
});
};

const clearTimeoutIfNeeded = () => {
if (!timeout) {
return;
}
clearTimeout(timeout);
timeout = undefined;
};

const scheduleScrollback = () => {
clearTimeoutIfNeeded();
if (!isTouching && minimumInnerHeight > window.innerHeight) {
timeout = setTimeout(scrollBack, 34);
}
};

document.addEventListener('touchstart', () => {
isTouching = true;
});
document.addEventListener('touchend', () => {
isTouching = false;
scheduleScrollback();
});
document.addEventListener('scroll', () => {
scheduleScrollback();
});
}
};

init();
sidferreira marked this conversation as resolved.
Show resolved Hide resolved