'use strict'; import Adw from 'gi://Adw'; import Gio from 'gi://Gio'; import Gtk from 'gi://Gtk'; import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; export default class QuotesPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { const settings = this.getSettings(); // Behavior Settings Page const behaviorPage = new Adw.PreferencesPage({ title: 'Behavior', icon_name: 'preferences-system-symbolic', }); window.add(behaviorPage); const timingGroup = new Adw.PreferencesGroup({ title: 'Timing Settings', description: 'Configure how quotes are rotated and synced', }); behaviorPage.add(timingGroup); // Rotation interval const rotationRow = new Adw.SpinRow({ title: 'Rotation Interval', subtitle: 'Time in seconds between quote changes', adjustment: new Gtk.Adjustment({ lower: 10, upper: 3600, step_increment: 10, page_increment: 60, value: settings.get_int('rotation-interval'), }), }); timingGroup.add(rotationRow); // Sync interval const syncRow = new Adw.SpinRow({ title: 'Sync Interval', subtitle: 'Time in seconds between API syncs', adjustment: new Gtk.Adjustment({ lower: 300, upper: 86400, step_increment: 300, page_increment: 3600, value: settings.get_int('sync-interval'), }), }); timingGroup.add(syncRow); // API Group const apiGroup = new Adw.PreferencesGroup({ title: 'API Settings', description: 'Configure external quote sources', }); behaviorPage.add(apiGroup); // API URL const apiRow = new Adw.EntryRow({ title: 'API URL', subtitle: 'URL for fetching quotes from remote server', text: settings.get_string('api-url'), }); apiGroup.add(apiRow); // Appearance Settings Page const appearancePage = new Adw.PreferencesPage({ title: 'Appearance', icon_name: 'preferences-desktop-theme-symbolic', }); window.add(appearancePage); const displayGroup = new Adw.PreferencesGroup({ title: 'Display Settings', description: 'Configure how quotes are displayed', }); appearancePage.add(displayGroup); // Font size const fontSizeRow = new Adw.SpinRow({ title: 'Font Size', subtitle: 'Size of quote text in pixels', adjustment: new Gtk.Adjustment({ lower: 8, upper: 32, step_increment: 1, page_increment: 2, value: settings.get_int('font-size'), }), }); displayGroup.add(fontSizeRow); // Text color const colorRow = new Adw.EntryRow({ title: 'Text Color', subtitle: 'Color for quote text in hex format', text: settings.get_string('text-color'), }); displayGroup.add(colorRow); // Maximum width const widthRow = new Adw.SpinRow({ title: 'Maximum Width', subtitle: 'Maximum characters before truncating', adjustment: new Gtk.Adjustment({ lower: 20, upper: 200, step_increment: 5, page_increment: 10, value: settings.get_int('max-width'), }), }); displayGroup.add(widthRow); // Storage Settings Page const storagePage = new Adw.PreferencesPage({ title: 'Storage', icon_name: 'folder-symbolic', }); window.add(storagePage); const storageGroup = new Adw.PreferencesGroup({ title: 'Storage Settings', description: 'Configure data storage options', }); storagePage.add(storageGroup); // Quotes file const quotesFileRow = new Adw.EntryRow({ title: 'Quotes File Name', subtitle: 'JSON file name for storing quotes', text: settings.get_string('quotes-file'), }); storageGroup.add(quotesFileRow); // Quotes Settings Page const quotesPage = new Adw.PreferencesPage({ title: 'Quotes', icon_name: 'text-editor-symbolic', }); window.add(quotesPage); const quotesSourceGroup = new Adw.PreferencesGroup({ title: 'Quote Source', description: 'Choose between built-in/synced quotes or custom quotes', }); quotesPage.add(quotesSourceGroup); // Use custom quotes switch const useCustomQuotesRow = new Adw.SwitchRow({ title: 'Use Custom Quotes', subtitle: 'Use custom quotes instead of built-in/synced quotes', active: settings.get_boolean('use-custom-quotes'), }); quotesSourceGroup.add(useCustomQuotesRow); const customQuotesGroup = new Adw.PreferencesGroup({ title: 'Custom Quotes', description: 'Edit your custom quotes in JSON format', }); quotesPage.add(customQuotesGroup); // Custom quotes text area const quotesTextView = new Gtk.TextView({ editable: true, wrap_mode: Gtk.WrapMode.WORD, hexpand: true, vexpand: true, }); const quotesBuffer = quotesTextView.get_buffer(); const customQuotesText = settings.get_string('custom-quotes'); try { const quotesArray = JSON.parse(customQuotesText); quotesBuffer.set_text(JSON.stringify(quotesArray, null, 2), -1); } catch (e) { quotesBuffer.set_text('[\n {\n "text": "Your custom quote here",\n "author": "Author Name"\n }\n]', -1); } const scrolledWindow = new Gtk.ScrolledWindow({ child: quotesTextView, hexpand: true, vexpand: true, min_content_height: 200, }); const quotesExpander = new Adw.ExpanderRow({ title: 'Custom Quotes Editor', subtitle: 'JSON format: [{"text": "quote", "author": "author"}]', }); quotesExpander.add_row(new Adw.PreferencesRow({ child: scrolledWindow, })); customQuotesGroup.add(quotesExpander); // Bind settings settings.bind( 'rotation-interval', rotationRow, 'value', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'sync-interval', syncRow, 'value', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'api-url', apiRow, 'text', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'font-size', fontSizeRow, 'value', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'text-color', colorRow, 'text', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'max-width', widthRow, 'value', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'quotes-file', quotesFileRow, 'text', Gio.SettingsBindFlags.DEFAULT ); settings.bind( 'use-custom-quotes', useCustomQuotesRow, 'active', Gio.SettingsBindFlags.DEFAULT ); // Save custom quotes when text changes quotesBuffer.connect('changed', () => { const [start, end] = quotesBuffer.get_bounds(); const text = quotesBuffer.get_text(start, end, false); try { // Validate JSON JSON.parse(text); settings.set_string('custom-quotes', text); } catch (e) { // Invalid JSON, don't save } }); } }