|
|
|
@ -46,6 +46,14 @@ function num(value: unknown): number { |
|
|
|
return typeof value === "number" && Number.isFinite(value) ? value : 0; |
|
|
|
} |
|
|
|
|
|
|
|
function safeParse(value: string): unknown { |
|
|
|
try { |
|
|
|
return JSON.parse(value); |
|
|
|
} catch { |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function readEdges(source: EdgeSource): ViewPaddings { |
|
|
|
return { |
|
|
|
top: num(source?.top), |
|
|
|
@ -99,9 +107,36 @@ class ViewPaddingsBridge { |
|
|
|
if (typeof window === "undefined") return; |
|
|
|
|
|
|
|
this.setupFlutterListener(); |
|
|
|
this.setupConfigEventListener(); |
|
|
|
this.requestConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
// مسیر جایگزین: برخی نسخههای اپ بهجای onFlutterResponse، کانفیگ را با
|
|
|
|
// CustomEvent('flutterConfig') یا postMessage میفرستند (طبق سند پل).
|
|
|
|
// payload در این مسیر همان بدنهی initial_config است (بدون پوشش action/data).
|
|
|
|
private setupConfigEventListener() { |
|
|
|
const handle = (raw: unknown) => { |
|
|
|
if (!raw || typeof raw !== "object") return; |
|
|
|
const data = raw as Record<string, any>; |
|
|
|
// فقط وقتی هنوز initial_config رسمی نرسیده و این payload فضای امن دارد.
|
|
|
|
if (this.hasInitialConfig) return; |
|
|
|
if (!data.safeArea && !data.viewInsets) return; |
|
|
|
this.applyInitialConfig(data); |
|
|
|
}; |
|
|
|
|
|
|
|
window.addEventListener("flutterConfig", (event) => { |
|
|
|
handle((event as CustomEvent).detail); |
|
|
|
}); |
|
|
|
|
|
|
|
window.addEventListener("message", (event) => { |
|
|
|
const data = |
|
|
|
typeof event.data === "string" |
|
|
|
? safeParse(event.data) |
|
|
|
: event.data; |
|
|
|
handle(data); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private setupFlutterListener() { |
|
|
|
const win = window as Window & { |
|
|
|
addFlutterResponseListener?: ( |
|
|
|
|