forked from MajortomVR/simple-timer-extension
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprefs.js
More file actions
190 lines (160 loc) · 6.62 KB
/
prefs.js
File metadata and controls
190 lines (160 loc) · 6.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import Gtk from 'gi://Gtk';
import Adw from 'gi://Adw';
import Gdk from 'gi://Gdk';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
import * as Settings from './src/Settings.js';
import * as Misc from './src/misc.js';
export default class SimpleTimerPreferences extends ExtensionPreferences {
fillPreferencesWindow(window) {
const settings = new Settings.Settings(this.getSettings());
// Main Page
const mainPage = new Adw.PreferencesPage({
title: 'General',
icon_name: 'dialog-information-symbolic',
});
window.add(mainPage);
// Custom alert sound file chooser
const alertGroup = new Adw.PreferencesGroup({ title: 'Alert' });
alertGroup.add( createFileChooser(window, 'Select custom sound file', (file) => settings.setCustomAlertSfxFile(file), () => settings.getCustomAlertSfxFile()) );
// Custom Keyboard Shortcut
const customKeyboardGroup = new Adw.PreferencesGroup({ title: 'Hotkey' });
customKeyboardGroup.add( createHotkeyInput(window, 'Hotkey', 'Hotkey to start the timer.', settings, settings.getAlertStartHotkeyID()) );
mainPage.add(alertGroup);
mainPage.add(customKeyboardGroup);
}
}
/**
* Create a new Hotkey-Customizer ActionRow
* @param {object} parent window
* @param {string} title Action row title text
* @param {string} description Action row subtitle description text
* @param {Settings} settings Settings object
* @param {string} hotkeyID The schema name of the hotkey
* @returns {Adw.ActionRow}
*/
function createHotkeyInput(parent, title, description, settings, hotkeyID) {
const hotkeyRow = new Adw.ActionRow({
title: title,
subtitle: description
});
// Displays the shortcut
const shortcutLabel = new Gtk.ShortcutLabel({
accelerator: settings.getHotkey(hotkeyID),
disabled_text: 'Set a hotkey',
valign: Gtk.Align.CENTER,
halign: Gtk.Align.CENTER,
});
hotkeyRow.add_suffix(shortcutLabel);
hotkeyRow.activatable_widget = shortcutLabel;
// Update the displayed hotkey label whenever the associated setting changes
settings.getSettings().connect(`changed::${hotkeyID}`, () => {
shortcutLabel.set_accelerator(settings.getHotkey(hotkeyID));
});
let isCapturing = false;
const controller = new Gtk.EventControllerKey();
// Waiting on key pressed
controller.connect('key-pressed', (_, keyval, keycode, state) => {
if (!isCapturing) return Gdk.EVENT_PROPAGATE;
const mod = state & Gtk.accelerator_get_default_mod_mask();
// Escape cancels capturing mode
if (!mod && keyval === Gdk.KEY_Escape) {
isCapturing = false;
shortcutLabel.set_accelerator(settings.getHotkey(hotkeyID));
shortcutLabel.disabled_text = 'Set a hotkey';
return Gdk.EVENT_STOP;
}
if (!mod || !Gtk.accelerator_valid(keyval, mod)) return Gdk.EVENT_STOP;
// Save the new shortcut
const shortcut = Gtk.accelerator_name_with_keycode(
null,
keyval,
keycode,
mod
);
settings.setHotkey(hotkeyID, shortcut);
isCapturing = false;
return Gdk.EVENT_STOP;
});
// Activated (clicked) hotkey configuration
hotkeyRow.connect('activated', () => {
isCapturing = true;
shortcutLabel.set_accelerator('');
shortcutLabel.disabled_text = 'Set a hotkey ...';
});
hotkeyRow.add_controller(controller);
return hotkeyRow;
}
/**
* Create a new File-Chooser ActionRow
* @param {object} parent window
* @param {string} title string
* @param {function} onSetAudioFile callback function executed to set(write) the audio filepath
* @param {function} onGetAudioFile callback function executed to get(read) the audio filepath.
* @returns {Adw.ActionRow}
*/
function createFileChooser(parent, title, onSetAudioFile, onGetAudioFile) {
const soundFileButton = new Adw.ActionRow({ title: title });
// Warning Icon
const warningIcon = new Gtk.Image({ icon_name: 'dialog-warning-symbolic' });
warningIcon.set_tooltip_text('File not found');
// Select File Button
const fileIcon = new Gtk.Image({ icon_name: 'folder-open-symbolic' });
const fileButton = new Gtk.Button({ valign: Gtk.Align.CENTER });
fileButton.set_child(fileIcon);
fileButton.set_tooltip_text('Select file');
// Delete Button
const deleteIcon = new Gtk.Image({ icon_name: 'user-trash-symbolic' });
const deleteButton = new Gtk.Button({ valign: Gtk.Align.CENTER });
deleteButton.set_child(deleteIcon);
deleteButton.set_tooltip_text('Remove custom sound file');
// Add Icons and Buttons
soundFileButton.add_prefix(warningIcon);
soundFileButton.add_suffix(fileButton);
soundFileButton.add_suffix(deleteButton);
// Reset the custom sfx file
deleteButton.connect('clicked', () => {
onSetAudioFile('');
onUpdate();
});
// Open the file chooser
fileButton.connect('clicked', () => {
// Create a row for selecting a custom sound effect file
const filechooser = new Gtk.FileChooserDialog({
title: title,
transient_for: parent,
modal: true,
action: Gtk.FileChooserAction.OPEN,
});
filechooser.add_button('Cancel', Gtk.ResponseType.CANCEL);
filechooser.add_button('OK', Gtk.ResponseType.ACCEPT);
// Filter by mime types
const mimeTypes = ['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/flac'];
const filter = new Gtk.FileFilter();
for (const mimeType of mimeTypes) {
filter.add_mime_type(mimeType);
}
filechooser.set_filter(filter);
// Handle filechooser response
filechooser.connect('response', (dialog, responseID) => {
if (responseID === Gtk.ResponseType.ACCEPT) {
const selectedFile = dialog.get_file().get_path();
if (Misc.fileExists(selectedFile)) {
onSetAudioFile(selectedFile);
onUpdate();
}
}
dialog.destroy();
});
filechooser.show();
});
function onUpdate() {
const file = onGetAudioFile();
soundFileButton.subtitle = file || 'No file selected';
warningIcon.set_visible(file && !Misc.fileExists(file));
deleteButton.set_visible(file);
}
onUpdate();
return soundFileButton;
}