/* OK ITHAKI R10F42 — FINAL NOTIFICATION OWNER / FULL SETTINGS / BIL EXACTLY ONCE */
(()=>{'use strict';
if(window.__ITHAKI_R10F42_NOTIFICATION_CENTER__)return;
window.__ITHAKI_R10F42_NOTIFICATION_EXCLUSIVE__=true;
window.__ITHAKI_R10F42_NOTIFICATION_CENTER__={version:'249526r10f42',singleOwner:true,fullSettings:true,bilExactlyOnce:true,at:Date.now()};
const I=()=>window.ITH=window.ITH||{}, S=()=>window.state||I().state||{}, $=id=>document.getElementById(id);
const STORE={
  prefs:'ithaki_r10f42_notification_preferences',
  read:'ithaki_r10f42_local_read_keys',
  seen:'ithaki_r10f42_bil_seen_ids',
  initialized:'ithaki_r10f42_bil_initialized',
  initializedAt:'ithaki_r10f42_bil_initialized_at'
};
const defaults={
  master:true, mode:'hybrid', bil:true, bilVoice:true, bilVisual:true,
  sound:true, vibration:true, quiet:false, quietStart:'22:30', quietEnd:'07:30',
  urgentDuringQuiet:true,
  categories:{messages:true,calls:true,friends:true,reactions:true,mentions:true,followers:true,comments:true,replies:true,posts:true,communities:true,external:true,security:true,system:true}
};
const runtime={open:false,tab:'new',items:[],loading:false,queue:[],announcing:false,lastSync:0,diag:{lastFetchAt:0,lastFetchCount:0,lastQueuedAt:0,lastAnnouncedAt:0,lastAnnouncedKey:'',lastSuppressedReason:'',lastError:'',firstBootRecent:0,firstBootBaseline:0}};
const esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
const clone=o=>JSON.parse(JSON.stringify(o));
function prefs(){let p=clone(defaults);try{const x=JSON.parse(localStorage.getItem(STORE.prefs)||'{}');p=Object.assign(p,x||{});p.categories=Object.assign({},defaults.categories,x&&x.categories||{})}catch(_e){}return p}
function savePrefs(p){p=Object.assign(clone(defaults),p||{});p.categories=Object.assign({},defaults.categories,p.categories||{});try{localStorage.setItem(STORE.prefs,JSON.stringify(p));localStorage.setItem('ith525_notifications_enabled',p.master?'1':'0');localStorage.setItem('ith525_bil_enabled',p.bil?'1':'0');localStorage.setItem('ith525_sound_enabled',p.sound?'1':'0');localStorage.setItem('ithaki_push_mode_v249258',nativeMode(p.mode))}catch(_e){}applyNative(p);return p}
function setOf(k){try{return new Set(JSON.parse(localStorage.getItem(k)||'[]'))}catch(_e){return new Set()}}
function saveSet(k,s,max=2400){try{localStorage.setItem(k,JSON.stringify([...s].slice(-max)))}catch(_e){}}
function lang(){return String(document.documentElement.lang||localStorage.getItem('ith_ui_lang_v249141')||localStorage.getItem('ith_ui_lang')||'el').toLowerCase().startsWith('en')?'en':'el'}
function t(el,en){return lang()==='en'?en:el}
function room(){return String(S().room||localStorage.getItem('ith_room')||'ithaki-phone-test')}
function device(){return String(S().device||S().deviceId||localStorage.getItem('ith_device')||localStorage.getItem('ith_device_id')||localStorage.getItem('ithaki_device_id')||'')}
function nickname(){return String(S().name||S().nickname||localStorage.getItem('ith_name')||localStorage.getItem('ith_nickname')||'Μέλος')}
function api(path){let b=String(S().api||'').replace(/\/+$/,'');if(!b||/appassets\.androidplatform\.net/i.test(b))b='https://ok-ithaki.gr';return /^https?:/i.test(path)?path:b+path}
async function getJson(path){const r=await fetch(api(path),{cache:'no-store',credentials:'include'});if(!r.ok)throw Error('HTTP '+r.status);return r.json()}
async function postJson(path,data){const r=await fetch(api(path),{method:'POST',cache:'no-store',credentials:'include',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)});if(!r.ok)throw Error('HTTP '+r.status);return r.json()}
function created(x){let n=Number(x.updated_at||x.created_at||x.time||x.ts||x.timestamp||0);if(n&&n<2e10)n*=1000;return n||0}
function rawType(x){return String(x.type||x.kind||x.event_type||x.action||'notification').toLowerCase()}
function category(x){const q=rawType(x);if(/voice_call|video_call|incoming_call|missed_call|\bcall\b/.test(q))return'calls';if(/message|\bdm\b|chat|secure_message/.test(q))return'messages';if(/friend|contact|request/.test(q))return'friends';if(/like|reaction|heart/.test(q))return'reactions';if(/mention/.test(q))return'mentions';if(/follow/.test(q))return'followers';if(/reply/.test(q))return'replies';if(/comment/.test(q))return'comments';if(/post|publication|video|photo|story/.test(q))return'posts';if(/community|room|space/.test(q))return'communities';if(/external|email|viber|sms|mms|whatsapp|telegram/.test(q))return'external';if(/security|admin|legal|report|warning|ban/.test(q))return'security';return'system'}
function groupType(x){const c=category(x);return c==='messages'?'message':c==='calls'?'call':c==='friends'?'friend_request':c==='reactions'?'reaction':c==='mentions'?'mention':c==='followers'?'follow':c==='comments'?'comment':c==='replies'?'reply':c==='posts'?'post':c==='communities'?'community':c==='external'?'external':c==='security'?'security':'system'}
function norm(s){return String(s||'').trim().toLocaleLowerCase('el').replace(/\s+/g,' ').replace(/[\u0000-\u001f]/g,'').slice(0,180)}
function stableId(x){for(const k of ['message_id','notification_id','event_id','request_id','session_id','comment_id','reply_id','post_id','publication_id','external_id']){const v=String(x&&x[k]||'').trim();if(v)return v}return''}
function semanticKey(x){const gt=groupType(x),actor=String(x.from_id||x.sender_id||x.actor_id||x.peer_id||''),recipient=String(x.to_id||x.recipient_id||device()||''),semantic=norm(x.body||x.text||x.message||x.title||x.from_name||x.sender_name||x.peer_name||''),stamp=created(x),bucket=stamp?Math.floor(stamp/60000):0;return[gt,actor,recipient,semantic,bucket].join('|')}
function canonicalKey(x){const gt=groupType(x),id=stableId(x);return id?gt+':'+id:semanticKey(x)}
function serverNoticeKey(x){return String(x.server_notice_key||x.notice_key||'')}
function localItems(){let a=[];try{a=JSON.parse(localStorage.getItem('ith_notifications')||'[]')||[]}catch(_e){}const read=setOf(STORE.read);return a.filter(x=>x&&x.read!==true&&String(x.status||'unread')!=='read').map(x=>{const y=Object.assign({},x,{source:'local'});y.canonical_key=canonicalKey(y);return y}).filter(x=>!read.has(x.canonical_key))}
async function serverItems(){if(!device())return[];const d=await getJson('/api/notifications/unread/r10f41?room_id='+encodeURIComponent(room())+'&device_id='+encodeURIComponent(device())+'&limit=400');return(d.items||[]).map(x=>{const y=Object.assign({},x,{server_notice_key:String(x.notice_key||''),source:String(x.source||'server')});y.canonical_key=canonicalKey(y);return y})}
function dedupe(a){const primary=new Map(),semantic=new Map();for(const x of a){if(!x)continue;const k=x.canonical_key||canonicalKey(x),sk=semanticKey(x),sid=stableId(x);x.canonical_key=k;x.semantic_key=sk;let o=primary.get(k);if(!o){const candidate=semantic.get(sk);if(candidate&&(!sid||!stableId(candidate)))o=candidate}if(!o){o=x}else if(created(x)>created(o)||(!o.server_notice_key&&x.server_notice_key)){Object.assign(o,x);o.canonical_key=k;o.semantic_key=sk}primary.set(o.canonical_key,o);semantic.set(o.semantic_key,o)}return[...new Set(primary.values())].sort((a,b)=>created(b)-created(a))}
async function fetchUnread(){let server=[];try{server=await serverItems()}catch(_e){}return dedupe([...server,...localItems()])}
function isQuiet(p,now=new Date()){if(!p.quiet)return false;const toMin=s=>{const a=String(s||'00:00').split(':').map(Number);return(a[0]||0)*60+(a[1]||0)},cur=now.getHours()*60+now.getMinutes(),start=toMin(p.quietStart),end=toMin(p.quietEnd);return start===end?true:(start<end?cur>=start&&cur<end:cur>=start||cur<end)}
function allowed(x,p){return p.master&&p.categories[category(x)]!==false}
function urgent(x){return['calls','security'].includes(category(x))}
function titleFor(x){const c=category(x),n=String(x.from_name||x.sender_name||x.nickname||x.peer_name||t('Μέλος','Member'));if(c==='messages')return t('Νέο μήνυμα','New message');if(c==='calls')return t('Κλήση','Call');if(c==='friends')return t('Αίτημα φιλίας','Friend request');if(c==='reactions')return t('Νέα αντίδραση','New reaction');if(c==='mentions')return t('Νέα αναφορά','New mention');if(c==='followers')return t('Νέος ακόλουθος','New follower');if(c==='comments')return t('Νέο σχόλιο','New comment');if(c==='replies')return t('Νέα απάντηση','New reply');if(c==='posts')return t('Νέα δημοσίευση','New post');if(c==='communities')return t('Ενημέρωση κοινότητας','Community update');if(c==='external')return t('Εξωτερικό μήνυμα','External message');if(c==='security')return t('Ασφάλεια και διαχείριση','Safety and administration');return String(x.title||t('Ειδοποίηση ΙΘΑΚΗΣ','ITHAKI notification'))}
function bodyFor(x){const n=String(x.from_name||x.sender_name||x.nickname||x.peer_name||t('Μέλος','Member')),c=category(x);if(x.body||x.text||x.message)return String(x.body||x.text||x.message);if(c==='messages')return t('Νέο μήνυμα από ','New message from ')+n+'.';if(c==='friends')return t('Νέο αίτημα φιλίας από ','New friend request from ')+n+'.';if(c==='reactions')return t('Νέα αντίδραση από ','New reaction from ')+n+'.';if(c==='comments')return t('Νέο σχόλιο από ','New comment from ')+n+'.';if(c==='replies')return t('Νέα απάντηση από ','New reply from ')+n+'.';if(c==='followers')return t('Νέος ακόλουθος: ','New follower: ')+n+'.';return titleFor(x)}
function speechText(x){return titleFor(x)+'. '+bodyFor(x)}
function bell(){return $('ithNotifyFabV249238')||document.querySelector('.ithNotifyFabV249238,[data-notifications-fab]')}
function setBadge(n){const b=bell();if(!b)return;let x=b.querySelector('.r40Badge');if(!x){x=document.createElement('span');x.className='badge r40Badge';b.appendChild(x)}x.textContent=n>99?'99+':String(n);x.hidden=n<1;x.style.setProperty('display',n>0?'grid':'none','important');b.dataset.r10f42Count=String(n);b.setAttribute('aria-label',t('Ειδοποιήσεις ','Notifications ')+n);try{const br=nativeBridge();if(br&&typeof br.resetNotificationBadgeV249525==='function'&&n===0)br.resetNotificationBadgeV249525()}catch(_e){}}
function nativeBridge(){return window.Android||window.IthakiAndroid||window.OKIthakiAndroid||window.NativeAndroid||null}
function nativeMode(m){return m==='open_only'?'open_app':m==='no_closed'?'no_closed':m==='stay_awake'?'background':'fcm_default'}
function safeNative(name,...args){try{const b=nativeBridge();return b&&typeof b[name]==='function'?b[name](...args):null}catch(_e){return null}}
function applyNative(p){safeNative('setNotificationMasterEnabledV249525',!!p.master);safeNative('setNotificationSoundEnabledV249525',!!p.sound);safeNative('setNotificationPreferencesR10F40',JSON.stringify(Object.assign({},p,{nativeMode:nativeMode(p.mode)})));safeNative('save','ithaki_push_mode_v249258',nativeMode(p.mode))}
function fcmStatus(){const b=nativeBridge();let permission=null,token='',diag=null;try{permission=b&&b.getPermissionState?JSON.parse(b.getPermissionState()||'{}'):null}catch(_e){}try{token=b&&b.getFcmToken?String(b.getFcmToken()||''):''}catch(_e){}try{diag=b&&b.getNotificationDiagnosticsR10F42?JSON.parse(b.getNotificationDiagnosticsR10F42()||'{}'):(b&&b.getNotificationDiagnosticsR10F40?JSON.parse(b.getNotificationDiagnosticsR10F40()||'{}'):null)}catch(_e){}return{android:!!b,permission,token,diag}}
function ensureCss(){if($('r40NotificationCss'))return;const s=document.createElement('style');s.id='r40NotificationCss';s.textContent=`
.r40Badge{position:absolute!important;top:-7px!important;right:-7px!important;min-width:22px!important;height:22px!important;padding:0 5px!important;place-items:center!important;border-radius:999px!important;background:#ff4068!important;color:#fff!important;border:2px solid #071722!important;font-size:11px!important;font-weight:900!important;z-index:10!important}
#ith526BilDock[data-r10f42-owner="1"]{display:flex!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;align-items:center!important;gap:8px!important;cursor:pointer!important}
#ith526BilDock[data-r10f42-owner="1"] #ith526BilSpeech{max-width:min(72vw,520px)!important}
.r40Shell{height:100%;overflow:auto;padding:12px 12px calc(var(--bar,72px) + 32px);background:radial-gradient(circle at 85% 0,#12324a 0,#07131f 38%,#040b12 100%);color:#edf8ff}.r40Head{position:sticky;top:0;z-index:8;display:flex;align-items:center;gap:9px;padding:11px;border:1px solid #ffffff20;border-radius:19px;background:#071927f2;box-shadow:0 15px 38px #0008;backdrop-filter:blur(16px)}.r40Head>div{flex:1;min-width:0}.r40Head b{display:block;font-size:16px}.r40Head small{opacity:.68}.r40IconBtn,.r40Btn{border:1px solid #ffffff24;background:#ffffff0d;color:#fff;border-radius:12px;padding:9px 11px;font-weight:750}.r40Btn.primary{background:#32d99222;border-color:#32d99266}.r40Btn.gold{background:#d6ae5520;border-color:#d6ae5570;color:#ffe4a6}.r40Btn.danger{background:#ff596619;border-color:#ff596666}.r40Tabs{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:11px 0}.r40Tab{border:1px solid #ffffff1d;background:#ffffff08;color:#cfe0ea;border-radius:14px;padding:11px;font-weight:900}.r40Tab.on{background:#e7bb5b1f;border-color:#e7bb5b75;color:#ffe6aa}.r40Summary,.r40Privacy{margin:10px 0;padding:12px 14px;border-radius:15px;border:1px solid #e7bb5b38;background:#e7bb5b12;color:#f6deb0;line-height:1.45}.r40Notice{margin:10px 0;padding:14px;border-radius:18px;background:#ffffff0b;border:1px solid #ffffff18}.r40Notice header{display:flex;gap:9px;align-items:flex-start}.r40Notice header>div{flex:1}.r40Notice h3{margin:0 0 5px;font-size:16px}.r40Notice p{margin:0;line-height:1.45;color:#cfe0e9}.r40Notice time{font-size:11px;opacity:.55}.r40Actions{display:flex;gap:7px;flex-wrap:wrap;margin-top:12px}.r40Empty{min-height:220px;display:grid;place-content:center;text-align:center;gap:7px;opacity:.8}.r40Count{display:inline-grid;place-items:center;min-width:29px;height:29px;border-radius:999px;background:#ff4068;color:#fff;font-weight:900}.r40Section{margin:12px 0;padding:14px;border:1px solid #ffffff1a;border-radius:19px;background:#ffffff09}.r40Section h3{margin:0 0 5px}.r40Section>p{margin:0 0 12px;color:#bcd0dc;line-height:1.45}.r40ModeGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:9px}.r40Mode{display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:start;padding:12px;border:1px solid #ffffff1c;border-radius:15px;background:#06131e;color:#eaf7ff;text-align:left}.r40Mode.on{border-color:#43db9a80;background:#43db9a14}.r40Mode b{display:block}.r40Mode small{display:block;margin-top:3px;color:#a9c0ce;line-height:1.35}.r40SwitchRow{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid #ffffff10}.r40SwitchRow:last-child{border-bottom:0}.r40SwitchRow>div{flex:1}.r40SwitchRow b{display:block}.r40SwitchRow small{color:#9fb6c4}.r40Switch{width:48px;height:28px;border:0;border-radius:999px;background:#6f7c85;position:relative}.r40Switch:after{content:"";position:absolute;width:22px;height:22px;left:3px;top:3px;border-radius:50%;background:#fff;transition:.18s}.r40Switch.on{background:#26c785}.r40Switch.on:after{left:23px}.r40Categories{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.r40Check{display:flex;align-items:center;gap:9px;padding:10px;border:1px solid #ffffff16;border-radius:13px;background:#05121c}.r40Check input{width:19px;height:19px}.r40Time{display:grid;grid-template-columns:1fr 1fr;gap:10px}.r40Time label{display:grid;gap:5px;color:#cfe0e9}.r40Time input{background:#06131e;color:#fff;border:1px solid #ffffff22;border-radius:12px;padding:11px}.r40Status{display:grid;gap:7px;padding:11px;border-radius:14px;background:#05121c;border:1px solid #ffffff16}.r40Status code{word-break:break-all;color:#ffe1a0}.r40ButtonRow{display:flex;flex-wrap:wrap;gap:8px;margin-top:11px}@media(max-width:600px){.r40Head small{display:none}.r40ModeGrid{grid-template-columns:1fr}.r40Time{grid-template-columns:1fr 1fr}.r40Shell{padding-left:8px;padding-right:8px}.r40Section{padding:12px}}
`;document.head.appendChild(s)}
function ensureBilDock(){let d=$('ith526BilDock');if(!d){d=document.createElement('button');d.type='button';d.id='ith526BilDock';document.body.appendChild(d)}if(!$('ith526BilSpeech'))d.innerHTML='<span aria-hidden="true">🐢</span><span id="ith526BilSpeech"></span>';d.dataset.r10f42Owner='1';d.onclick=e=>{e.preventDefault();e.stopPropagation();openCenter('settings')};return d}
function authorizeSpeak(txt){const p=prefs();if(!p.master||!p.bil||!p.bilVoice||!txt)return false;if(isQuiet(p)&&!p.urgentDuringQuiet)return false;try{if(!('speechSynthesis'in window)||typeof SpeechSynthesisUtterance==='undefined')return false;const u=new SpeechSynthesisUtterance(txt);u.lang=lang()==='en'?'en-US':'el-GR';u.rate=.94;u.pitch=1;u.volume=1;u.__ithakiR10F42Authorized=true;window.speechSynthesis.speak(u);return true}catch(_e){return false}}
function announce(x){const p=prefs();if(!allowed(x,p)){runtime.diag.lastSuppressedReason='category_or_master_disabled';return}if(!p.bil){runtime.diag.lastSuppressedReason='bil_disabled';return}const txt=speechText(x),d=ensureBilDock(),s=$('ith526BilSpeech');runtime.diag.lastAnnouncedAt=Date.now();runtime.diag.lastAnnouncedKey=x.canonical_key||canonicalKey(x);runtime.diag.lastSuppressedReason='';if(p.bilVisual&&s){s.textContent=txt;s.classList.add('show');d.hidden=false;clearTimeout(announce._hide);announce._hide=setTimeout(()=>s.classList.remove('show'),6500)}if(p.bilVoice&&(!isQuiet(p)||p.urgentDuringQuiet&&urgent(x)))authorizeSpeak(txt);else if(p.bilVoice)runtime.diag.lastSuppressedReason='quiet_hours';if(p.sound&&!p.bilVoice&&(!isQuiet(p)||p.urgentDuringQuiet&&urgent(x)))safeNative('playNotificationSoundV249525')}
function runQueue(){if(runtime.announcing||!runtime.queue.length)return;runtime.announcing=true;const x=runtime.queue.shift();announce(x);setTimeout(()=>{runtime.announcing=false;runQueue()},6800)}
function processFresh(items){const seen=setOf(STORE.seen);let initialized=localStorage.getItem(STORE.initialized)==='1';const now=Date.now(),freshWindow=180000;if(!initialized){let recent=0,baseline=0;for(const x of items){const k=x.canonical_key,sk=x.semantic_key||semanticKey(x),at=created(x);seen.add(k);seen.add(sk);if(at&&now-at>=0&&now-at<=freshWindow&&allowed(x,prefs())){runtime.queue.push(x);recent++}else baseline++}runtime.diag.firstBootRecent=recent;runtime.diag.firstBootBaseline=baseline;saveSet(STORE.seen,seen);localStorage.setItem(STORE.initialized,'1');localStorage.setItem(STORE.initializedAt,String(now));if(recent){runtime.diag.lastQueuedAt=now;runQueue()}return}const fresh=items.filter(x=>!seen.has(x.canonical_key)&&!seen.has(x.semantic_key||semanticKey(x))).sort((a,b)=>created(a)-created(b));for(const x of fresh){seen.add(x.canonical_key);seen.add(x.semantic_key||semanticKey(x));const p=prefs();if(allowed(x,p)){runtime.queue.push(x);runtime.diag.lastQueuedAt=Date.now()}else runtime.diag.lastSuppressedReason='category_or_master_disabled'}saveSet(STORE.seen,seen);runQueue()}
function localMarkRead(x){const read=setOf(STORE.read);read.add(x.canonical_key);saveSet(STORE.read,read);if(x.source==='local'){try{const a=JSON.parse(localStorage.getItem('ith_notifications')||'[]')||[];for(const n of a){if(canonicalKey(n)===x.canonical_key){n.read=true;n.status='read'}}localStorage.setItem('ith_notifications',JSON.stringify(a))}catch(_e){}}}
async function markRead(x){localMarkRead(x);runtime.items=runtime.items.filter(n=>n.canonical_key!==x.canonical_key);render();setBadge(runtime.items.length);if(x.source!=='local'&&device())postJson('/api/notifications/read/r10f41',{room_id:room(),device_id:device(),source:x.source,item_id:x.id||x.event_id||'',notice_key:serverNoticeKey(x)}).catch(()=>{});return true}
async function markAll(){const copy=[...runtime.items];for(const x of copy)localMarkRead(x);runtime.items=[];render();setBadge(0);if(device())postJson('/api/notifications/read-all/r10f41',{room_id:room(),device_id:device()}).catch(()=>{})}
function noticeCard(x){const k=esc(x.canonical_key),peer=esc(String(x.from_id||x.sender_id||x.peer_id||'')),id=esc(String(x.id||x.event_id||'')),request=category(x)==='friends',stamp=created(x);return`<article class="r40Notice" data-key="${k}"><header><div><h3>${esc(titleFor(x))}</h3><p>${esc(bodyFor(x))}</p></div><time>${stamp?esc(new Date(stamp).toLocaleString(lang()==='en'?'en-GB':'el-GR')):''}</time></header><div class="r40Actions">${request?`<button class="r40Btn primary" data-a="accept" data-peer="${peer}" data-id="${id}">✓ ${t('Αποδοχή','Accept')}</button><button class="r40Btn danger" data-a="reject" data-peer="${peer}" data-id="${id}">× ${t('Απόρριψη','Reject')}</button>`:`<button class="r40Btn primary" data-a="open" data-peer="${peer}">${t('Άνοιγμα','Open')}</button>`}<button class="r40Btn" data-a="read">✓ ${t('Διαβασμένο','Read')}</button></div></article>`}
function switchRow(key,title,help,on){return`<div class="r40SwitchRow"><div><b>${title}</b><small>${help}</small></div><button type="button" class="r40Switch ${on?'on':''}" data-pref-toggle="${key}" aria-pressed="${on?'true':'false'}"></button></div>`}
const catLabels={messages:['Μηνύματα','Messages'],calls:['Κλήσεις','Calls'],friends:['Αιτήματα φιλίας','Friend requests'],reactions:['Likes και αντιδράσεις','Likes and reactions'],mentions:['Αναφορές','Mentions'],followers:['Νέοι ακόλουθοι','New followers'],comments:['Σχόλια','Comments'],replies:['Απαντήσεις','Replies'],posts:['Νέες δημοσιεύσεις','New posts'],communities:['Κοινότητες','Communities'],security:['Ασφάλεια και διαχείριση','Safety and administration'],external:['Εξωτερικά μηνύματα','External messages'],system:['Σύστημα ΙΘΑΚΗΣ','ITHAKI system']};
function settingsHtml(){const p=prefs(),f=fcmStatus(),token=f.token?f.token.slice(0,10)+'…'+f.token.slice(-6):t('Δεν υπάρχει ακόμη token','No token yet'),perm=f.permission?esc(JSON.stringify(f.permission)):t('Διαθέσιμο μετά την εγκατάσταση Android APK','Available after installing the Android APK');const modes=[['hybrid','🔔🟢',t('Έξυπνο — FCM + ενεργή σύνδεση','Smart — FCM + active connection'),t('Προτεινόμενο: ενεργό όταν είναι ανοιχτό, FCM όταν κοιμάται.','Recommended: active while open, FCM while sleeping.')],['fcm','🔔',t('FCM — κοιμάται και ειδοποιεί','FCM — sleeps and notifies'),t('Η εφαρμογή μπορεί να κοιμάται και το Firebase την ξυπνά.','The app can sleep and Firebase wakes it.')],['open_only','📱',t('Μόνο όταν είναι ανοιχτή','Only while the app is open'),t('Οικονομία μπαταρίας, χωρίς ειδοποίηση με κλειστή εφαρμογή.','Battery saving, no closed-app notifications.')],['stay_awake','🟢',t('Ενεργό πρόγραμμα — δεν κοιμάται','Active program — stays awake'),t('Ταχύτερο, με μεγαλύτερη κατανάλωση μπαταρίας.','Faster, with higher battery use.')],['no_closed','⛔',t('Χωρίς ειδοποιήσεις κλειστής εφαρμογής','No closed-app notifications'),t('Οι κλήσεις ασφαλείας παραμένουν διαθέσιμες.','Safety calls remain available.')]];return`
<section class="r40Section"><h3>${t('Κύρια λειτουργία','Main operation')}</h3><p>${t('Μία ενιαία ρύθμιση για browser, Android, FCM, ήχο και BIL.','One unified setting for browser, Android, FCM, sound and BIL.')}</p>${switchRow('master',t('Ειδοποιήσεις ενεργές','Notifications enabled'),t('Κλείνει τις συνηθισμένες ειδοποιήσεις, όχι τις επείγουσες ζωντανές κλήσεις.','Disables ordinary notifications, not urgent live calls.'),p.master)}<div class="r40ModeGrid">${modes.map(m=>`<button class="r40Mode ${p.mode===m[0]?'on':''}" data-mode="${m[0]}"><span>${m[1]}</span><span><b>${m[2]}</b><small>${m[3]}</small></span></button>`).join('')}</div></section>
<section class="r40Section"><h3>Firebase / FCM</h3><p>${t('Το FCM είναι προαιρετικό. Για ιδιωτικά μηνύματα μεταφέρει σήμα αφύπνισης και όχι το κείμενο του μηνύματος.','FCM is optional. For private messages it carries a wake signal, not the message text.')}</p><div class="r40Status"><div><b>${t('Περιβάλλον','Environment')}:</b> ${f.android?'Android APK':t('Browser / υπολογιστής','Browser / desktop')}</div><div><b>${t('Άδεια ειδοποιήσεων','Notification permission')}:</b> <code>${perm}</code></div><div><b>FCM token:</b> <code>${esc(token)}</code></div></div><div class="r40ButtonRow"><button class="r40Btn gold" data-native="permission">${t('Ζήτηση άδειας','Request permission')}</button><button class="r40Btn" data-native="fcm">${t('Ανανέωση και σύνδεση FCM','Refresh and connect FCM')}</button><button class="r40Btn" data-native="system">${t('Ρυθμίσεις Android','Android settings')}</button></div></section>
<section class="r40Section"><h3>BIL</h3><p>${t('Κάθε πραγματικά νέο αναγνωριστικό εμφανίζεται και εκφωνείται μόνο μία φορά. Στην πρώτη ενεργοποίηση εκφωνούνται τα καινούργια των τελευταίων 3 λεπτών· τα παλαιότερα μένουν ορατά χωρίς μαζική εκφώνηση.','Each genuinely new identifier is shown and spoken only once. On first activation, items from the last 3 minutes are announced; older items remain visible without mass speech.')}</p>${switchRow('bil',t('BIL ενεργός','BIL enabled'),t('Ο βοηθός εμφανίζει μόνο νέες επιτρεπόμενες ειδοποιήσεις.','The assistant shows only new allowed notifications.'),p.bil)}${switchRow('bilVoice',t('Φωνητική εκφώνηση','Voice announcement'),t('Μία εκφώνηση ανά μοναδική ειδοποίηση.','One announcement per unique notification.'),p.bilVoice)}${switchRow('bilVisual',t('Οπτικό μήνυμα BIL','BIL visual bubble'),t('Το μήνυμα εμφανίζεται μία φορά πάνω από τον BIL.','The message appears once above BIL.'),p.bilVisual)}<div class="r40ButtonRow"><button class="r40Btn" data-test="bil">${t('Δοκιμή BIL μία φορά','Test BIL once')}</button></div></section>
<section class="r40Section"><h3>${t('Ήχος και δόνηση','Sound and vibration')}</h3>${switchRow('sound',t('Ήχος ειδοποίησης','Notification sound'),t('Χρησιμοποιεί τον κανονικό ήχο ειδοποίησης της συσκευής.','Uses the device notification sound.'),p.sound)}${switchRow('vibration',t('Δόνηση','Vibration'),t('Εφαρμόζεται στις εγγενείς ειδοποιήσεις Android.','Applies to native Android notifications.'),p.vibration)}<div class="r40ButtonRow"><button class="r40Btn" data-test="sound">${t('Δοκιμή ήχου','Test sound')}</button></div></section>
<section class="r40Section"><h3>${t('Κατηγορίες','Categories')}</h3><p>${t('Επιλέξτε ακριβώς τι θέλετε να λαμβάνετε.','Choose exactly what you want to receive.')}</p><div class="r40Categories">${Object.keys(catLabels).map(k=>`<label class="r40Check"><input type="checkbox" data-category="${k}" ${p.categories[k]?'checked':''}><span>${catLabels[k][lang()==='en'?1:0]}</span></label>`).join('')}</div><div class="r40ButtonRow"><button class="r40Btn" data-categories="all">${t('Όλες','All')}</button><button class="r40Btn" data-categories="none">${t('Καμία','None')}</button></div></section>
<section class="r40Section"><h3>${t('Ώρες ησυχίας','Quiet hours')}</h3>${switchRow('quiet',t('Ενεργές ώρες ησυχίας','Enable quiet hours'),t('Οι ειδοποιήσεις μένουν στο κέντρο χωρίς ήχο ή φωνή.','Notifications remain in the center without sound or voice.'),p.quiet)}<div class="r40Time"><label>${t('Έναρξη','Start')}<input type="time" data-time="quietStart" value="${esc(p.quietStart)}"></label><label>${t('Λήξη','End')}<input type="time" data-time="quietEnd" value="${esc(p.quietEnd)}"></label></div>${switchRow('urgentDuringQuiet',t('Κλήσεις και ασφάλεια στις ώρες ησυχίας','Calls and safety during quiet hours'),t('Επιτρέπει μόνο επείγουσες κλήσεις και ειδοποιήσεις ασφάλειας.','Allows only urgent calls and safety notifications.'),p.urgentDuringQuiet)}</section>
<section class="r40Section"><h3>🩺 ${t('Ζωντανός έλεγχος R10F42','R10F42 live diagnostics')}</h3><div class="r40Status"><div><b>${t('Τελευταίος συγχρονισμός','Last sync')}:</b> <code>${runtime.lastSync?new Date(runtime.lastSync).toLocaleString():t('Όχι ακόμη','Not yet')}</code></div><div><b>${t('Βρέθηκαν','Fetched')}:</b> <code>${runtime.diag.lastFetchCount||0}</code></div><div><b>${t('Ουρά BIL','BIL queue')}:</b> <code>${runtime.queue.length}</code></div><div><b>${t('Τελευταία εκφώνηση','Last announcement')}:</b> <code>${runtime.diag.lastAnnouncedAt?new Date(runtime.diag.lastAnnouncedAt).toLocaleString():t('Καμία','None')}</code></div><div><b>${t('Αιτία αποκλεισμού','Suppression reason')}:</b> <code>${esc(runtime.diag.lastSuppressedReason||'—')}</code></div><div><b>${t('Σφάλμα','Error')}:</b> <code>${esc(runtime.diag.lastError||'—')}</code></div></div><div class="r40ButtonRow"><button class="r40Btn" data-native="diagnostics">${t('Ανανέωση εγγενούς ελέγχου','Refresh native diagnostics')}</button><button class="r40Btn" data-native="fullscreen">${t('Άδεια πλήρους οθόνης κλήσης','Full-screen call permission')}</button><button class="r40Btn" data-native="battery">${t('Ρυθμίσεις μπαταρίας','Battery settings')}</button></div></section>
<section class="r40Section"><h3>${t('Διαχείριση','Management')}</h3><div class="r40ButtonRow"><button class="r40Btn primary" data-manage="new">${t('Άνοιγμα νέων ειδοποιήσεων','Open new notifications')}</button><button class="r40Btn" data-manage="readall">${t('Όλα διαβασμένα','Mark all read')}</button><button class="r40Btn" data-manage="external">${t('Τοπικό κέντρο άλλων εφαρμογών','Local center for other apps')}</button></div></section>
<div class="r40Privacy">🔒 ${t('Οι ρυθμίσεις αποθηκεύονται κυρίως στη συσκευή. Το FCM δεν πρέπει να περιέχει το ιδιωτικό κείμενο κρυπτογραφημένων μηνυμάτων.','Settings are stored mainly on the device. FCM must not contain the private text of encrypted messages.')}</div>`}
function externalCenterHtml(){const has=!!(I().openProfessionalNotificationOrganizerV249527||I().openExternalMessageCenterV249477||window.openProfessionalNotificationOrganizerV249527);return `<section class="r40Section"><h3>📨 ${t('Κέντρο Εξωτερικών Μηνυμάτων','External message center')}</h3><p>${t('Email, Viber, SMS/MMS και ειδοποιήσεις άλλων εφαρμογών οργανώνονται τοπικά στο Android. Το περιεχόμενο δεν ανεβαίνει στον server της ΙΘΑΚΗΣ.','Email, Viber, SMS/MMS and notifications from other apps are organised locally on Android. Their content is not uploaded to the ITHAKI server.')}</p><div class="r40ModeGrid"><article class="r40Mode on"><span>✉️</span><div><b>Email</b><small>${t('Νέα ειδοποίηση, άνοιγμα αρχικής εφαρμογής, σημείωση και ημερολόγιο.','New notice, open the original app, notes and calendar.')}</small></div></article><article class="r40Mode on"><span>📞</span><div><b>Viber / WhatsApp / Telegram</b><small>${t('Μόνο νέες ειδοποιήσεις, με ξεχωριστή επιλογή ανά πηγή.','Only new notifications, with separate choice per source.')}</small></div></article><article class="r40Mode on"><span>💬</span><div><b>SMS / MMS</b><small>${t('Τοπική οργάνωση χωρίς αντιγραφή του παλιού inbox.','Local organisation without copying the old inbox.')}</small></div></article><article class="r40Mode"><span>🔐</span><div><b>${t('Ιδιωτικότητα Android','Android privacy')}</b><small>${t('Αποθήκευση μόνο στη συσκευή και κρυπτογράφηση μέσω Android Keystore όπου υποστηρίζεται από το APK.','Device-only storage and Android Keystore encryption where supported by the APK.')}</small></div></article></div><div class="r40ButtonRow"><button class="r40Btn primary" data-external="inbox" ${has?'':'disabled'}>📨 ${t('Άνοιγμα πλήρους κέντρου','Open full center')}</button><button class="r40Btn" data-external="calendar" ${has?'':'disabled'}>📅 ${t('Ημερολόγιο ενεργειών','Action calendar')}</button><button class="r40Btn" data-external="access">⚙️ ${t('Άδεια πρόσβασης ειδοποιήσεων','Notification access')}</button></div></section><div class="r40Privacy">🔒 ${t('Κάθε πηγή ενεργοποιείται χωριστά. Η αποθήκευση είναι τοπική από προεπιλογή· προαιρετικός συγχρονισμός μεταφέρει μόνο κρυπτογραφημένο snapshot όταν το ενεργοποιήσει το μέλος.','Each source is enabled separately. Storage is local by default; optional sync transfers only an encrypted snapshot when the member enables it.')}</div>`}
function root(){return $('r40NotificationCenter')}
function render(){const r=root();if(!r||!runtime.open)return;const newTab=runtime.tab==='new',settingsTab=runtime.tab==='settings',externalTab=runtime.tab==='external',cards=runtime.items.map(noticeCard).join('')||`<section class="r40Empty"><b>${t('Δεν υπάρχουν νέες ειδοποιήσεις.','There are no new notifications.')}</b><span>${t('Ό,τι σημειώνεται ως διαβασμένο αφαιρείται από τη λίστα.','Items marked read are removed from the list.')}</span></section>`;const body=newTab?`<div class="r40Summary">${t('Η ειδοποίηση μένει μέχρι να κάνετε ενέργεια ή να πατήσετε «Διαβασμένο».','A notification remains until you act or press “Read”.')}</div><div class="r40ButtonRow"><button class="r40Btn" data-top="sync">↻ ${t('Ανανέωση','Refresh')}</button><button class="r40Btn" data-top="all" ${runtime.items.length?'':'disabled'}>✓ ${t('Όλα διαβασμένα','Mark all read')}</button></div><main>${cards}</main>`:(settingsTab?settingsHtml():externalCenterHtml());r.innerHTML=`<div class="r40Head"><button class="r40IconBtn" data-top="close">‹</button><div><b>${t('Κέντρο ειδοποιήσεων','Notification center')}</b><small>${t('ΙΘΑΚΗ, εξωτερικά μηνύματα και πλήρεις ρυθμίσεις','ITHAKI, external messages and complete settings')}</small></div><span class="r40Count">${runtime.items.length}</span><button class="r40IconBtn" data-top="close">×</button></div><div class="r40Tabs"><button class="r40Tab ${newTab?'on':''}" data-tab="new">🔔 ${t('Νέες','New')} (${runtime.items.length})</button><button class="r40Tab ${externalTab?'on':''}" data-tab="external">📨 ${t('Εξωτερικά','External')}</button><button class="r40Tab ${settingsTab?'on':''}" data-tab="settings">⚙️ ${t('Ρυθμίσεις','Settings')}</button></div>${body}`}
function closeCenter(){runtime.open=false;const m=$('memberMenu');if(m){m.classList.remove('show');m.innerHTML='';delete m.dataset.r10f42Owner}}
async function route(x){const peer=String(x.from_id||x.sender_id||x.peer_id||'');if(category(x)==='messages'&&peer){const f=I().startDM||I().openDMWith;if(typeof f==='function')return f.call(I(),peer)}if(x.url){location.href=x.url;return}if(x.post_id&&typeof I().openFeedPost==='function')return I().openFeedPost(x.post_id)}
async function act(action,x,b){if(action==='read')return markRead(x);if(action==='open'){await markRead(x);closeCenter();return route(x)}if(action==='accept'||action==='reject'){b.disabled=true;const f=I().respondFriendProposalV249233||I().respondFriendProposalV249241||I().respondFriendProposalV249240||I().respondFriendProposalV249223;try{if(typeof f==='function')await f.call(I(),String(x.id||x.event_id||''),action==='accept',String(x.from_id||''),serverNoticeKey(x));await markRead(x)}catch(e){b.disabled=false;alert(t('Δεν ολοκληρώθηκε: ','Failed: ')+(e.message||e))}}}
function updatePref(key,value){const p=prefs();p[key]=value;savePrefs(p);render()}
function bindCenter(m){m.onclick=e=>{const tab=e.target.closest('[data-tab]');if(tab){runtime.tab=tab.dataset.tab;render();return}const top=e.target.closest('[data-top]');if(top){if(top.dataset.top==='close')return closeCenter();if(top.dataset.top==='all')return markAll();if(top.dataset.top==='sync')return sync(true)}const ext=e.target.closest('[data-external]');if(ext){const v=ext.dataset.external;if(v==='access'){safeNative('openNotificationAccessSettingsV249477');return}const f=I().openProfessionalNotificationOrganizerV249527||I().openExternalMessageCenterV249477||window.openProfessionalNotificationOrganizerV249527;if(typeof f==='function'){closeCenter();f(v==='calendar'?'calendar':'inbox')}return}const n=e.target.closest('[data-key]'),a=e.target.closest('[data-a]');if(n&&a){const x=runtime.items.find(v=>v.canonical_key===n.dataset.key);if(x)return act(a.dataset.a,x,a)}const sw=e.target.closest('[data-pref-toggle]');if(sw){const p=prefs(),k=sw.dataset.prefToggle;return updatePref(k,!p[k])}const md=e.target.closest('[data-mode]');if(md)return updatePref('mode',md.dataset.mode);const nv=e.target.closest('[data-native]');if(nv){if(nv.dataset.native==='permission')safeNative('requestNotificationPermission');if(nv.dataset.native==='system'){safeNative('openAppSettings');safeNative('openNotificationAccessSettingsV249477')}if(nv.dataset.native==='fcm'){safeNative('requestNotificationPermission');safeNative('requestFcmToken',room(),device(),nickname(),'https://ok-ithaki.gr');setTimeout(render,1000)}if(nv.dataset.native==='diagnostics'){safeNative('refreshFcmDiagnosticsR10F42');setTimeout(render,700)}if(nv.dataset.native==='fullscreen')safeNative('openFullScreenIntentSettingsR10F42');if(nv.dataset.native==='battery')safeNative('openBatteryOptimizationSettingsR10F42');return}const ts=e.target.closest('[data-test]');if(ts){if(ts.dataset.test==='sound')safeNative('playNotificationSoundV249525');if(ts.dataset.test==='bil'){const x={type:'system',event_id:'r10f42-test-'+Date.now(),title:t('Δοκιμή BIL','BIL test'),body:t('Αυτή είναι μία μοναδική δοκιμαστική ειδοποίηση.','This is one unique test notification.'),created_at:Date.now()/1000};x.canonical_key=canonicalKey(x);announce(x)}return}const cg=e.target.closest('[data-categories]');if(cg){const p=prefs(),v=cg.dataset.categories==='all';Object.keys(p.categories).forEach(k=>p.categories[k]=v);savePrefs(p);render();return}const mg=e.target.closest('[data-manage]');if(mg){if(mg.dataset.manage==='new'){runtime.tab='new';render()}if(mg.dataset.manage==='readall')markAll();if(mg.dataset.manage==='external'){const f=I().openProfessionalNotificationOrganizerV249527||I().openExternalMessageCenterV249477;if(typeof f==='function'){closeCenter();f()}}}};m.onchange=e=>{const c=e.target.closest('[data-category]');if(c){const p=prefs();p.categories[c.dataset.category]=!!c.checked;savePrefs(p)}const ti=e.target.closest('[data-time]');if(ti){const p=prefs();p[ti.dataset.time]=ti.value;savePrefs(p)}}}
async function openCenter(tab='new'){ensureCss();ensureBilDock();const m=$('memberMenu');if(!m)return false;runtime.open=true;runtime.tab=['settings','external'].includes(tab)?tab:'new';m.dataset.r10f42Owner='notifications';m.classList.add('show','fullAvatarMenuV249231');m.innerHTML='<div id="r40NotificationCenter" class="r40Shell"><section class="r40Empty">'+t('Φόρτωση…','Loading…')+'</section></div>';bindCenter(m);await sync(true);return false}
async function sync(renderOpen=false){if(runtime.loading)return;runtime.loading=true;try{const items=await fetchUnread();runtime.items=items;runtime.diag.lastFetchAt=Date.now();runtime.diag.lastFetchCount=items.length;runtime.diag.lastError='';processFresh(items);setBadge(items.length);runtime.lastSync=Date.now();if(runtime.open||renderOpen)render()}catch(e){runtime.diag.lastError=String(e&&e.message||e);if(runtime.open||renderOpen)render()}finally{runtime.loading=false}}
function ingest(text,item){const x=Object.assign({},item||{});if(text&&!x.body&&!x.text)x.body=String(text);if(!created(x))x.created_at=Date.now()/1000;x.canonical_key=canonicalKey(x);x.semantic_key=semanticKey(x);const seen=setOf(STORE.seen);if(seen.has(x.canonical_key)||seen.has(x.semantic_key)){runtime.diag.lastSuppressedReason='duplicate';return false}seen.add(x.canonical_key);seen.add(x.semantic_key);saveSet(STORE.seen,seen);if(!runtime.items.some(n=>n.canonical_key===x.canonical_key)){runtime.items=dedupe([x,...runtime.items]);setBadge(runtime.items.length)}if(allowed(x,prefs())){runtime.queue.push(x);runtime.diag.lastQueuedAt=Date.now();runQueue()}else runtime.diag.lastSuppressedReason='category_or_master_disabled';if(runtime.open)render();return true}
function installOwners(){const o=I();const openNew=()=>openCenter('new'),openSettings=()=>openCenter('settings'),openExternal=()=>openCenter('external');o.notifyCenter=openNew;window.notifyCenter=openNew;o.openNotificationSettingsV249238=openSettings;window.openNotificationSettingsV249238=openSettings;o.renderNotificationModeSettingsV249258=openSettings;window.renderNotificationModeSettingsV249258=openSettings;o.openFullNotificationCenterR10F42=openNew;window.openFullNotificationCenterR10F42=openNew;o.openFullNotificationSettingsR10F42=openSettings;window.openFullNotificationSettingsR10F42=openSettings;o.openExternalNotificationCenterR10F42=openExternal;window.openExternalNotificationCenterR10F42=openExternal;o.refreshNotificationBadgeV249238=()=>sync(false);window.refreshNotificationBadgeV249238=()=>sync(false);o.showBilNotificationV249526=ingest;window.showBilNotificationV249526=ingest;o.showBilNotificationR10F42=ingest;window.showBilNotificationR10F42=ingest;o.showBilNotificationR10F40=ingest;window.showBilNotificationR10F40=ingest;o.showBilNotificationR10F41=ingest;window.showBilNotificationR10F41=ingest;o.openFullNotificationCenterR10F41=openNew;window.openFullNotificationCenterR10F41=openNew;o.openFullNotificationSettingsR10F41=openSettings;window.openFullNotificationSettingsR10F41=openSettings}
function patchBell(){const b=bell();if(!b)return;b.dataset.r10f42Owner='1';b.onclick=e=>{e.preventDefault();e.stopPropagation();openCenter('new')};if(!b.__r10f42Capture){b.addEventListener('click',e=>{e.preventDefault();e.stopImmediatePropagation();openCenter('new')},true);b.__r10f42Capture=1}}
function maintain(){ensureCss();ensureBilDock();installOwners();patchBell();document.querySelectorAll('#ith525BilDock,#ithBilDock,.ithBilDock').forEach(x=>{if(x.id!=='ith526BilDock')x.remove()});if(runtime.open&&$('memberMenu')&&!root()){$('memberMenu').innerHTML='<div id="r40NotificationCenter" class="r40Shell"></div>';bindCenter($('memberMenu'));render()}setBadge(runtime.items.length)}
function boot(){savePrefs(prefs());ensureCss();ensureBilDock();installOwners();maintain();sync(false);setInterval(()=>sync(false),8000);setInterval(maintain,1400);new MutationObserver(()=>{clearTimeout(boot._m);boot._m=setTimeout(maintain,60)}).observe(document.documentElement,{subtree:true,childList:true});addEventListener('pageshow',()=>sync(false));addEventListener('focus',()=>sync(false));document.documentElement.dataset.ithakiNotificationOwner='r10f42-final-professional-owner'}
window.__ITHAKI_R10F42_TEST__={canonicalKey,semanticKey,category,dedupe,stableId};
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot();
})();
