Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | // lib/core/policies/policy-manager.ts import mobile from './defaults.mobile.json'; import tablet from './defaults.tablet.json'; import desktop from './defaults.desktop.json'; import { detectDeviceKind, prefersReducedMotion, isLowEndHardware } from './detectors'; import type { Policy, DeviceKind } from './types'; const STORAGE_DEVICE_KEY = 'DEVICE_KIND'; const STORAGE_POLICY_KEY = 'OS_LAST_POLICY'; function deepMerge<T>(base: T, patch?: Partial<T>): T { if (!patch) return base; const out: any = Array.isArray(base) ? [...(base as any)] : { ...(base as any) }; for (const k of Object.keys(patch)) { const v = (patch as any)[k]; if (v && typeof v === 'object' && !Array.isArray(v)) out[k] = deepMerge((out as any)[k] ?? {}, v); else out[k] = v; } return out; } export class PolicyManager { private cached: Policy | null = null; private overrides: Partial<Policy> | null = null; /** محاولة قراءة آخر سياسة محفوظة (للاختبارات/الإقلاع السريع) */ private readLastPolicy(): Policy | null { try { const raw = sessionStorage.getItem(STORAGE_POLICY_KEY); return raw ? (JSON.parse(raw) as Policy) : null; } catch { return null; } } private writeLastPolicy(p: Policy) { try { sessionStorage.setItem(STORAGE_POLICY_KEY, JSON.stringify(p)); } catch {} } compute(device?: DeviceKind): Policy { // === Context Cache: احترم الجهاز المخزون إن لم يُمرَّر يدويًا let kind: DeviceKind | undefined = device; if (!kind) { try { const cachedKind = sessionStorage.getItem(STORAGE_DEVICE_KEY) as DeviceKind | null; kind = cachedKind ?? detectDeviceKind(); } catch { kind = detectDeviceKind(); } } // اكتب نوع الجهاز المختار للذاكرة القصيرة try { sessionStorage.setItem(STORAGE_DEVICE_KEY, kind!); } catch {} const base: Policy = kind === 'mobile' ? (mobile as Policy) : kind === 'tablet' ? (tablet as Policy) : (desktop as Policy); const reduceMotion = prefersReducedMotion(); const lowEnd = isLowEndHardware(); // === Policy confidence heuristic const confidence = kind === 'desktop' ? 1 : kind === 'tablet' ? 0.9 : 0.8; let adjusted: Policy = deepMerge(base, { ui: { animations: reduceMotion ? 'reduced' : base.ui.animations }, behavior: { perfMode: base.behavior.perfMode || lowEnd }, meta: { confidence }, }); if (this.overrides) adjusted = deepMerge(adjusted, this.overrides); this.cached = adjusted; this.writeLastPolicy(adjusted); return adjusted; } setOverrides(o: Partial<Policy>) { this.overrides = deepMerge(this.overrides ?? {}, o); this.cached = null; } clearOverrides() { this.overrides = null; this.cached = null; } getCached(): Policy | null { if (this.cached) return this.cached; return this.readLastPolicy(); } } export const policyManager = new PolicyManager(); |