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

Conversation

sidferreira
Copy link
Contributor

@sidferreira sidferreira commented Nov 23, 2021

Details

On Mobile Web Safari, if you scroll up too much when the keyboard is open, this code will scroll back automatically

Fixed Issues

$ #5894

Tests

Open mobile web, go to composer with software keyboard active, scroll up as much as you can

QA Steps

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Recordings

Platform Recording
Mobile Web Android https://user-images.githubusercontent.com/143615/142961774-34921c18-5e3b-425c-86e5-acabe6149b39.mov
iPhone 13 Pro Max https://user-images.githubusercontent.com/143615/143508193-65e44413-091d-4d78-bb0e-1560d02af98c.mp4
iPhone 13 Pro https://user-images.githubusercontent.com/143615/143508219-05aadb38-871c-4372-a568-95b11ff3cef3.mp4
iPhone 13 https://user-images.githubusercontent.com/143615/143508250-18e90f02-d99c-4f01-9d78-4962a748c7c6.mp4
iPhone 13 Mini https://user-images.githubusercontent.com/143615/143508264-06d64d01-13e7-4e81-9b95-1f9a3bf05430.mp4
iPhone 12 iOS 15 Pro Max https://user-images.githubusercontent.com/143615/143508374-049947b1-764f-4bdb-a975-58f3b314248a.mp4
iPhone 12 iOS 15 Pro https://user-images.githubusercontent.com/143615/143508389-5d4e143e-ae8c-409f-93b5-9793d6b72676.mp4
iPhone 12 iOS 15 https://user-images.githubusercontent.com/143615/143508409-82d2867e-9b3c-4f4d-b7cd-1d03fce893d9.mp4
iPhone 12 iOS 15 Mini https://user-images.githubusercontent.com/143615/143508439-ba5de795-bcb1-4a71-8d5c-bf8d5229fae2.mp4
iPhone 12 iOS 14 Pro Max https://user-images.githubusercontent.com/143615/143508282-fbdac104-b54f-4f84-96ee-0b917554850d.mp4
iPhone 12 iOS 14 Pro https://user-images.githubusercontent.com/143615/143508311-44536d40-e622-465c-a79b-96dc456b1fc0.mp4
iPhone 12 iOS 14 https://user-images.githubusercontent.com/143615/143508346-0fb34ff8-4e91-4853-8115-15e4630cd47e.mp4
iPhone 12 iOS 14 Mini https://user-images.githubusercontent.com/143615/143508366-b5586bf6-5248-4ca0-9e61-0ed5b5501a93.mp4
iPhone 11 iOS 14 Pro Max https://user-images.githubusercontent.com/143615/143508512-fb38ec91-f8c1-4bdf-be7b-39035116d6f3.mp4
iPhone 11 iOS 14 Pro https://user-images.githubusercontent.com/143615/143508530-b2b898fb-121f-45c4-9701-616db05a9a74.mp4
iPhone 11 iOS 14 https://user-images.githubusercontent.com/143615/143508551-567f6903-c540-4f65-8e0d-817c8591b307.mp4

@sidferreira sidferreira requested a review from a team as a code owner November 23, 2021 02:12
@MelvinBot MelvinBot requested review from roryabraham and removed request for a team November 23, 2021 02:12
@sidferreira
Copy link
Contributor Author

@tgolen I'm not sure if import './libs/autoScrollback'; at the app.js is the best choice, so I'm open to suggestions.

@sidferreira sidferreira changed the title Mobile Web Safari: Adds auto scroll back Mobile Web Safari: Adds auto scroll back - Issue 5894 Nov 23, 2021
Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have one major critique of this implementation: it seems very brittle and that it will not be very future-proof. I would love to see a responsive implementation that does not check against exact pixel heights of various iPhone models. Looking at this code, it seems like that should be possible.

Other than that, I have a few more minor notes/suggestions here:

  1. The autoScrollback/index.js file should at least contain a comment explaining what autoScrollback does and why it doesn't have a non-web implementation.
  2. Maybe we should rename autoScrollback to mobileSafariAutoScrollback
  3. Wherever you're using someString.indexOf('someOtherString') > 0), we can instead use Str.contains(somString, 'someOtherString') from expensify-common, to improve readability and consistency.
  4. You've also got some lint errors.

src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
@sidferreira
Copy link
Contributor Author

sidferreira commented Nov 25, 2021

I have one major critique of this implementation: it seems very brittle and that it will not be very future-proof. I would love to see a responsive implementation that does not check against exact pixel heights of various iPhone models. Looking at this code, it seems like that should be possible.

@roryabraham So, did a review, made some extra tests, and managed to find a better solution IMHO. Sadly it still not a silver bullet (it's hard to find the sweet spot UI wise), it should cover properly iPhone 11, iPhone 12, iPhone 13, including Mini, Pro, Pro Max with a smaller complexity.

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, I don't think we need to use the smooth-scroll polyfill. Could you please tell me why did you use it?
I doubt the implementation...Looks very volatile.

@sidferreira
Copy link
Contributor Author

@parasharrajat So, I mentioned previously ( #5894 (comment) ) and it seems to me that the team were OK with that. Now, the main reason we need it is cause Safari doesn't support Smooth Scroll ( https://caniuse.com/css-scroll-behavior ), but I must admit that library was just one I found at that moment. I recently found another ( https://github.com/CristianDavideConte/universalSmoothScroll ) that may be more recent.

About the implementation, I did test each of the devices there to be sure it was working as expected.

@parasharrajat
Copy link
Member

parasharrajat commented Nov 25, 2021

But you are using javascript scrollTo https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo#browser_compatibility

About the implementation, I did test each of the devices there to be sure it was working as expected.

I will add to what Rory said, I would love to see a responsive implementation that does not check against exact pixel heights of various iPhone models.

@sidferreira
Copy link
Contributor Author

@parasharrajat I'll revisit it, but I did try the smooth option on it and had no success. For sure I'll be glad to remove the dep!

@sidferreira
Copy link
Contributor Author

@parasharrajat @roryabraham So, in the end, I did found a workaround and with that I could drop the extra lib. It isn't as smooth as I would like, but I think it isn't a big deal (of course I can add the polyfill back at any time)

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am yet to test it on a device..

src/libs/autoScrollback/index.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good.

Edit:
Not tested on the device yet.

@sidferreira
Copy link
Contributor Author

@roryabraham

Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few comments:

  1. Overall, the code is pretty simple and responsive, so great job there 👍

  2. Let's add the smoothscroll polyfill back. I tested this out on a physical device and the "jumpy" scroll feels like a glitchy UX. The goal here is to simulate an experience that's as close to the default iOS behavior as possible. The smooth scrolling was definitely better.

  3. Let's rename this library to iOSSafariAutoScrollback, just to make it extra clear what it's all about.

  4. It's pretty bizarre that we're importing a library that just does things totally by side-effect. Instead, I think that autoScrollback should default-export a function like so:

    export default function () {
      if (getBrowser() === CONST.BROWSER.SAFARI && Str.contains(userAgent, 'iphone os 1')) {
    	    document.addEventListener('touchstart', touchStarted);
    	    document.addEventListener('touchend', scrollbackAfterTouch);
    	    document.addEventListener('scroll', scrollbackAfterScroll);
    	    document.addEventListener('focusin', startsWaitingForScroll);
    	    document.addEventListener('focusout', stopsWaitingForScroll);
      }
    }

    Of course, index.js would just export a noop:

    export default () => {};

    Then App.js would import and execute that function like so:

    import initializeiOSSafariAutoScrollback from './libs/iOSSafariAutoScrollback';
    ...
    ...
    initializeiOSSafariAutoScrollback();
  5. Do we still plan to follow-up and get similar code merged directly into react-native-web?

src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
src/libs/autoScrollback/index.web.js Outdated Show resolved Hide resolved
@sidferreira
Copy link
Contributor Author

Do we still plan to follow-up and get similar code merged directly into react-native-web?

Totally forgot about this tbh. Should I reach them about it? You guys wanna do it?

@roryabraham
Copy link
Contributor

LGTM, I think we can merge this code in our repo, then do a follow-up to:

  1. Open an issue in react-native-web
  2. Submit a PR to fix it.
  3. If/when that PR is merged and released with a new version of react-native-web, then we should update react-native-web and remove this code.

Do you think you can handle that? I think it's fair to create a separate Upwork milestone with a separate (smaller) payout, if that's something you'd be interested in.

@roryabraham roryabraham merged commit f70f5da into Expensify:main Nov 30, 2021
@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@sidferreira
Copy link
Contributor Author

@roryabraham cc

Comment on lines +44 to +45
initializeiOSSafariAutoScrollback();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is something that's only intended to run on web, maybe you should consider importing and calling it only inside src/setup/platformSetup/index.website.js

I'll would even go as far as

export default function () {
  // AppRegistry.runApplication(
  // ...

    if (getBrowser() === CONST.BROWSER.SAFARI || Str.contains(userAgent, 'iphone os 1')) {
        const applyScrollFix = require('../libs/iOSSafariAutoScrollback');
        applyScrollFix();
    }

This way extra code is imported only when needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kidroca it is merged already... but that's a GREAT suggestion!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion @kidroca! If either of you wouldn't mind submitting a quick PR, I'll review it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks guys!
@roryabraham I'll open a PR about this today, when I get the chance



export default function () {
if (!getBrowser() === CONST.BROWSER.SAFARI || !Str.contains(userAgent, 'iphone os 1')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this supposed to be

getBrowser() !== CONST.BROWSER.SAFARI

!getBrowser() would be evaluated to boolean otherwise, so it's most probably the second part of the check that is doing all the work here

Copy link
Member

@parasharrajat parasharrajat Dec 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WOW. It should be getBrowser() == CONST.BROWSER.SAFARI

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we want to exist early if it regular safari, and only apply the polyfill for mobile ?

Copy link
Contributor

@kidroca kidroca Dec 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an early return condition
I though it tried to exist early if the browser is not Safari or mobile safari

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IT should only work on Safari web.

Copy link
Contributor Author

@sidferreira sidferreira Dec 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG 🤦‍♂️ how I did that?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kidroca if possible, load that file only for Website + Safari

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey I'm slightly confused I thought the issue is "Mobile Web Safari: Adds auto scroll back"
Which mean we're only targeting ios Safari (iPhone & iPads) and should apply the fix there, correct?

My plan is to use this expression

if (_.every([/iP(ad|hone)/i, /WebKit/i, /CriOS/i], re => re.test(navigator.userAgent))) {
   const applyAutoScrollbackFix = require('../../libs/iOSSafariAutoScrollback');
   applyAutoScrollbackFix();
}

The check is based on: https://stackoverflow.com/a/29696509/4834103

I can extract

const isMobileSafari = () => _.every([/iP(ad|hone)/i, /WebKit/i, /CriOS/i], re => re.test(navigator.userAgent));

But I don't know where to put it
Since it's only one time usage so far, I think I'll just keep it inline
Otherwise getBrowser seems to be a nice place, but I'm not sure how exactly to fit this expression there, or just add a isMobileSafari check

@kidroca
Copy link
Contributor

kidroca commented Dec 1, 2021

Hey, guys I've checked out main in order to apply the suggested update, but it seems there are cases that aren't covered

1 For some reason the text field is covered by the keyboard (only happened once)

rec1.mov

2 Keyboard is partially covering input
3 Depending on where you start to drag you can hide the input and not get it back (you can notice 2 scroll bars at some point)

rec2.mov

This is without applying any modifications to the code and after npm install

@parasharrajat
Copy link
Member

parasharrajat commented Dec 1, 2021

1st seems like an issue , I didn't face it as I think I tested it on old safari where the address field is at the top.
@sidferreira Could you please look into it?

@sidferreira
Copy link
Contributor Author

@parasharrajat I tested both in iOS14 and 15, will take a look!

@sidferreira
Copy link
Contributor Author

@kidroca just in case, do you mind sharing the exact commit you were testing?

@kidroca
Copy link
Contributor

kidroca commented Dec 3, 2021

Yes, it was: 0360fd7

@sidferreira
Copy link
Contributor Author

@kidroca @parasharrajat #6572 I couldn't reproduce it, still addressed discussed issues.

@parasharrajat
Copy link
Member

I will try to reproduce.

@OSBotify
Copy link
Contributor

OSBotify commented Dec 7, 2021

🚀 Deployed to staging by @roryabraham in version: 1.1.17-8 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

OSBotify commented Dec 8, 2021

🚀 Deployed to production by @roryabraham in version: 1.1.18-3 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants