Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/lib/crypto/secure-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ const BIOMETRIC_SUCCESS = 0;
async function getDwebBiometric(): Promise<DwebBiometricPlugin | null> {
if (!isDwebEnvironment()) return null;
try {
// 使用变量规避 Vite 静态分析
const moduleName = '@plaoc/plugins';
const module = await import(/* @vite-ignore */ moduleName);
const module = await import('@plaoc/plugins');
return module.biometricsPlugin as DwebBiometricPlugin;
} catch {
return null;
Expand Down
50 changes: 0 additions & 50 deletions src/lib/dweb-keyboard-overlay.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { describe, expect, it, vi } from 'vitest'
import {
applyDwebKeyboardOverlay,
startDwebKeyboardOverlay,
type DwebPluginsModule,
} from './dweb-keyboard-overlay'

Expand Down Expand Up @@ -60,53 +59,4 @@ describe('dweb keyboard overlay', () => {

warnSpy.mockRestore()
})

it('retries until dweb environment is ready', async () => {
vi.useFakeTimers()

const setOverlay = vi.fn<(overlay: boolean) => Promise<void>>().mockResolvedValue()
const loadPlugins = vi.fn<() => Promise<DwebPluginsModule>>().mockResolvedValue({
virtualKeyboardPlugin: { setOverlay },
})

let ready = false
const stop = startDwebKeyboardOverlay({
isDweb: () => ready,
loadPlugins,
maxAttempts: 4,
retryDelayMs: 100,
})

expect(loadPlugins).not.toHaveBeenCalled()

ready = true
await vi.advanceTimersByTimeAsync(120)

expect(loadPlugins).toHaveBeenCalledTimes(1)
expect(setOverlay).toHaveBeenCalledWith(true)

stop()
vi.useRealTimers()
})

it('stops retrying after cleanup', async () => {
vi.useFakeTimers()

const loadPlugins = vi.fn<() => Promise<DwebPluginsModule>>().mockResolvedValue({})
const stop = startDwebKeyboardOverlay({
isDweb: () => true,
loadPlugins,
maxAttempts: 10,
retryDelayMs: 100,
})

await vi.advanceTimersByTimeAsync(120)
expect(loadPlugins).toHaveBeenCalledTimes(2)

stop()
await vi.advanceTimersByTimeAsync(500)
expect(loadPlugins).toHaveBeenCalledTimes(2)

vi.useRealTimers()
})
})
48 changes: 1 addition & 47 deletions src/lib/dweb-keyboard-overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,8 @@ export interface ApplyDwebKeyboardOverlayOptions {
loadPlugins?: () => Promise<DwebPluginsModule>
}

export interface StartDwebKeyboardOverlayOptions extends ApplyDwebKeyboardOverlayOptions {
maxAttempts?: number
retryDelayMs?: number
}

async function defaultLoadPlugins(): Promise<DwebPluginsModule> {
const moduleName = '@plaoc/plugins'
const module = await import(/* @vite-ignore */ moduleName)
const module = await import('@plaoc/plugins')
return module as DwebPluginsModule
}

Expand Down Expand Up @@ -51,43 +45,3 @@ export async function applyDwebKeyboardOverlay(
return false
}
}

/**
* 启动键盘 overlay 应用流程(包含重试),用于规避运行时初始化时机过早导致的失效。
*/
export function startDwebKeyboardOverlay(
options: StartDwebKeyboardOverlayOptions = {},
): () => void {
const maxAttempts = Math.max(1, options.maxAttempts ?? 10)
const retryDelayMs = Math.max(50, options.retryDelayMs ?? 300)
let stopped = false
let timer: ReturnType<typeof setTimeout> | null = null
let attempts = 0

const run = async (): Promise<void> => {
if (stopped) {
return
}

const applied = await applyDwebKeyboardOverlay(options)
attempts += 1

if (applied || stopped || attempts >= maxAttempts) {
return
}

timer = setTimeout(() => {
void run()
}, retryDelayMs)
}

void run()

return () => {
stopped = true
if (timer !== null) {
clearTimeout(timer)
timer = null
}
}
}
5 changes: 5 additions & 0 deletions src/providers/AppInitializer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MigrationRequiredView } from '@/components/common/migration-required-vi
import { LoadingSpinner } from '@/components/common'
import { DwebUpdateDialog } from '@/components/common/dweb-update-dialog'
import { dwebUpdateActions } from '@/stores/dweb-update'
import { applyDwebKeyboardOverlay } from '@/lib/dweb-keyboard-overlay'

// 立即执行:在 React 渲染之前应用缓存的主题色,避免闪烁
initializeThemeHue()
Expand All @@ -35,6 +36,10 @@ export function AppInitializer({ children }: { children: ReactNode }) {
const chainConfigLoading = useChainConfigLoading()
const walletLoading = useWalletLoading()

useEffect(() => {
void applyDwebKeyboardOverlay()
}, [])

useEffect(() => {
// 统一初始化所有需要持久化的 store
if (!addressBookState.isInitialized) {
Expand Down
5 changes: 0 additions & 5 deletions src/service-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
installLegacyAuthorizeHashRewriter,
rewriteLegacyAuthorizeHashInPlace,
} from '@/services/authorize/deep-link'
import { startDwebKeyboardOverlay } from '@/lib/dweb-keyboard-overlay'

export type ServiceMainCleanup = () => void

Expand All @@ -18,9 +17,6 @@ export function startServiceMain(): ServiceMainCleanup {
// Normalize legacy mpay-style authorize deep links before Stackflow reads URL.
rewriteLegacyAuthorizeHashInPlace()

// DWEB: keep viewport stable when soft keyboard appears.
const cleanupKeyboardOverlay = startDwebKeyboardOverlay()

// Initialize preference side effects (i18n + RTL) as early as possible.
preferencesActions.initialize()

Expand All @@ -37,6 +33,5 @@ export function startServiceMain(): ServiceMainCleanup {

return () => {
cleanupDeepLink()
cleanupKeyboardOverlay()
}
}