const { useState, useEffect, useRef } = React; const SCREENS = { home:HomeScreen, categories:CategoriesScreen, genre:GenreScreen, library:LibraryScreen, search:SearchScreen, details:DetailsScreen, player:PlayerScreen, settings:SettingsScreen }; const TAB_ROOTS = ['home','categories','library','settings']; const LS = { get(k,d){ try{ const v=localStorage.getItem('matm_'+k); return v?JSON.parse(v):d; }catch(e){ return d; } }, set(k,v){ try{ localStorage.setItem('matm_'+k, JSON.stringify(v)); }catch(e){} } }; function MobileApp(){ const [route,setRoute] = useState({name:'home'}); const [backStack,setBackStack] = useState([]); const [favorites,setFavorites] = useState(()=>LS.get('fav',['aot'])); const [history,setHistory] = useState(()=>LS.get('hist',[ { animeId:'aot', season:2, ep:1, quality:'240p SD', progress:0.02, ts: Date.now()-3600*1000 } ])); const [settings,setSettings] = useState(()=>LS.get('set',{ defaultQuality:'تلقائي', autoPlay:true, resume:true })); const [toastMsg,setToastMsg] = useState(null); const toastTimer = useRef(null); const R = useRef({}); R.current = { route, favorites, history, settings }; const [,force] = useState(0); useEffect(()=>{ MAT.fetchArt().then(()=>force(x=>x+1)); },[]); const ctx = useRef(null); if(!ctx.current){ ctx.current = { go(name, params){ setBackStack(b=>[...b, R.current.route]); setRoute({name, params:params||{}}); }, goTab(name){ setBackStack([]); setRoute({name, params:{}}); }, goBack(){ setBackStack(b=>{ if(!b.length){ setRoute({name:'home',params:{}}); return b; } setRoute(b[b.length-1]); return b.slice(0,-1); }); }, byId(id){ return MAT.all.find(a=>a.id===id); }, isFav(id){ return R.current.favorites.includes(id); }, toggleFav(id){ const had = R.current.favorites.includes(id); setFavorites(f=>{ const n = had? f.filter(x=>x!==id):[...f,id]; LS.set('fav',n); return n; }); this.toast(had? 'أُزيل من المفضلة':'أُضيف إلى المفضلة'); }, get favorites(){ return R.current.favorites; }, get history(){ return [...R.current.history].sort((a,b)=>b.ts-a.ts); }, get settings(){ return R.current.settings; }, continueList(){ return [...R.current.history].sort((a,b)=>b.ts-a.ts) .filter(h=>h.progress>0.005 && h.progress<0.985) .map(h=>({ anime:this.byId(h.animeId), season:h.season, ep:h.ep, quality:h.quality, progress:h.progress })) .filter(x=>x.anime).slice(0,8); }, resume(it){ const a = it.anime || this.byId(it.animeId); this.go('player', { item:a, season: it.season, episode: it.ep, quality: it.quality }); }, playFirst(a){ const h = R.current.history.find(x=>x.animeId===a.id); this.go('player', { item:a, season: h?h.season:1, episode: h?h.ep:1, quality: h?h.quality : (R.current.settings.defaultQuality==='تلقائي'?'1080p WEB-DL':R.current.settings.defaultQuality+' WEB-DL') }); }, recordPlay(a, season, ep, quality, progress){ setHistory(h=>{ const rest = h.filter(x=> !(x.animeId===a.id && x.season===season && x.ep===ep)); const n = [{ animeId:a.id, season, ep, quality, progress, ts:Date.now() }, ...rest].slice(0,30); LS.set('hist', n); return n; }); }, savedPos(id, season, ep){ const e = R.current.history.find(x=>x.animeId===id && x.season===season && x.ep===ep); return e? e.progress : 0; }, setSetting(k,v){ setSettings(s=>{ const n={...s,[k]:v}; LS.set('set',n); return n; }); }, clearHistory(){ setHistory([]); LS.set('hist',[]); }, clearFavorites(){ setFavorites([]); LS.set('fav',[]); }, toast(msg){ setToastMsg(msg); clearTimeout(toastTimer.current); toastTimer.current=setTimeout(()=>setToastMsg(null),2000); }, }; } const ScreenComp = SCREENS[route.name]; const isTabRoot = TAB_ROOTS.includes(route.name) && backStack.length===0; return (
{isTabRoot && }
{toastMsg}
); } ReactDOM.createRoot(document.getElementById('app')).render();