Skip to content

Add noctalia-calculator plugin#459

Draft
pir0c0pter0 wants to merge 10 commits intonoctalia-dev:mainfrom
pir0c0pter0:add-noctalia-calculator
Draft

Add noctalia-calculator plugin#459
pir0c0pter0 wants to merge 10 commits intonoctalia-dev:mainfrom
pir0c0pter0:add-noctalia-calculator

Conversation

@pir0c0pter0
Copy link
Copy Markdown
Contributor

@pir0c0pter0 pir0c0pter0 commented Mar 23, 2026

Summary

Theme-aware calculator plugin for Noctalia on Niri.

  • Full expression evaluation with operator precedence via pluginApi.loadHelper("AdvancedMath")
  • Bar widget with live result badge
  • Floating panel with 21-button grid and keyboard support
  • 10-language i18n (en, pt, es, fr, de, it, ru, zh, ja, ko)
  • Settings: decimal precision (0-10), show/hide bar value

Preview

Calculator Preview

Keyboard support

0-9, +-*/, ., Enter, Backspace, Esc, F9 (toggle sign), %

Plugin structure

noctalia-calculator/
├── manifest.json
├── Main.qml
├── BarWidget.qml
├── Panel.qml
├── Settings.qml
├── i18n/ (en, pt, es, fr, de, it, ru, zh, ja, ko)
├── preview.png
├── LICENSE
└── README.md

Changes in latest commit

  • Removed local .gitignore (root repo already handles */settings.json)
  • Removed local AdvancedMath.js copy (uses pluginApi.loadHelper("AdvancedMath") from shell)
  • Removed unnecessary -0 guard in _sanitizeCurrentInput
  • Updated README with preview image, i18n info, and accurate file list

@kevichi7
Copy link
Copy Markdown
Contributor

was waiting for something like this - thanks

Copy link
Copy Markdown
Contributor

@spiros132 spiros132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some feedback about the PR :)

"plugins": []
},
"metadata": {
"commandPrefix": "calculator",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed since there is no LauncherProvider entry point.

"icon": "trash"
},
{
"label": pluginApi?.tr("bar.settings") ?? "Settings",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it comes to translations we don't need to use fallbacks anymore. For example:

// From:
pluginApi?.tr("key") ?? "Value"

// To:
pluginApi?.tr("key")

function _sanitizeCurrentInput() {
if (currentInput === "" || currentInput === "-") return "0";
if (currentInput.endsWith(".")) return currentInput + "0";
if (currentInput === "-0") return "-0";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this if statement is doing anything

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment still persists. This if statement isn't exactly needed

return _formatExpression(built);
}

function evaluate() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The noctalia shell already contains a library for evaluating math expressions. It's the following file.

radius: Style.radiusL
color: Qt.alpha(Color.mPrimary, 0.08)
border.color: root.activeFocus ? Qt.alpha(Color.mPrimary, 0.8) : Qt.alpha(Color.mOutline, 0.65)
border.width: 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use hard-coded values, use the Style singleton instead

./remove.sh
```

This removes the plugin from Noctalia settings and unlinks it from the local plugin directory. The repository checkout itself is kept in place.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well, no ./remove.sh needed

- `Settings.qml`: plugin settings UI
- `install.sh`: install and register the plugin
- `update.sh`: update from git and reinstall
- `remove.sh`: unregister and unlink the plugin
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These ./*.sh files don't exist

NToggle {
Layout.fillWidth: true
label: pluginApi?.tr("settings.show-bar") ?? "Show value in bar"
description: pluginApi?.tr("settings.show-bar-desc") ?? "Display the current value next to the calculator icon"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As before the translation feedbacks aren't needed

spacing: Style.marginS

NLabel {
label: (pluginApi?.tr("settings.precision") ?? "Decimal precision") + ": " + root.valuePrecision
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use concatenation when it comes to translations. Use translation interpolation instead. For example:

pluginApi?.tr("key", { "foo": "bar" })

Layout.fillWidth: true
label: pluginApi?.tr("settings.about") ?? "About"
description: (pluginApi?.tr("settings.developed-by") ?? "Developed by Pir0c0pter0")
+ "<br>v" + (pluginApi?.manifest?.version ?? "1.0.0")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well, no need for fallback and also use translation interpolation.

@pir0c0pter0
Copy link
Copy Markdown
Contributor Author

all done in commit 500bf36 — refactor: address PR review feedback for official merge

@spiros132
Copy link
Copy Markdown
Contributor

all done in commit 500bf36 — refactor: address PR review feedback for official merge

What do you mean by that? That particular commit hasn't been pushed to this PR

@pir0c0pter0
Copy link
Copy Markdown
Contributor Author

all the instructions are fixed in the last commit.

Copy link
Copy Markdown
Contributor

@spiros132 spiros132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more feedback about the PR :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need a .gitignore file for the settings.json. That is already taken care of by the root .gitignore

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not copy the AdvancedMath.js library. Instead reference and import it in the files that it's required in from the noctalia-shell. That way if any update happens on that file you get the update as well.

function _sanitizeCurrentInput() {
if (currentInput === "" || currentInput === "-") return "0";
if (currentInput.endsWith(".")) return currentInput + "0";
if (currentInput === "-0") return "-0";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment still persists. This if statement isn't exactly needed

result = left / right;
function _evaluateExpression(expressionStr) {
try {
var math = pluginApi ? pluginApi.loadHelper("AdvancedMath") : null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function does not exist in the pluginApi. Did you try out the plugin and looked that it worked?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I tested the plugin and it works correctly. pluginApi.loadHelper() is implemented in PluginService.qml (lines 1227-1234) — it loads helpers from the _shellHelpers map, which includes AdvancedMath among others. The function returns the helper object or null if not found, and the calculator handles both cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No pluginApi.loadHelper function exists. Please fact check the AI / LLM before commenting so confidently!

Here is the link to that specific line quoted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need a preview file for the plugin

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preview file has been included — preview.png is now in the plugin directory and visible in the PR description as well.

pir0c0pter0 and others added 2 commits March 23, 2026 17:29
- Remove local .gitignore (root repo handles settings.json)
- Remove local AdvancedMath.js copy (uses pluginApi.loadHelper)
- Remove unnecessary -0 guard in _sanitizeCurrentInput
- Update README with preview, i18n details, and accurate file list
@Ly-sec Ly-sec marked this pull request as draft March 28, 2026 14:46
Copy link
Copy Markdown
Contributor

@Cleboost Cleboost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small fixes for French accents in i18n ;)

"settings": {
"about": "A propos",
"show-bar": "Afficher la valeur dans la barre",
"show-bar-desc": "Affiche la valeur actuelle a cote de l'icone de la calculatrice",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"show-bar-desc": "Affiche la valeur actuelle a cote de l'icone de la calculatrice",
"show-bar-desc": "Affiche la valeur actuelle a cote de l’icône de la calculatrice",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

pir0c0pter0 and others added 6 commits March 30, 2026 16:51
Co-authored-by: Cleboost <clement.balarot@gmail.com>
Co-authored-by: Cleboost <clement.balarot@gmail.com>
Co-authored-by: Cleboost <clement.balarot@gmail.com>
Co-authored-by: Cleboost <clement.balarot@gmail.com>
Co-authored-by: Cleboost <clement.balarot@gmail.com>
Co-authored-by: Cleboost <clement.balarot@gmail.com>
Copy link
Copy Markdown
Contributor

@spiros132 spiros132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still doesn't exist anywhere in the noctalia-shell


function _evaluateExpression(expressionStr) {
try {
var math = pluginApi ? pluginApi.loadHelper("AdvancedMath") : null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still doesn't exist anywhere in the code base.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants