Telegram Web App collapse on bottom swipe
Asked Answered
D

1

3

When I swipe down in the Telegram web app, the window closes. I found an example of how this was handled in another application: when swiping, an empty space appears, and instead of closing the curtain, the application scrolls up. The larger I make this space, the more acceleration there is in the scroll, and the less intense swipes are needed to go beyond the edge of the application. If this space is not large enough, with strong swipes, the application closes. Here is my implementation:

<html lang="en">
<body>
<div id="scrollArea" style="margin-top: 0px;"></div>
...
</body>
<script>
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
  var scrollArea = document.querySelector("#scrollArea")
  scrollArea.style.marginTop = "280px";
  scrollArea.style.paddingBottom = "20px";
  scrollToTop();
  window.addEventListener('scroll', function () {
    if (window.scrollY < 280) {
      scrollToTop();
    }
  });
}

function scrollToTop() {
  document.body.scrollTop = 0;
  setTimeout(() => {
    window.scroll({top: 300, behavior: "instant"});
  }, 50);
}
</script>
</html>

Here is an example of how it works (only works on iOS) @unicorn_go_bot

Any ideas how can i handle it?

Dudden answered 12/1, 2024 at 18:34 Comment(0)
A
4

I've investigated @tapswap_bot (props to them) source code (webkit debug) and found the solution. I've also made the scrolling working (their solution was breaking it).

So steps to implement:

  1. Document/body magic (without this touchmove step doesn't fix the problem for some reason):

(tailwind style) document: h-auto, overflow-hidden body: min-h-screen h-screen overflow-hidden

js code:

const overflow = 100
document.body.style.overflowY = 'hidden'
document.body.style.marginTop = `${overflow}px`
document.body.style.height = window.innerHeight + overflow + "px"
document.body.style.paddingBottom = `${overflow}px`
window.scrollTo(0, overflow)
  1. Block touchmove (block scroll on doc and body, because of the first step. Make body's child scrollable and then...):
let ts: number | undefined
const onTouchStart = (e: TouchEvent) => {
  ts = e.touches[0].clientY
}
const onTouchMove = (e: TouchEvent) => {
  if (scrollableEl) {
    const scroll = scrollableEl.scrollTop
    const te = e.changedTouches[0].clientY
    if (scroll <= 0 && ts! < te) {
      e.preventDefault()
    }
  } else {
    e.preventDefault()
  }
}
document.documentElement.addEventListener('touchstart', onTouchStart, { passive: false })
document.documentElement.addEventListener('touchmove', onTouchMove, { passive: false })

After that it works perfectly, no rage scroll breaks it. The only concern is that maybe some device has reversed scroll direction, in that case we will need to reverse touchmove condition logic, but anyway - it's working.

Atkinson answered 15/3, 2024 at 9:38 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.