Files
gnome-jarvis/apps/gnome-extension/[email protected]/settings-window.js
T
snxraven af9246151f
Rolling release / release (push) Failing after 1m50s
Updates
2026-09-14 11:31:41 -04:00

115 lines
5.2 KiB
JavaScript

import { accessSettingsPage } from './access-settings.js';
import { obsidianSettingsPage } from './obsidian-settings.js';
import Adw from 'gi://Adw';
import Gtk from 'gi://Gtk';
import Gdk from 'gi://Gdk';
import { SettingsEditor } from './settings-editor.js';
import { BRAND, normalizeAccent } from './brand.js';
const OVERLAY_STYLES = ['tray', 'expanded'];
function applyBrandCss(directory) {
try {
const css = new Gtk.CssProvider();
css.load_from_path(`${directory}/brand/gtk.css`);
Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch {}
}
function brandBanner(directory) {
const row = new Adw.ActionRow({ title: BRAND.product, subtitle: `${BRAND.tagline} · ${BRAND.publisher}` });
try {
const image = Gtk.Image.new_from_file(`${directory}/brand/icons/jarvis-mark.svg`);
image.set_pixel_size(36);
row.add_prefix(image);
} catch {}
row.activatable = false;
return row;
}
function accentRow(settings) {
const current = normalizeAccent(settings.get_string('accent-color'));
const row = new Adw.ActionRow({
title: 'Accent color',
subtitle: 'Gold is the Jarvis default. This tints the HUD immediately.',
});
const box = new Gtk.Box({ spacing: 6, valign: Gtk.Align.CENTER });
for (const accent of BRAND.accents) {
const button = new Gtk.Button({ tooltip_text: accent.label, valign: Gtk.Align.CENTER });
button.add_css_class('circular');
button.add_css_class('jarvis-swatch');
button.add_css_class(`jarvis-swatch-${accent.id}`);
button.set_size_request(24, 24);
button.connect('clicked', () => settings.set_string('accent-color', accent.value));
box.append(button);
}
const entry = new Gtk.Entry({ text: current, width_chars: 9, valign: Gtk.Align.CENTER });
try { entry.get_buffer().set_max_length(7); } catch {}
entry.connect('changed', () => {
const value = normalizeAccent(entry.get_text(), '');
if (value) settings.set_string('accent-color', value);
});
settings.connect('changed::accent-color', () => {
const value = normalizeAccent(settings.get_string('accent-color'));
if (entry.get_text() !== value) entry.set_text(value);
});
row.add_suffix(box);
row.add_suffix(entry);
return row;
}
function strvRow(settings, title, key) {
const row = new Adw.EntryRow({ title });
row.set_text(settings.get_strv(key).join(', '));
row.connect('changed', () => {
const values = row.get_text().split(',').map((item) => item.trim()).filter(Boolean);
settings.set_strv(key, values);
});
return row;
}
function comboRow(settings, title, subtitle, key, values) {
const row = new Adw.ComboRow({ title, subtitle, model: Gtk.StringList.new(values) });
const current = settings.get_string(key);
row.selected = Math.max(0, values.indexOf(current));
row.connect('notify::selected', () => {
const value = values[row.selected];
if (value) settings.set_string(key, value);
});
return row;
}
export function fillSettingsWindow(window, settings, directory) {
window.set_title(BRAND.product);
window.set_default_size(840, 780);
window.search_enabled = true;
applyBrandCss(directory);
const editor = new SettingsEditor(directory, settings);
const intro = new Adw.PreferencesGroup();
intro.add(brandBanner(directory));
const voice = editor.page(window, 'Voice', ['Identity', 'Speech', 'Voice design'], 'audio-speakers-symbolic', true, intro);
window.add(voice);
const listening = editor.page(window, 'Listening', ['Listening', 'Wake and privacy', 'Detection tuning', 'Audio routing'], 'audio-input-microphone-symbolic');
window.add(listening);
const desktop = editor.page(window, 'Desktop', ['Desktop images', 'Camera'], 'preferences-desktop-display-symbolic');
const desktopGroup = new Adw.PreferencesGroup({ title: 'Overlay and shortcuts', description: 'These appearance settings take effect immediately.' });
desktopGroup.add(strvRow(settings, 'Hotkey', 'hotkey'));
desktopGroup.add(accentRow(settings));
desktopGroup.add(comboRow(settings, 'Desktop layout', 'Tray keeps Jarvis in the top bar; expanded opens a conversation panel', 'overlay-style', OVERLAY_STYLES));
desktop.add(desktopGroup);
window.add(desktop);
const models = editor.page(window, 'Models', ['Chat model', 'Agent limits'], 'system-run-symbolic');
const service = new Adw.PreferencesGroup({ title: 'Apply chat model changes' });
const restart = new Adw.ActionRow({ title: 'Restart Jarvis', subtitle: 'Saves your changes and restarts the user service. Ends the current request and desktop grant.' });
const restartButton = new Gtk.Button({ label: 'Save & Restart', valign: Gtk.Align.CENTER });
restartButton.connect('clicked', async () => { restartButton.sensitive = false; try { await editor.restart(); } finally { restartButton.sensitive = true; } });
restart.add_suffix(restartButton); service.add(restart); models.add(service);
window.add(models);
const access = accessSettingsPage(editor, window);
window.add(access);
const obsidian = obsidianSettingsPage(editor, window);
window.add(obsidian);
return { editor, pages: [voice, listening, desktop, models, access, obsidian] };
}