Skip to content

Commit 5eef0dc

Browse files
committed
fix ios keyboardplugin
1 parent 873d276 commit 5eef0dc

4 files changed

Lines changed: 42 additions & 2 deletions

File tree

app/src/views/Home.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ export const HomeView = (props: ScrollViewProps) => {
3838
const [selectedTabUri, setSelectedTabUri] = useState<string>('')
3939

4040
// fix default settings
41+
// depsのtはi18nの言語ロードで参照が変わるので、ガードがないとドロワーが二重にpushされる
42+
const profileSetupOpened = useRef(false)
4143
useEffect(() => {
4244
if (!client) return
4345
// オフライン時はプロフィールがキャッシュから読めなかっただけの可能性があり、
4446
// そもそもcommitもできないので表示しない
4547
if (isDomainOffline) return
48+
if (profileSetupOpened.current) return
4649
if (!(client.currentProfile in client.profiles)) {
50+
profileSetupOpened.current = true
4751
drawer.open(
4852
<ProfileEditor
4953
noLoading

plugins/tauri-plugin-keyboard/ios/Sources/KeyboardPlugin.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@ class KeyboardPlugin: Plugin {
2525
)
2626
}
2727

28+
// object: nilで購読しているため、webview以外が出したキーボードの通知も届く。
29+
// 特にアカウント作成フローはアプリ内ブラウザ(SFSafariViewController)の登録フォームに
30+
// 入力させるので、そのキーボード高さをそのまま流すとwebview側に余白が残り続け、
31+
// ブラウザを閉じた後に開いたBottomSheetの中身が高さ0に潰れて真っ白になる
32+
private func isOwnKeyboard(_ notification: Notification) -> Bool {
33+
// アプリ内ブラウザは別プロセスで動くのでisLocalがfalseになる。
34+
// キーが無い経路もあるため、取れない場合は自分のものとみなす
35+
if let isLocal = notification.userInfo?[UIResponder.keyboardIsLocalUserInfoKey] as? Bool, !isLocal {
36+
return false
37+
}
38+
39+
// モーダルが乗っている間(アプリ内ブラウザ/バーコードスキャナ等)はwebviewが隠れており、
40+
// そこで出たキーボードはこちらのレイアウトには関係ない
41+
if manager.viewController?.presentedViewController != nil {
42+
return false
43+
}
44+
45+
return true
46+
}
47+
2848
@objc func keyboardWillChangeFrame(_ notification: Notification) {
2949
guard
3050
let endFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?
@@ -36,7 +56,12 @@ class KeyboardPlugin: Plugin {
3656

3757
// 画面下端とキーボードの重なり。hide時はendFrameが画面外に出て0になる。
3858
// QuickTypeバー切替等で同一表示中にも発火するため、差分ではなく毎回絶対値で計算する。
39-
let height = max(0, UIScreen.main.bounds.maxY - endFrame.minY)
59+
// 自分以外のキーボードは無視(return)ではなく高さ0として流す。
60+
// 無視すると直前の高さがJS側のstateに残り続けてしまう
61+
let height =
62+
isOwnKeyboard(notification)
63+
? max(0, UIScreen.main.bounds.maxY - endFrame.minY)
64+
: 0
4065

4166
do {
4267
try trigger(

ui/src/ui/BottomSheet.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { type ReactNode } from 'react'
22
import { animate, motion, useDragControls, useMotionValue, useTransform } from 'motion/react'
33
import { CssVar } from '../types/Theme'
44

5+
// キーボード分の余白でコンテンツを潰し切らないための下限
6+
const MIN_CONTENT_HEIGHT = 120
7+
58
interface Props {
69
height: number
710
onDismiss: () => void
@@ -20,6 +23,10 @@ export const BottomSheet = (props: Props) => {
2023
const height = props.height
2124
const backdropOpacity = useTransform(y, [0, height], [0.5, 0])
2225

26+
// 想定外に大きいキーボード高さが来ても、スペーサーがシートを食い尽くして
27+
// スクロールコンテナが高さ0になる(中身が消える)ことがないようクランプする
28+
const keyboardHeight = Math.min(props.keyboardInset?.height ?? 0, Math.max(0, height - MIN_CONTENT_HEIGHT))
29+
2330
return (
2431
<>
2532
<motion.div
@@ -128,7 +135,7 @@ export const BottomSheet = (props: Props) => {
128135
<div
129136
style={{
130137
flexShrink: 0,
131-
height: `${props.keyboardInset.height}px`,
138+
height: `${keyboardHeight}px`,
132139
transition: `height ${props.keyboardInset.duration}s ease-out`
133140
}}
134141
/>

web/src/views/Home.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,16 @@ export const HomeView = (props: ScrollViewProps) => {
4141
const [selectedTabUri, setSelectedTabUri] = useState<string>('')
4242

4343
// fix default settings
44+
// depsのtはi18nの言語ロードで参照が変わるので、ガードがないとドロワーが二重にpushされる
45+
const profileSetupOpened = useRef(false)
4446
useEffect(() => {
4547
if (!client) return
4648
// オフライン時はプロフィールがキャッシュから読めなかっただけの可能性があり、
4749
// そもそもcommitもできないので表示しない
4850
if (isDomainOffline) return
51+
if (profileSetupOpened.current) return
4952
if (!(client.currentProfile in client.profiles)) {
53+
profileSetupOpened.current = true
5054
drawer.open(
5155
<ProfileEditor
5256
noLoading

0 commit comments

Comments
 (0)