Review of "PanelMate Timer" version 1.0 (1)

Details Page Preview

Timer, stopwatch, Pomodoro and time stats in your top bar. Countdown and Pomodoro modes, a stopwatch with laps, tasks and projects, searchable history, weekly to yearly stats, and fifteen clock styles that follow your light/dark appearance and accent color.

Extension Homepage
https://github.com/bilalmkhalil/panelmate-timer

No comments.

FAQ

Files

Note: Binary files aren't shown on the web site. To see all files, please download the extension zipfile.

Shexli (experimental) warning 2

Shexli found 2 issues that may need reviewer attention.

EGO-L-002 warning

objects created by extension should be destroyed in disable()

Objects assigned in `enable()` are missing matching `.destroy()` calls in `disable()` or its helper methods.

Destroy all objects

  • extension.js:722
    this._historySearch = new St.Entry({hint_text:'Search timer and stopwatch history…', text:this._historyQuery ?? '', style_class:'history-search', can_focus:true, x_expand:true})
  • extension.js:118
    this._icon = new St.Icon({...(brand ? {gicon: brand} : {icon_name: 'alarm-symbolic'}), icon_size: 18, style_class: 'system-status-icon'})
  • extension.js:438
    this._lapButton = new St.Button({child: lapContent, style_class: 'timer-control panelmate-action', can_focus: true, reactive: true, track_hover: true})
  • extension.js:420
    this._play = new St.Button({child: this._playIcon, style_class: 'timer-play panelmate-action', can_focus: true, reactive: true, track_hover: true})
  • extension.js:419
    this._playIcon = new St.Icon({icon_name: 'media-playback-start-symbolic', icon_size: 18})
  • extension.js:775
    this._renameEditor = editor

EGO-L-003 warning

signals connected by extension should be disconnected in disable()

Signals assigned in `enable()` are missing matching disconnect calls in `disable()` or its helper methods.

Disconnect all signals

  • extension.js:725
    this._historySearch.clutter_text.connect('text-changed',()=>{this._historyQuery=this._historySearch.get_text();this._renderHistoryList();})
  • extension.js:343
            this._indicator.menu.connect('open-state-changed', (_menu, open) => {
                if (!open) this._finishRename?.();
            })
  • extension.js:441
    this._lapButton.connect('clicked', () => { if (this._state.lap()) { this._save(); this._update(); } })
  • extension.js:346
            this._panel.connect('captured-event', (_actor, event) => {
                if (this._handlePanelKey(event) === Clutter.EVENT_STOP) return Clutter.EVENT_STOP;
                if (this._renameEditor && event.type() === Clutter.EventType.BUTTON_PRESS) {
                    const [x, y] = event.get_coords()
  • extension.js:422
    this._play.connect('clicked', () => this._playPause())
  • extension.js:397
    this._resetButton.connect('clicked', () => this._reset())
  • extension.js:730
    this._undoButton.connect('clicked',()=>this._undoDelete())
  • extension.js:561
    entry.clutter_text.connect('activate', () => { this._save(); this._play?.grab_key_focus(); })
  • extension.js:588
    entry.clutter_text.connect('activate', () => { if (entry.get_text().trim()) choose(entry.get_text()); })
  • extension.js:782
    editor.clutter_text.connect('activate', () => finish())
  • extension.js:69
    actor.connect('button-press-event', hide)
  • extension.js:71
    actor.connect('destroy', hide)
  • extension.js:67
    actor.connect('key-focus-in', show)
  • extension.js:68
    actor.connect('key-focus-out', hide)
  • extension.js:66
    actor.connect('notify::hover', () => actor.hover ? show() : hide())
  • extension.js:70
    actor.connect('notify::mapped', () => { if (!actor.mapped) hide(); })
  • extension.js:394
    appearance.connect('clicked', () => { this._buildAppearancePage(); this._styleButtons.find(([style]) => style === this._style)?.[1].grab_key_focus(); })
  • extension.js:428
    control.connect('clicked', () => { this._adjustTime(delta); })
  • extension.js:829
    control.connect('clicked',()=>this._buildProjectPage(page))
  • extension.js:657
    done.connect('clicked', () => { this._buildClockPage(); this._appearanceButton?.grab_key_focus(); })
  • extension.js:844
    done.connect('clicked',back)
  • extension.js:535
    info.connect('clicked', () => { this._indicator.menu.close(); this.openPreferences(); })
  • extension.js:601
    item.connect('clicked', () => choose(project))
  • extension.js:855
    item.connect('clicked',()=>{this._projectFilter=project;this._openPage(returnPage);})
  • extension.js:562
    entry.clutter_text.connect('key-focus-out', () => this._save())
  • extension.js:781
    editor.clutter_text.connect('key-focus-out', () => finish())
  • extension.js:783
                editor.clutter_text.connect('key-press-event', (_text, event) => {
                    if (event.get_key_symbol() === Clutter.KEY_Escape) { finish(true); return Clutter.EVENT_STOP; }
                    return Clutter.EVENT_PROPAGATE;
                })
  • extension.js:788
                name.connect('clicked', () => {
                    const now = GLib.get_monotonic_time() / 1000;
                    const interval = Clutter.Settings.get_default().double_click_time;
                    if (lastClick && now - lastClick <= interval) { lastClick = 0; rename(); }
                    else
  • extension.js:794
                name.connect('key-press-event', (_actor, event) => {
                    if (event.get_key_symbol() === Clutter.KEY_F2) { rename(); return Clutter.EVENT_STOP; }
                    return Clutter.EVENT_PROPAGATE;
                })
  • extension.js:244
    option.connect('clicked',()=>{this._statisticsPeriod=period;this._buildStatisticsPage();this._periodButton?.grab_key_focus();})
  • extension.js:480
                option.connect('clicked', () => {
                    option.checked = selected;
                    if (!selected) this._switchTimerMode(enable);
                })
  • extension.js:391
    preferences.connect('clicked', () => { this._indicator.menu.close(); this.openPreferences(); })
  • extension.js:456
                preset.connect('clicked', () => {
                    this._selectPreset(minutes);
                    this._play?.grab_key_focus();
                })
  • extension.js:624
            remove.connect('clicked', () => {
                // The first click asks for confirmation inside the row; the second deletes.
                if (!armed) {
                    armed = true;
                    remove.set_child(new St.Label({text: 'Delete', y_align: Clutter.ActorAlign.CENTER}));
               
  • extension.js:814
    remove.connect('clicked', () => this._deleteRecord(entry))
  • extension.js:818
    repeat.connect('clicked',()=>this._prepareTimer(entry.durationMs,{task:entry.name,project:entry.project},false,entry.pomodoro ?? (entry.phase ? {enabled:true,phase:entry.phase,round:1} : null)))
  • extension.js:805
                    reveal.connect('clicked', () => {
                        lapList.visible = !lapList.visible;
                        reveal.set_label(`${entry.laps.length} laps ${lapList.visible ? '▴' : '▾'}`);
                        reveal.accessible_name = `${entry.laps.length} laps, ${lapList.visible ? 'ex
  • extension.js:538
    skip.connect('clicked', () => { this._skipPhase(); this._play?.grab_key_focus(); })
  • extension.js:1031
    source.connect('destroy', () => { this._notificationSource = null; })
  • extension.js:184
    tab.connect('clicked', () => { this._openPage(id); this._tabs.get(id)?.grab_key_focus(); })
  • extension.js:185
                tab.connect('key-press-event', (_actor, event) => {
                    const ids = ['timer', 'stopwatch', 'history', 'statistics'];
                    const key = event.get_key_symbol();
                    let next = ids.indexOf(id);
                    if (key === Clutter.KEY_Right) next = (next + 1
  • extension.js:557
            entry.clutter_text.connect('text-changed', () => {
                this._state.details[mode].task = entry.get_text().trim().slice(0, 80);
                syncClear();
            })
  • extension.js:128
    this._systemSettings.connect(`changed::${key}`, () => {
                        this._refreshSystemTheme();
                    })

All Versions

Version Status
1.0 (1) Unreviewed