From f15a52b3db78d716f1c9bf72717dfce412969f91 Mon Sep 17 00:00:00 2001 From: thislight Date: Thu, 7 Nov 2024 16:17:13 +0800 Subject: [PATCH] Settings: add safe area inset emulation --- src/settings/Settings.tsx | 131 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index dd82f25..8806ff5 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -3,6 +3,7 @@ import { createSignal, For, Show, + type JSX, type ParentComponent, } from "solid-js"; import Scaffold from "../material/Scaffold.js"; @@ -17,6 +18,7 @@ import { ListItemSecondaryAction, ListItemText, ListSubheader, + NativeSelect, Switch, Toolbar, } from "@suid/material"; @@ -46,6 +48,96 @@ import BottomSheet from "../material/BottomSheet.jsx"; import { useServiceWorker } from "../platform/host.js"; import { useSessions } from "../masto/clients.js"; +type Inset = { + top?: number; + right?: number; + bottom?: number; + left?: number; +}; + +type SafeAreaInsets = { + landscape: Inset; + protrait: Inset; +}; + +const safeAreaInsets: Record = { + iphone15: { + protrait: { + top: 59, + bottom: 34, + }, + landscape: { + bottom: 21, + left: 59, + right: 59, + }, + }, + iphone12: { + protrait: { + top: 47, + bottom: 34, + }, + landscape: { + bottom: 21, + left: 47, + right: 47, + }, + }, + iphone13mini: { + protrait: { + top: 50, + bottom: 34, + }, + landscape: { + bottom: 21, + left: 50, + right: 50, + }, + }, +}; + +let screenOrientationCallback: (() => void) | undefined; + +function applySafeAreaEmulation(root: HTMLElement, insets: Inset) { + for (const key of Object.keys(insets) as (keyof Inset)[]) { + const value = insets[key]; + if (!value || value === 0) continue; + root.style.setProperty(`--safe-area-inset-${key}`, `${value}px`); + } +} + +function setupSafeAreaEmulation(name: string) { + const insets = safeAreaInsets[name]; + const root = document.querySelector(":root")! as HTMLElement; + if (!insets) { + if (screenOrientationCallback) { + window.screen.orientation.removeEventListener( + "change", + screenOrientationCallback, + ); + screenOrientationCallback = undefined; + } + for (const name of ["top", "right", "bottom", "left"]) { + root.style.removeProperty(`--safe-area-inset-${name}`); + } + } else { + screenOrientationCallback = () => { + if (window.screen.orientation.type === "portrait-primary") { + console.debug("safe area emulation: protrait"); + applySafeAreaEmulation(root, insets.protrait); + } else if (window.screen.orientation.type === "landscape-primary") { + console.debug("safe area emulation: landscape"); + applySafeAreaEmulation(root, insets.landscape); + } + }; + window.screen.orientation.addEventListener( + "change", + screenOrientationCallback, + ); + screenOrientationCallback(); + } +} + type Strings = { ["lang.auto"]: Template<{ detected: string }>; } & Record; @@ -235,6 +327,45 @@ const Settings: ParentComponent = (props) => { + {import.meta.env.DEV ? ( +
  • + Developer Tools + { + const k = event.currentTarget.value; + setupSafeAreaEmulation(k); + }} + > + + + + + + + ) : undefined + } + > + + Safe Area Insets + + + +
  • + ) : ( + <> + )} );