Skip to content

Commit 430ee7d

Browse files
author
Gurasuraisu
committed
add app perm
1 parent cad01b5 commit 430ee7d

6 files changed

Lines changed: 338 additions & 161 deletions

File tree

assets/gurapp/intl/settings/index.html

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ <h1 class="page-title">Settings</h1>
9292
</div>
9393
<span class="material-symbols-rounded">arrow_forward_ios</span>
9494
</div>
95-
<div class="setting-item nav-item" data-page="page-system">
95+
<div class="setting-item nav-item" data-page="page-general">
9696
<div class="setting-info">
97-
<span class="material-symbols-rounded">manufacturing</span>
98-
<span class="setting-label">System</span>
99-
<span class="setting-description">Adjust system settings</span>
97+
<span class="material-symbols-rounded">page_info</span>
98+
<span class="setting-label">General</span>
99+
<span class="setting-description">Manage your overall setup and perferences</span>
100100
</div>
101101
<span class="material-symbols-rounded">arrow_forward_ios</span>
102102
</div>
@@ -110,11 +110,13 @@ <h1 class="page-title">Settings</h1>
110110
</div>
111111
<span class="material-symbols-rounded">arrow_forward_ios</span>
112112
</div>
113-
<div class="setting-item nav-item" data-page="page-general">
113+
</div>
114+
<div class="setting-section">
115+
<div class="setting-item nav-item" data-page="page-apps">
114116
<div class="setting-info">
115-
<span class="material-symbols-rounded">page_info</span>
116-
<span class="setting-label">General</span>
117-
<span class="setting-description">Manage your overall setup and perferences</span>
117+
<span class="material-symbols-rounded">grid_view</span>
118+
<span class="setting-label">Apps</span>
119+
<span class="setting-description">Manage applications</span>
118120
</div>
119121
<span class="material-symbols-rounded">arrow_forward_ios</span>
120122
</div>
@@ -126,6 +128,14 @@ <h1 class="page-title">Settings</h1>
126128
</div>
127129
<span class="material-symbols-rounded">arrow_forward_ios</span>
128130
</div>
131+
<div class="setting-item nav-item" data-page="page-system">
132+
<div class="setting-info">
133+
<span class="material-symbols-rounded">manufacturing</span>
134+
<span class="setting-label">System</span>
135+
<span class="setting-description">Adjust system settings</span>
136+
</div>
137+
<span class="material-symbols-rounded">arrow_forward_ios</span>
138+
</div>
129139
</div>
130140
<div class="setting-section">
131141
<div class="setting-item nav-item" data-page="page-data">
@@ -263,6 +273,39 @@ <h2 class="section-title">Sound Feedback</h2>
263273
</div>
264274
</div>
265275

276+
<!-- Apps Page -->
277+
<div class="page" id="page-apps">
278+
<div class="setting-section">
279+
<div id="apps-list-container">
280+
<!-- Dynamic list of apps and permissions -->
281+
</div>
282+
</div>
283+
</div>
284+
285+
<!-- App Details Page -->
286+
<div class="page" id="page-app-details">
287+
<div class="setting-section" style="display: flex; flex-direction: column; align-items: center; padding: 25px 20px 20px;">
288+
<img id="detail-app-icon" src="" style="width: 72px; height: 72px; corner-shape: superellipse(1.25); border-radius: 35%; margin-bottom: 12px; object-fit: cover; box-shadow: var(--sun-shadow);">
289+
<h2 id="detail-app-name" style="margin: 0; color: var(--text-color); font-size: 24px;">App Name</h2>
290+
<span id="detail-app-url" style="opacity: 0.5; font-size: 13px; margin-top: 4px; text-align: center; word-break: break-all;">url</span>
291+
292+
<div style="display: flex; gap: 10px; margin-top: 24px; width: 100%;">
293+
<button class="action-btn" id="btn-app-force-stop" style="flex: 1; background-color: var(--search-background); justify-content: center;">Force stop</button>
294+
<button class="action-btn" id="btn-app-uninstall" style="flex: 1; background-color: #ff5252; color: white; border: none; justify-content: center;">Uninstall</button>
295+
</div>
296+
<div style="display: flex; gap: 10px; margin-top: 10px; width: 100%;">
297+
<button class="action-btn" id="btn-app-clear-tracking-data" style="flex: 1; background-color: var(--search-background); justify-content: center;">Clear tracking data</button>
298+
</div>
299+
</div>
300+
301+
<div class="setting-section">
302+
<h2 class="section-title">Permissions</h2>
303+
<div id="detail-app-permissions">
304+
<!-- Toggles injected here -->
305+
</div>
306+
</div>
307+
</div>
308+
266309
<!-- Home Screen Page -->
267310
<div class="page" id="page-homescreen">
268311
<div class="setting-section">
@@ -316,22 +359,6 @@ <h2 class="section-title">Live Activities</h2>
316359
</div>
317360
<input type="checkbox" class="toggle-switch" data-key="homeActivitiesEnabled">
318361
</div>
319-
<div class="setting-item nav-item" data-page="page-live-activities">
320-
<div class="setting-info">
321-
<span class="setting-label">Manage permissions</span>
322-
</div>
323-
<span class="material-symbols-rounded">arrow_forward_ios</span>
324-
</div>
325-
</div>
326-
</div>
327-
<!-- Live Activities Management Page -->
328-
<div class="page" id="page-live-activities">
329-
<div class="setting-section">
330-
<h2 class="section-title">Permissions</h2>
331-
<p class="setting-description" style="margin-bottom: 20px;">Apps that have previously sent a Live Activity appear here.</p>
332-
<div id="live-activity-list-container">
333-
<!-- Dynamic list of apps -->
334-
</div>
335362
</div>
336363
</div>
337364
<!-- Clock Settings Page -->

assets/gurapp/intl/settings/settings.js

Lines changed: 115 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ function initializeSettingsApp() {
1111
'main-settings': 'Settings',
1212
'page-display': 'Display',
1313
'page-sound': 'Sound & Haptics',
14+
'page-apps': 'Apps',
15+
'page-app-details': 'App Details',
1416
'page-homescreen': 'Home Screen',
15-
'page-live-activities': 'Live Activities',
1617
'page-clock': 'Clock',
1718
'page-wallpaper': 'Wallpaper',
1819
'page-system': 'System',
@@ -291,45 +292,128 @@ function initializeSettingsApp() {
291292
}
292293
}
293294

294-
function refreshLiveActivitiesPage() {
295-
const container = document.getElementById('live-activity-list-container');
296-
const senders = JSON.parse(window.parent.localStorage.getItem('appsWithActivities') || '[]');
297-
const blocked = JSON.parse(window.parent.localStorage.getItem('blockedActivities') || '[]');
298-
295+
function refreshAppsListPage() {
296+
const container = document.getElementById('apps-list-container');
299297
container.innerHTML = '';
300-
if (senders.length === 0) {
301-
container.innerHTML = '<p style="text-align:center; opacity:0.5; padding:20px;">No activities recorded.</p>';
298+
299+
const perms = JSON.parse(window.parent.localStorage.getItem('appPermissions') || '{}');
300+
const systemAppsObj = window.parent.apps || {};
301+
const installedAppsObj = JSON.parse(window.parent.localStorage.getItem('userInstalledApps') || '{}');
302+
303+
const allApps = new Set([...Object.keys(installedAppsObj), ...Object.keys(perms)]);
304+
305+
const excludedApps = ['Settings', 'Terminal', 'Donburi', 'kirbStore', 'Apps'];
306+
307+
if (allApps.size === 0) {
308+
container.innerHTML = '<p style="text-align:center; opacity:0.5; padding:20px;">No installed apps found.</p>';
302309
return;
303310
}
304311

305-
senders.forEach(name => {
306-
const item = document.createElement('div');
307-
item.className = 'setting-item';
308-
const isBlocked = blocked.includes(name);
312+
allApps.forEach(appName => {
313+
if (excludedApps.includes(appName)) return;
309314

315+
const appDef = systemAppsObj[appName] || installedAppsObj[appName] || {};
316+
let iconSrc = appDef.icon || 'system.png';
317+
if (!iconSrc.startsWith('http') && !iconSrc.startsWith('/') && !iconSrc.startsWith('data:')) {
318+
iconSrc = `/assets/appicon/${iconSrc}`;
319+
}
320+
321+
const item = document.createElement('div');
322+
item.className = 'setting-item nav-item';
310323
item.innerHTML = `
311-
<div class="setting-info">
312-
<span class="setting-label">${name}</span>
324+
<div class="setting-info" style="display: flex; align-items: center; gap: 12px; flex-direction: row;">
325+
<img src="${iconSrc}" style="width: 36px; height: 36px; border-radius: 35%; object-fit: cover; corner-shape: superellipse(1.25);">
326+
<span class="setting-label">${appName}</span>
313327
</div>
314-
<input type="checkbox" class="toggle-switch" ${!isBlocked ? 'checked' : ''}>
328+
<span class="material-symbols-rounded">arrow_forward_ios</span>
315329
`;
330+
item.onclick = () => openAppDetails(appName, appDef);
331+
container.appendChild(item);
332+
});
333+
}
334+
335+
function openAppDetails(appName, appDef) {
336+
// Setup Header
337+
document.getElementById('detail-app-name').textContent = appName;
338+
document.getElementById('detail-app-url').textContent = appDef.url || 'System App / Unknown URL';
339+
340+
let iconSrc = appDef.icon || 'system.png';
341+
if (!iconSrc.startsWith('http') && !iconSrc.startsWith('/') && !iconSrc.startsWith('data:')) {
342+
iconSrc = `/assets/appicon/${iconSrc}`;
343+
}
344+
document.getElementById('detail-app-icon').src = iconSrc;
345+
346+
// Buttons
347+
document.getElementById('btn-app-force-stop').onclick = () => {
348+
window.parent.postMessage({ action: 'callGurasuraisuFunc', functionName: 'forceCloseAppByName', args: [appName] }, '*');
349+
Gurasuraisu.showPopup(`Force stopped ${appName}`);
350+
};
351+
352+
document.getElementById('btn-app-uninstall').onclick = async () => {
353+
if (await Gurasuraisu.showConfirm(`Are you sure you want to uninstall ${appName}?`)) {
354+
Gurasuraisu.deleteApp(appName);
355+
navigateBack();
356+
setTimeout(refreshAppsListPage, 300);
357+
}
358+
};
316359

317-
const toggle = item.querySelector('input');
318-
toggle.onchange = () => {
319-
let currentBlocked = JSON.parse(window.parent.localStorage.getItem('blockedActivities') || '[]');
320-
if (!toggle.checked) {
321-
if (!currentBlocked.includes(name)) currentBlocked.push(name);
322-
} else {
323-
currentBlocked = currentBlocked.filter(n => n !== name);
360+
document.getElementById('btn-app-clear-tracking-data').onclick = async () => {
361+
if (await Gurasuraisu.showConfirm(`Clear all tracking data and revoke all permissions for ${appName}?`)) {
362+
window.parent.postMessage({ action: 'callGurasuraisuFunc', functionName: 'clearAppData', args: [appName] }, '*');
363+
Gurasuraisu.showPopup(`Data cleared for ${appName}`);
364+
openAppDetails(appName, appDef); // Refresh view to update toggles
365+
}
366+
};
367+
368+
// Permissions List
369+
const permContainer = document.getElementById('detail-app-permissions');
370+
permContainer.innerHTML = '';
371+
372+
const availablePerms = [
373+
{ id: 'notifications', name: 'Notifications' },
374+
{ id: 'live-activity', name: 'Live Activities' },
375+
{ id: 'immersive-mode', name: 'Immersive mode' },
376+
{ id: 'file-upload', name: 'File access' },
377+
{ id: 'widgets', name: 'Widgets' },
378+
{ id: 'media-session', name: 'Media session' },
379+
{ id: 'tts', name: 'Text-to-Speech' },
380+
{ id: 'waves', name: 'Waves remote' },
381+
{ id: 'ui-sounds', name: 'Sound effects' },
382+
{ id: 'app-management', name: 'App management' },
383+
{ id: 'system-admin', name: 'Modify core system settings (root access)' }
384+
];
385+
386+
let currentPerms = JSON.parse(window.parent.localStorage.getItem('appPermissions') || '{}');
387+
let appPerms = currentPerms[appName] || {};
388+
389+
availablePerms.forEach(p => {
390+
const isGranted = appPerms[p.id] === 'granted';
391+
392+
const item = document.createElement('div');
393+
item.className = 'setting-item';
394+
item.innerHTML = `
395+
<span class="setting-label">${p.name}</span>
396+
<input type="checkbox" class="toggle-switch" ${isGranted ? 'checked' : ''}>
397+
`;
398+
399+
item.querySelector('input').onchange = (e) => {
400+
currentPerms = JSON.parse(window.parent.localStorage.getItem('appPermissions') || '{}');
401+
if (!currentPerms[appName]) currentPerms[appName] = {};
402+
currentPerms[appName][p.id] = e.target.checked ? 'granted' : 'denied';
403+
window.parent.localStorage.setItem('appPermissions', JSON.stringify(currentPerms));
404+
405+
// Real-time cleanup if a feature is revoked
406+
if (p.id === 'live-activity' && !e.target.checked) {
407+
window.parent.postMessage({ action: 'callGurasuraisuFunc', functionName: 'stopActivitiesForApp', args: [appName] }, '*');
324408
}
325-
window.parent.localStorage.setItem('blockedActivities', JSON.stringify(currentBlocked));
326-
// Notify parent to stop current activities if blocked
327-
if (!toggle.checked) {
328-
window.parent.postMessage({ action: 'callGurasuraisuFunc', functionName: 'stopActivitiesForApp', args: [name] }, '*');
409+
if (p.id === 'media-session' && !e.target.checked) {
410+
window.parent.postMessage({ action: 'callGurasuraisuFunc', functionName: 'clearMediaSession', args: [appName] }, '*');
329411
}
330412
};
331-
container.appendChild(item);
413+
permContainer.appendChild(item);
332414
});
415+
416+
navigateTo('page-app-details');
333417
}
334418

335419
function bindEventListeners() {
@@ -348,6 +432,10 @@ function initializeSettingsApp() {
348432
if (aboutBtn) {
349433
aboutBtn.addEventListener('click', updateVersionDisplay);
350434
}
435+
const appsListBtn = document.querySelector('.nav-item[data-page="page-apps"]');
436+
if (appsListBtn) {
437+
appsListBtn.addEventListener('click', refreshAppsListPage);
438+
}
351439

352440
backBtn.addEventListener('click', navigateBack);
353441

css/styles.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3474,6 +3474,7 @@ input[type="radio"]:checked::before {
34743474
box-sizing: border-box;
34753475
border-radius: 35px;
34763476
corner-shape: superellipse(1.5);
3477+
box-shadow: 0 5px 20px -10px rgba(0, 0, 0, 0.2);
34773478
}
34783479

34793480
.widget-instance.is-dragging {

0 commit comments

Comments
 (0)