From be1ef05d07a47268b25495ea9da60f8d66895564 Mon Sep 17 00:00:00 2001 From: Nick <544436+Milchreis@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:07:42 +0200 Subject: [PATCH 1/6] adds simple-battery desklet --- simple-battery@suckatcoding.com/CHANGELOG.md | 2 + simple-battery@suckatcoding.com/README.md | 56 +++++++ .../files/desklet.js | 149 ++++++++++++++++++ .../files/icon.png | Bin 0 -> 4145 bytes .../simple-battery@suckatcoding.com.mo | Bin 0 -> 619 bytes .../files/metadata.json | 7 + .../files/po/de.po | 38 +++++ .../files/settings-schema.json | 16 ++ .../files/stylesheet.css | 82 ++++++++++ simple-battery@suckatcoding.com/info.json | 4 + .../screenshot.png | Bin 0 -> 52226 bytes 11 files changed, 354 insertions(+) create mode 100644 simple-battery@suckatcoding.com/CHANGELOG.md create mode 100644 simple-battery@suckatcoding.com/README.md create mode 100644 simple-battery@suckatcoding.com/files/desklet.js create mode 100644 simple-battery@suckatcoding.com/files/icon.png create mode 100644 simple-battery@suckatcoding.com/files/locale/de/LC_MESSAGES/simple-battery@suckatcoding.com.mo create mode 100644 simple-battery@suckatcoding.com/files/metadata.json create mode 100644 simple-battery@suckatcoding.com/files/po/de.po create mode 100644 simple-battery@suckatcoding.com/files/settings-schema.json create mode 100644 simple-battery@suckatcoding.com/files/stylesheet.css create mode 100644 simple-battery@suckatcoding.com/info.json create mode 100644 simple-battery@suckatcoding.com/screenshot.png diff --git a/simple-battery@suckatcoding.com/CHANGELOG.md b/simple-battery@suckatcoding.com/CHANGELOG.md new file mode 100644 index 000000000..085249e3c --- /dev/null +++ b/simple-battery@suckatcoding.com/CHANGELOG.md @@ -0,0 +1,2 @@ +# 1.0.0 +* Initial release \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/README.md b/simple-battery@suckatcoding.com/README.md new file mode 100644 index 000000000..6a5a79d50 --- /dev/null +++ b/simple-battery@suckatcoding.com/README.md @@ -0,0 +1,56 @@ +# Simple Battery Desklet for Cinnamon + +A minimalist, highly customizable battery desklet for the Cinnamon desktop environment. It provides essential power metrics at a glance without cluttering your workspace. + +![Screenshot placeholder](screenshot.png) + +*(Note: Upload a screenshot of your desklet to your repo and replace this link!)* + +## ✨ Features + +* **Minimalist Design:** A sleek horizontal progress bar and compact text. +* **Real-Time Status:** Shows the exact battery percentage and time remaining (or time until fully charged). +* **Session Tracking:** Calculates how much battery percentage you have consumed (or charged) since you turned on the PC. +* **System Uptime:** Displays how long your current session has been running. +* **Customizable Appearance:** Turn the semi-transparent background on/off and adjust the opacity directly via Cinnamon's desklet settings. +* **Multi-Language Support (i18n):** English and German are included by default. Easily expandable to other languages. + +## 📦 Installation + +### Manual Installation via Git +1. Open your terminal. +2. Clone this repository directly into your Cinnamon desklets folder: + ```bash + git clone [https://github.com/suckatcoding-com/simple-battery-desklet.git](https://github.com/suckatcoding-com/simple-battery-desklet.git) ~/.local/share/cinnamon/desklets/simple-battery@local + ``` +3. Restart Cinnamon so it detects the new desklet. Press Alt + F2, type r, and press Enter. +4. Right-click your desktop, select Add Desklets, go to the Manage tab, and add "Simple Battery" to your desktop. + +## ⚙️ Configuration + +You can easily configure the desklet to match your desktop theme: + +1. Right-click the desklet on your desktop. +2. Select Configure (the gear icon). +3. Toggle the background visibility or adjust the background opacity using the slider. Changes are applied instantly. + +## 🌍 Translations (i18n) + +This desklet supports Gettext for translations. The base language of the code is English. + +Want to add your language? + +1. Create a new .po file in the main directory (e.g., fr.po for French) and translate the msgid strings. +2. Create the locale folder for your language: + ```bash + mkdir -p locale/fr/LC_MESSAGES + ``` +3. Compile the .po file into a .mo file using msgfmt: + ```bash + msgfmt po/fr.po -o locale/fr/LC_MESSAGES/simple-battery@suckatcoding.com.mo + ``` +4. Restart Cinnamon. +5. Feel free to open a Pull Request to share your translation with everyone! + +## 📜 License +This project is licensed under the Apache 2.0 License - see the LICENSE file for details. \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/desklet.js b/simple-battery@suckatcoding.com/files/desklet.js new file mode 100644 index 000000000..e40ce71ec --- /dev/null +++ b/simple-battery@suckatcoding.com/files/desklet.js @@ -0,0 +1,149 @@ +const Desklet = imports.ui.desklet; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const GLib = imports.gi.GLib; +const Settings = imports.ui.settings; +const Gettext = imports.gettext; + +// Gettext für Übersetzungen einrichten +const UUID = "simple-battery@suckatcoding.com"; +const DESKLET_DIR = GLib.get_home_dir() + "/.local/share/cinnamon/desklets/" + UUID; +Gettext.bindtextdomain(UUID, DESKLET_DIR + "/locale"); + +function _(str) { + return Gettext.dgettext(UUID, str); +} + +function SimpleBatteryDesklet(metadata, desklet_id) { + this._init(metadata, desklet_id); +} + +SimpleBatteryDesklet.prototype = { + __proto__: Desklet.Desklet.prototype, + + _init: function(metadata, desklet_id) { + Desklet.Desklet.prototype._init.call(this, metadata, desklet_id); + + this.settings = new Settings.DeskletSettings(this, this.metadata["uuid"], desklet_id); + this.settings.bindProperty(Settings.BindingDirection.IN, "show-background", "show_background", this.on_setting_changed, null); + this.settings.bindProperty(Settings.BindingDirection.IN, "bg-opacity", "bg_opacity", this.on_setting_changed, null); + + this.setupUI(); + this.update(); + }, + + setupUI: function() { + this.container = new St.BoxLayout({vertical: true, style_class: "battery-desklet"}); + + this.barContainer = new St.BoxLayout({vertical: false}); + this.track = new St.BoxLayout({style_class: "battery-track"}); + this.fill = new St.BoxLayout({style_class: "battery-fill"}); + this.track.add_actor(this.fill); + this.pctLabel = new St.Label({style_class: "battery-pct-small"}); + this.barContainer.add_actor(this.track); + this.barContainer.add_actor(this.pctLabel); + + this.timeLabel = new St.Label({style_class: "battery-time"}); + + this.divider = new St.BoxLayout({style_class: "battery-divider"}); + this.uptimeLabel = new St.Label({style_class: "battery-stats"}); + this.usageLabel = new St.Label({style_class: "battery-stats"}); + + this.container.add_actor(this.barContainer); + this.container.add_actor(this.timeLabel); + this.container.add_actor(this.divider); + this.container.add_actor(this.uptimeLabel); + this.container.add_actor(this.usageLabel); + + this.setContent(this.container); + this.on_setting_changed(); + }, + + on_setting_changed: function() { + if (this.show_background) { + let alpha = this.bg_opacity / 100; + this.container.set_style("background-color: rgba(0, 0, 0, " + alpha + ");"); + } else { + this.container.set_style("background-color: transparent;"); + } + }, + + update: function() { + try { + let cmdBat = 'bash -c "upower -i $(upower -e | grep -i bat | head -n 1)"'; + let [resBat, outBat] = GLib.spawn_command_line_sync(cmdBat); + + if (resBat) { + let output = outBat.toString(); + let matchPct = output.match(/percentage:\s+(\d+)%/); + let matchEmpty = output.match(/time to empty:\s+(.*)/); + let matchFull = output.match(/time to full:\s+(.*)/); + let matchState = output.match(/state:\s+(.*)/); + + let pctNum = matchPct ? parseInt(matchPct[1]) : 0; + + this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); + let fillWidth = Math.round(150 * (pctNum / 100)); + this.fill.set_style("width: " + fillWidth + "px;"); + + let state = matchState ? matchState[1] : ""; + if (state === "discharging" && matchEmpty) { + this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); + } else if (state === "charging" && matchFull) { + this.timeLabel.set_text(matchFull[1] + " " + _("until full")); + } else if (state === "fully-charged") { + this.timeLabel.set_text(_("Fully charged")); + } else { + this.timeLabel.set_text(_("AC Power")); + } + + let cmdUsage = `bash -c "if [ ! -f /tmp/desklet_start_bat.txt ]; then echo ${pctNum} > /tmp/desklet_start_bat.txt; fi; cat /tmp/desklet_start_bat.txt"`; + let [resUsage, outUsage] = GLib.spawn_command_line_sync(cmdUsage); + + if (resUsage) { + let startPct = parseInt(outUsage.toString().trim()); + let diff = startPct - pctNum; + + if (diff > 0) { + this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); + } else if (diff < 0) { + this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); + } else { + this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); + } + } + } + + let [resUptime, outUptime] = GLib.spawn_command_line_sync("cat /proc/uptime"); + if (resUptime) { + let uptimeSeconds = parseFloat(outUptime.toString().split(" ")[0]); + let hours = Math.floor(uptimeSeconds / 3600); + let minutes = Math.floor((uptimeSeconds % 3600) / 60); + + if (hours > 0) { + this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); + } else { + this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); + } + } + + } catch (e) { + this.timeLabel.set_text(_("Error reading data")); + } + + this.timeout = Mainloop.timeout_add_seconds(60, () => { + this.update(); + return false; + }); + }, + + on_desklet_removed: function() { + if (this.timeout) { + Mainloop.source_remove(this.timeout); + } + } +}; + +function main(metadata, desklet_id) { + return new SimpleBatteryDesklet(metadata, desklet_id); +} \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/icon.png b/simple-battery@suckatcoding.com/files/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ed83e7f57ff8479236d6da6757dbceb932542d46 GIT binary patch literal 4145 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 literal 0 HcmV?d00001 diff --git a/simple-battery@suckatcoding.com/files/locale/de/LC_MESSAGES/simple-battery@suckatcoding.com.mo b/simple-battery@suckatcoding.com/files/locale/de/LC_MESSAGES/simple-battery@suckatcoding.com.mo new file mode 100644 index 0000000000000000000000000000000000000000..e510b0f3fcccdd050490543d845fa9ac0c6d1b0d GIT binary patch literal 619 zcmYk1u}UOC5Qgh?^}JJ&TSO2HIyullG1SR)&s8`TVbSBlo|)R2W_x?2r$=$)iwp$= zF)%Ul0WKFzeFnpe4txdwnq9I}%KZyb5Dg&iGo7{naB;h6S}3+ywG znO1*r((8HM4fRyJY<0>mqBiH2y^7iN)mBwnF4@sZVQm?n?p#B?25YY+y*y}3EBkF{d4lwH(wk(^NT}ma2RHq&`Hl;el4fF=b8-Ha0 literal 0 HcmV?d00001 diff --git a/simple-battery@suckatcoding.com/files/metadata.json b/simple-battery@suckatcoding.com/files/metadata.json new file mode 100644 index 000000000..1bd155e96 --- /dev/null +++ b/simple-battery@suckatcoding.com/files/metadata.json @@ -0,0 +1,7 @@ +{ + "uuid": "simple-battery@suckatcoding.com", + "name": "Simple Battery", + "description": "Displays battery status, uptime, and usage in a sleek, minimalist progress bar.", + "prevent-decorations": true, + "version": "1.0.0" +} \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/po/de.po b/simple-battery@suckatcoding.com/files/po/de.po new file mode 100644 index 000000000..59649bef8 --- /dev/null +++ b/simple-battery@suckatcoding.com/files/po/de.po @@ -0,0 +1,38 @@ +msgid "remaining" +msgstr "verbleibend" + +msgid "until full" +msgstr "bis voll" + +msgid "Fully charged" +msgstr "Vollständig geladen" + +msgid "AC Power" +msgstr "Netzbetrieb" + +msgid "Error reading data" +msgstr "Fehler beim Auslesen" + +msgid "Usage:" +msgstr "Verbrauch:" + +msgid "Charged:" +msgstr "Geladen:" + +msgid "since start" +msgstr "seit Start" + +msgid "Uptime:" +msgstr "Laufzeit:" + +msgid "h" +msgstr "Std" + +msgid "min" +msgstr "Min" + +msgid "Show background" +msgstr "Hintergrund anzeigen" + +msgid "Background opacity (%)" +msgstr "Hintergrund-Deckkraft (%)" \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/settings-schema.json b/simple-battery@suckatcoding.com/files/settings-schema.json new file mode 100644 index 000000000..1e99f4cd7 --- /dev/null +++ b/simple-battery@suckatcoding.com/files/settings-schema.json @@ -0,0 +1,16 @@ +{ + "show-background": { + "type": "checkbox", + "default": true, + "description": "Show background" + }, + "bg-opacity": { + "type": "scale", + "default": 40, + "min": 0, + "max": 100, + "step": 5, + "description": "Background opacity (%)", + "dependency": "show-background" + } +} \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/stylesheet.css b/simple-battery@suckatcoding.com/files/stylesheet.css new file mode 100644 index 000000000..5fd9d169b --- /dev/null +++ b/simple-battery@suckatcoding.com/files/stylesheet.css @@ -0,0 +1,82 @@ +.battery-desklet { + /* background-color wurde hier entfernt! */ + border-radius: 10px; + padding: 15px 20px; + color: #ffffff; + font-family: sans-serif; +} + +.battery-track { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 5px; + height: 12px; + width: 150px; +} + +.battery-fill { + background-color: #eeeeee; + border-radius: 5px; + height: 12px; +} + +.battery-pct-small { + font-size: 14px; + font-weight: bold; + margin-left: 12px; + text-shadow: 1px 1px 2px rgba(0,0,0,0.8); +} + +.battery-time { + font-size: 13px; + margin-top: 10px; + color: #dddddd; + text-shadow: 1px 1px 2px rgba(0,0,0,0.8); +} + +.battery-desklet { + border-radius: 10px; + padding: 15px 20px; + color: #ffffff; + font-family: sans-serif; +} + +.battery-track { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 5px; + height: 12px; + width: 150px; +} + +.battery-fill { + background-color: #eeeeee; + border-radius: 5px; + height: 12px; +} + +.battery-pct-small { + font-size: 14px; + font-weight: bold; + margin-left: 12px; + text-shadow: 1px 1px 2px rgba(0,0,0,0.8); +} + +.battery-time { + font-size: 13px; + margin-top: 10px; + color: #dddddd; + text-shadow: 1px 1px 2px rgba(0,0,0,0.8); +} + +.battery-divider { + height: 1px; + background-color: rgba(255, 255, 255, 0.2); + margin-top: 8px; + margin-bottom: 8px; +} + +/* NEU: Schriftart für Systemzeit und Verbrauch */ +.battery-stats { + font-size: 11px; + color: #bbbbbb; + text-shadow: 1px 1px 2px rgba(0,0,0,0.8); +} \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/info.json b/simple-battery@suckatcoding.com/info.json new file mode 100644 index 000000000..166863c96 --- /dev/null +++ b/simple-battery@suckatcoding.com/info.json @@ -0,0 +1,4 @@ +{ + "author": "Nick 'Milchreis' Müller", + "license": "Apache 2.0" +} diff --git a/simple-battery@suckatcoding.com/screenshot.png b/simple-battery@suckatcoding.com/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..9ff1de69fefd0cde1cc47e1d3dc037bd1ae36de8 GIT binary patch literal 52226 zcmV)QK(xP!P)`uARa<85;C9$2}#Hj*a$59L&Ey8Y=77ha`?yL za9ECTg#F_WM>y;sN7!N6A;Pl4A)8PmBtQrnH6R42dDB4C^rNb)vhsb;-fPa`kGb}_ z=Vn&78cX0G?Z~>7_vAVI?7h~SuQA44oA3Io|AmY(;_R$PiXaFY#}-R(k}}nrgBY2T z%t#u%zw!Tk|KZm^Dq2dY!`uM6

fWm69SsNJgWPB*2V8QW8?2AmPkzedl-F`21J2 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 literal 0 HcmV?d00001 From c97e5946e7be465ce546ab9cca37a3b85d883064 Mon Sep 17 00:00:00 2001 From: Nick <544436+Milchreis@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:16:58 +0200 Subject: [PATCH 2/6] fixing warnings --- .../files/desklet.js | 133 ++++++++++-------- 1 file changed, 78 insertions(+), 55 deletions(-) diff --git a/simple-battery@suckatcoding.com/files/desklet.js b/simple-battery@suckatcoding.com/files/desklet.js index e40ce71ec..eba481267 100644 --- a/simple-battery@suckatcoding.com/files/desklet.js +++ b/simple-battery@suckatcoding.com/files/desklet.js @@ -2,12 +2,13 @@ const Desklet = imports.ui.desklet; const St = imports.gi.St; const Mainloop = imports.mainloop; const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const ByteArray = imports.byteArray; const Settings = imports.ui.settings; const Gettext = imports.gettext; -// Gettext für Übersetzungen einrichten const UUID = "simple-battery@suckatcoding.com"; -const DESKLET_DIR = GLib.get_home_dir() + "/.local/share/cinnamon/desklets/" + UUID; +const DESKLET_DIR = GLib.get_user_data_dir() + "/cinnamon/desklets/" + UUID; Gettext.bindtextdomain(UUID, DESKLET_DIR + "/locale"); function _(str) { @@ -70,73 +71,95 @@ SimpleBatteryDesklet.prototype = { update: function() { try { - let cmdBat = 'bash -c "upower -i $(upower -e | grep -i bat | head -n 1)"'; - let [resBat, outBat] = GLib.spawn_command_line_sync(cmdBat); + let procBat = Gio.Subprocess.new( + ['bash', '-c', 'upower -i $(upower -e | grep -i bat | head -n 1)'], + Gio.SubprocessFlags.STDOUT_PIPE + ); - if (resBat) { - let output = outBat.toString(); - let matchPct = output.match(/percentage:\s+(\d+)%/); - let matchEmpty = output.match(/time to empty:\s+(.*)/); - let matchFull = output.match(/time to full:\s+(.*)/); - let matchState = output.match(/state:\s+(.*)/); - - let pctNum = matchPct ? parseInt(matchPct[1]) : 0; - - this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); - let fillWidth = Math.round(150 * (pctNum / 100)); - this.fill.set_style("width: " + fillWidth + "px;"); - - let state = matchState ? matchState[1] : ""; - if (state === "discharging" && matchEmpty) { - this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); - } else if (state === "charging" && matchFull) { - this.timeLabel.set_text(matchFull[1] + " " + _("until full")); - } else if (state === "fully-charged") { - this.timeLabel.set_text(_("Fully charged")); - } else { - this.timeLabel.set_text(_("AC Power")); - } - - let cmdUsage = `bash -c "if [ ! -f /tmp/desklet_start_bat.txt ]; then echo ${pctNum} > /tmp/desklet_start_bat.txt; fi; cat /tmp/desklet_start_bat.txt"`; - let [resUsage, outUsage] = GLib.spawn_command_line_sync(cmdUsage); - - if (resUsage) { - let startPct = parseInt(outUsage.toString().trim()); - let diff = startPct - pctNum; - - if (diff > 0) { - this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); - } else if (diff < 0) { - this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); - } else { - this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); + procBat.communicate_utf8_async(null, null, (proc, res) => { + try { + let [ok, outBat, stderr] = proc.communicate_utf8_finish(res); + if (ok && outBat) { + this.parseAndUpdate(outBat); } + } catch (e) { + this.timeLabel.set_text(_("Error reading data")); } - } - - let [resUptime, outUptime] = GLib.spawn_command_line_sync("cat /proc/uptime"); - if (resUptime) { - let uptimeSeconds = parseFloat(outUptime.toString().split(" ")[0]); - let hours = Math.floor(uptimeSeconds / 3600); - let minutes = Math.floor((uptimeSeconds % 3600) / 60); - - if (hours > 0) { - this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); - } else { - this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); - } - } + }); } catch (e) { this.timeLabel.set_text(_("Error reading data")); } + if (this.timeout) Mainloop.source_remove(this.timeout); this.timeout = Mainloop.timeout_add_seconds(60, () => { this.update(); return false; }); }, + parseAndUpdate: function(output) { + let matchPct = output.match(/percentage:\s+(\d+)%/); + let matchEmpty = output.match(/time to empty:\s+(.*)/); + let matchFull = output.match(/time to full:\s+(.*)/); + let matchState = output.match(/state:\s+(.*)/); + + let pctNum = matchPct ? parseInt(matchPct[1]) : 0; + + this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); + let fillWidth = Math.round(150 * (pctNum / 100)); + this.fill.set_style("width: " + fillWidth + "px;"); + + let state = matchState ? matchState[1] : ""; + if (state === "discharging" && matchEmpty) { + this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); + } else if (state === "charging" && matchFull) { + this.timeLabel.set_text(matchFull[1] + " " + _("until full")); + } else if (state === "fully-charged") { + this.timeLabel.set_text(_("Fully charged")); + } else { + this.timeLabel.set_text(_("AC Power")); + } + + let tmpPath = "/tmp/desklet_start_bat_" + UUID + ".txt"; + let startPct = pctNum; + + if (GLib.file_test(tmpPath, GLib.FileTest.EXISTS)) { + let [res, contents] = GLib.file_get_contents(tmpPath); + if (res) { + let contentStr = ByteArray.toString(contents).trim(); + if (contentStr !== "") { + startPct = parseInt(contentStr); + } + } + } else { + GLib.file_set_contents(tmpPath, pctNum.toString()); + } + + let diff = startPct - pctNum; + if (diff > 0) { + this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); + } else if (diff < 0) { + this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); + } else { + this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); + } + + let [resUptime, contentsUptime] = GLib.file_get_contents("/proc/uptime"); + if (resUptime) { + let outUptime = ByteArray.toString(contentsUptime); + let uptimeSeconds = parseFloat(outUptime.split(" ")[0]); + let hours = Math.floor(uptimeSeconds / 3600); + let minutes = Math.floor((uptimeSeconds % 3600) / 60); + + if (hours > 0) { + this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); + } else { + this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); + } + } + }, + on_desklet_removed: function() { if (this.timeout) { Mainloop.source_remove(this.timeout); From a80d5244a9c540c164aa94d2bf68b1ac3a7a833f Mon Sep 17 00:00:00 2001 From: Nick <544436+Milchreis@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:20:10 +0200 Subject: [PATCH 3/6] fixing sync warnings --- .../files/desklet.js | 71 ++++++++++++------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/simple-battery@suckatcoding.com/files/desklet.js b/simple-battery@suckatcoding.com/files/desklet.js index eba481267..f6e890d60 100644 --- a/simple-battery@suckatcoding.com/files/desklet.js +++ b/simple-battery@suckatcoding.com/files/desklet.js @@ -122,21 +122,54 @@ SimpleBatteryDesklet.prototype = { } let tmpPath = "/tmp/desklet_start_bat_" + UUID + ".txt"; - let startPct = pctNum; - - if (GLib.file_test(tmpPath, GLib.FileTest.EXISTS)) { - let [res, contents] = GLib.file_get_contents(tmpPath); - if (res) { - let contentStr = ByteArray.toString(contents).trim(); - if (contentStr !== "") { - startPct = parseInt(contentStr); + let tmpFile = Gio.File.new_for_path(tmpPath); + + tmpFile.load_contents_async(null, (file, res) => { + try { + let [success, contents] = file.load_contents_finish(res); + if (success) { + let contentStr = ByteArray.toString(contents).trim(); + let startPct = contentStr !== "" ? parseInt(contentStr) : pctNum; + this.updateUsageUI(startPct, pctNum); } + } catch (e) { + file.replace_contents_async( + pctNum.toString(), + null, + false, + Gio.FileCreateFlags.NONE, + null, + (f, r) => { + try { f.replace_contents_finish(r); } catch (err) {} + } + ); + this.updateUsageUI(pctNum, pctNum); } - } else { - GLib.file_set_contents(tmpPath, pctNum.toString()); - } + }); - let diff = startPct - pctNum; + let uptimeFile = Gio.File.new_for_path("/proc/uptime"); + uptimeFile.load_contents_async(null, (file, res) => { + try { + let [success, contents] = file.load_contents_finish(res); + if (success) { + let outUptime = ByteArray.toString(contents); + let uptimeSeconds = parseFloat(outUptime.split(" ")[0]); + let hours = Math.floor(uptimeSeconds / 3600); + let minutes = Math.floor((uptimeSeconds % 3600) / 60); + + if (hours > 0) { + this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); + } else { + this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); + } + } + } catch (e) { + } + }); + }, + + updateUsageUI: function(startPct, currentPct) { + let diff = startPct - currentPct; if (diff > 0) { this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); } else if (diff < 0) { @@ -144,20 +177,6 @@ SimpleBatteryDesklet.prototype = { } else { this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); } - - let [resUptime, contentsUptime] = GLib.file_get_contents("/proc/uptime"); - if (resUptime) { - let outUptime = ByteArray.toString(contentsUptime); - let uptimeSeconds = parseFloat(outUptime.split(" ")[0]); - let hours = Math.floor(uptimeSeconds / 3600); - let minutes = Math.floor((uptimeSeconds % 3600) / 60); - - if (hours > 0) { - this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); - } else { - this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); - } - } }, on_desklet_removed: function() { From 0f9dc2f8a2fcaf1b62610ba8afafa1ab834054a6 Mon Sep 17 00:00:00 2001 From: Milchreis Date: Sun, 14 Jun 2026 11:03:41 +0200 Subject: [PATCH 4/6] fixed: moved files after validation --- .../files/desklet.js | 191 ------------------ .../simple-battery@suckatcoding.com.mo | Bin 619 -> 0 bytes .../files/po/de.po | 38 ---- .../desklet.js | 148 ++++++++++++++ .../icon.png | Bin .../metadata.json | 0 .../simple-battery@suckatcoding.com/po/de.po | 81 ++++++++ .../po/simple-battery@suckatcoding.com.pot | 80 ++++++++ .../settings-schema.json | 0 .../stylesheet.css | 0 10 files changed, 309 insertions(+), 229 deletions(-) delete mode 100644 simple-battery@suckatcoding.com/files/desklet.js delete mode 100644 simple-battery@suckatcoding.com/files/locale/de/LC_MESSAGES/simple-battery@suckatcoding.com.mo delete mode 100644 simple-battery@suckatcoding.com/files/po/de.po create mode 100644 simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js rename simple-battery@suckatcoding.com/files/{ => simple-battery@suckatcoding.com}/icon.png (100%) rename simple-battery@suckatcoding.com/files/{ => simple-battery@suckatcoding.com}/metadata.json (100%) create mode 100644 simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/de.po create mode 100644 simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/simple-battery@suckatcoding.com.pot rename simple-battery@suckatcoding.com/files/{ => simple-battery@suckatcoding.com}/settings-schema.json (100%) rename simple-battery@suckatcoding.com/files/{ => simple-battery@suckatcoding.com}/stylesheet.css (100%) diff --git a/simple-battery@suckatcoding.com/files/desklet.js b/simple-battery@suckatcoding.com/files/desklet.js deleted file mode 100644 index f6e890d60..000000000 --- a/simple-battery@suckatcoding.com/files/desklet.js +++ /dev/null @@ -1,191 +0,0 @@ -const Desklet = imports.ui.desklet; -const St = imports.gi.St; -const Mainloop = imports.mainloop; -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const ByteArray = imports.byteArray; -const Settings = imports.ui.settings; -const Gettext = imports.gettext; - -const UUID = "simple-battery@suckatcoding.com"; -const DESKLET_DIR = GLib.get_user_data_dir() + "/cinnamon/desklets/" + UUID; -Gettext.bindtextdomain(UUID, DESKLET_DIR + "/locale"); - -function _(str) { - return Gettext.dgettext(UUID, str); -} - -function SimpleBatteryDesklet(metadata, desklet_id) { - this._init(metadata, desklet_id); -} - -SimpleBatteryDesklet.prototype = { - __proto__: Desklet.Desklet.prototype, - - _init: function(metadata, desklet_id) { - Desklet.Desklet.prototype._init.call(this, metadata, desklet_id); - - this.settings = new Settings.DeskletSettings(this, this.metadata["uuid"], desklet_id); - this.settings.bindProperty(Settings.BindingDirection.IN, "show-background", "show_background", this.on_setting_changed, null); - this.settings.bindProperty(Settings.BindingDirection.IN, "bg-opacity", "bg_opacity", this.on_setting_changed, null); - - this.setupUI(); - this.update(); - }, - - setupUI: function() { - this.container = new St.BoxLayout({vertical: true, style_class: "battery-desklet"}); - - this.barContainer = new St.BoxLayout({vertical: false}); - this.track = new St.BoxLayout({style_class: "battery-track"}); - this.fill = new St.BoxLayout({style_class: "battery-fill"}); - this.track.add_actor(this.fill); - this.pctLabel = new St.Label({style_class: "battery-pct-small"}); - this.barContainer.add_actor(this.track); - this.barContainer.add_actor(this.pctLabel); - - this.timeLabel = new St.Label({style_class: "battery-time"}); - - this.divider = new St.BoxLayout({style_class: "battery-divider"}); - this.uptimeLabel = new St.Label({style_class: "battery-stats"}); - this.usageLabel = new St.Label({style_class: "battery-stats"}); - - this.container.add_actor(this.barContainer); - this.container.add_actor(this.timeLabel); - this.container.add_actor(this.divider); - this.container.add_actor(this.uptimeLabel); - this.container.add_actor(this.usageLabel); - - this.setContent(this.container); - this.on_setting_changed(); - }, - - on_setting_changed: function() { - if (this.show_background) { - let alpha = this.bg_opacity / 100; - this.container.set_style("background-color: rgba(0, 0, 0, " + alpha + ");"); - } else { - this.container.set_style("background-color: transparent;"); - } - }, - - update: function() { - try { - let procBat = Gio.Subprocess.new( - ['bash', '-c', 'upower -i $(upower -e | grep -i bat | head -n 1)'], - Gio.SubprocessFlags.STDOUT_PIPE - ); - - procBat.communicate_utf8_async(null, null, (proc, res) => { - try { - let [ok, outBat, stderr] = proc.communicate_utf8_finish(res); - if (ok && outBat) { - this.parseAndUpdate(outBat); - } - } catch (e) { - this.timeLabel.set_text(_("Error reading data")); - } - }); - - } catch (e) { - this.timeLabel.set_text(_("Error reading data")); - } - - if (this.timeout) Mainloop.source_remove(this.timeout); - this.timeout = Mainloop.timeout_add_seconds(60, () => { - this.update(); - return false; - }); - }, - - parseAndUpdate: function(output) { - let matchPct = output.match(/percentage:\s+(\d+)%/); - let matchEmpty = output.match(/time to empty:\s+(.*)/); - let matchFull = output.match(/time to full:\s+(.*)/); - let matchState = output.match(/state:\s+(.*)/); - - let pctNum = matchPct ? parseInt(matchPct[1]) : 0; - - this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); - let fillWidth = Math.round(150 * (pctNum / 100)); - this.fill.set_style("width: " + fillWidth + "px;"); - - let state = matchState ? matchState[1] : ""; - if (state === "discharging" && matchEmpty) { - this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); - } else if (state === "charging" && matchFull) { - this.timeLabel.set_text(matchFull[1] + " " + _("until full")); - } else if (state === "fully-charged") { - this.timeLabel.set_text(_("Fully charged")); - } else { - this.timeLabel.set_text(_("AC Power")); - } - - let tmpPath = "/tmp/desklet_start_bat_" + UUID + ".txt"; - let tmpFile = Gio.File.new_for_path(tmpPath); - - tmpFile.load_contents_async(null, (file, res) => { - try { - let [success, contents] = file.load_contents_finish(res); - if (success) { - let contentStr = ByteArray.toString(contents).trim(); - let startPct = contentStr !== "" ? parseInt(contentStr) : pctNum; - this.updateUsageUI(startPct, pctNum); - } - } catch (e) { - file.replace_contents_async( - pctNum.toString(), - null, - false, - Gio.FileCreateFlags.NONE, - null, - (f, r) => { - try { f.replace_contents_finish(r); } catch (err) {} - } - ); - this.updateUsageUI(pctNum, pctNum); - } - }); - - let uptimeFile = Gio.File.new_for_path("/proc/uptime"); - uptimeFile.load_contents_async(null, (file, res) => { - try { - let [success, contents] = file.load_contents_finish(res); - if (success) { - let outUptime = ByteArray.toString(contents); - let uptimeSeconds = parseFloat(outUptime.split(" ")[0]); - let hours = Math.floor(uptimeSeconds / 3600); - let minutes = Math.floor((uptimeSeconds % 3600) / 60); - - if (hours > 0) { - this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); - } else { - this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); - } - } - } catch (e) { - } - }); - }, - - updateUsageUI: function(startPct, currentPct) { - let diff = startPct - currentPct; - if (diff > 0) { - this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); - } else if (diff < 0) { - this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); - } else { - this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); - } - }, - - on_desklet_removed: function() { - if (this.timeout) { - Mainloop.source_remove(this.timeout); - } - } -}; - -function main(metadata, desklet_id) { - return new SimpleBatteryDesklet(metadata, desklet_id); -} \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/locale/de/LC_MESSAGES/simple-battery@suckatcoding.com.mo b/simple-battery@suckatcoding.com/files/locale/de/LC_MESSAGES/simple-battery@suckatcoding.com.mo deleted file mode 100644 index e510b0f3fcccdd050490543d845fa9ac0c6d1b0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 619 zcmYk1u}UOC5Qgh?^}JJ&TSO2HIyullG1SR)&s8`TVbSBlo|)R2W_x?2r$=$)iwp$= zF)%Ul0WKFzeFnpe4txdwnq9I}%KZyb5Dg&iGo7{naB;h6S}3+ywG znO1*r((8HM4fRyJY<0>mqBiH2y^7iN)mBwnF4@sZVQm?n?p#B?25YY+y*y}3EBkF{d4lwH(wk(^NT}ma2RHq&`Hl;el4fF=b8-Ha0 diff --git a/simple-battery@suckatcoding.com/files/po/de.po b/simple-battery@suckatcoding.com/files/po/de.po deleted file mode 100644 index 59649bef8..000000000 --- a/simple-battery@suckatcoding.com/files/po/de.po +++ /dev/null @@ -1,38 +0,0 @@ -msgid "remaining" -msgstr "verbleibend" - -msgid "until full" -msgstr "bis voll" - -msgid "Fully charged" -msgstr "Vollständig geladen" - -msgid "AC Power" -msgstr "Netzbetrieb" - -msgid "Error reading data" -msgstr "Fehler beim Auslesen" - -msgid "Usage:" -msgstr "Verbrauch:" - -msgid "Charged:" -msgstr "Geladen:" - -msgid "since start" -msgstr "seit Start" - -msgid "Uptime:" -msgstr "Laufzeit:" - -msgid "h" -msgstr "Std" - -msgid "min" -msgstr "Min" - -msgid "Show background" -msgstr "Hintergrund anzeigen" - -msgid "Background opacity (%)" -msgstr "Hintergrund-Deckkraft (%)" \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js new file mode 100644 index 000000000..be40801de --- /dev/null +++ b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js @@ -0,0 +1,148 @@ +const Desklet = imports.ui.desklet; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const GLib = imports.gi.GLib; +const Settings = imports.ui.settings; +const Gettext = imports.gettext; + +const UUID = "simple-battery@suckatcoding.com"; +const DESKLET_DIR = GLib.get_home_dir() + "/.local/share/cinnamon/desklets/" + UUID; +Gettext.bindtextdomain(UUID, DESKLET_DIR + "/locale"); + +function _(str) { + return Gettext.dgettext(UUID, str); +} + +function SimpleBatteryDesklet(metadata, desklet_id) { + this._init(metadata, desklet_id); +} + +SimpleBatteryDesklet.prototype = { + __proto__: Desklet.Desklet.prototype, + + _init: function(metadata, desklet_id) { + Desklet.Desklet.prototype._init.call(this, metadata, desklet_id); + + this.settings = new Settings.DeskletSettings(this, this.metadata["uuid"], desklet_id); + this.settings.bindProperty(Settings.BindingDirection.IN, "show-background", "show_background", this.on_setting_changed, null); + this.settings.bindProperty(Settings.BindingDirection.IN, "bg-opacity", "bg_opacity", this.on_setting_changed, null); + + this.setupUI(); + this.update(); + }, + + setupUI: function() { + this.container = new St.BoxLayout({vertical: true, style_class: "battery-desklet"}); + + this.barContainer = new St.BoxLayout({vertical: false}); + this.track = new St.BoxLayout({style_class: "battery-track"}); + this.fill = new St.BoxLayout({style_class: "battery-fill"}); + this.track.add_actor(this.fill); + this.pctLabel = new St.Label({style_class: "battery-pct-small"}); + this.barContainer.add_actor(this.track); + this.barContainer.add_actor(this.pctLabel); + + this.timeLabel = new St.Label({style_class: "battery-time"}); + + this.divider = new St.BoxLayout({style_class: "battery-divider"}); + this.uptimeLabel = new St.Label({style_class: "battery-stats"}); + this.usageLabel = new St.Label({style_class: "battery-stats"}); + + this.container.add_actor(this.barContainer); + this.container.add_actor(this.timeLabel); + this.container.add_actor(this.divider); + this.container.add_actor(this.uptimeLabel); + this.container.add_actor(this.usageLabel); + + this.setContent(this.container); + this.on_setting_changed(); + }, + + on_setting_changed: function() { + if (this.show_background) { + let alpha = this.bg_opacity / 100; + this.container.set_style("background-color: rgba(0, 0, 0, " + alpha + ");"); + } else { + this.container.set_style("background-color: transparent;"); + } + }, + + update: function() { + try { + let cmdBat = 'bash -c "upower -i $(upower -e | grep -i bat | head -n 1)"'; + let [resBat, outBat] = GLib.spawn_command_line_sync(cmdBat); + + if (resBat) { + let output = outBat.toString(); + let matchPct = output.match(/percentage:\s+(\d+)%/); + let matchEmpty = output.match(/time to empty:\s+(.*)/); + let matchFull = output.match(/time to full:\s+(.*)/); + let matchState = output.match(/state:\s+(.*)/); + + let pctNum = matchPct ? parseInt(matchPct[1]) : 0; + + this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); + let fillWidth = Math.round(150 * (pctNum / 100)); + this.fill.set_style("width: " + fillWidth + "px;"); + + let state = matchState ? matchState[1] : ""; + if (state === "discharging" && matchEmpty) { + this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); + } else if (state === "charging" && matchFull) { + this.timeLabel.set_text(matchFull[1] + " " + _("until full")); + } else if (state === "fully-charged") { + this.timeLabel.set_text(_("Fully charged")); + } else { + this.timeLabel.set_text(_("AC Power")); + } + + let cmdUsage = `bash -c "if [ ! -f /tmp/desklet_start_bat.txt ]; then echo ${pctNum} > /tmp/desklet_start_bat.txt; fi; cat /tmp/desklet_start_bat.txt"`; + let [resUsage, outUsage] = GLib.spawn_command_line_sync(cmdUsage); + + if (resUsage) { + let startPct = parseInt(outUsage.toString().trim()); + let diff = startPct - pctNum; + + if (diff > 0) { + this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); + } else if (diff < 0) { + this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); + } else { + this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); + } + } + } + + let [resUptime, outUptime] = GLib.spawn_command_line_sync("cat /proc/uptime"); + if (resUptime) { + let uptimeSeconds = parseFloat(outUptime.toString().split(" ")[0]); + let hours = Math.floor(uptimeSeconds / 3600); + let minutes = Math.floor((uptimeSeconds % 3600) / 60); + + if (hours > 0) { + this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); + } else { + this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); + } + } + + } catch (e) { + this.timeLabel.set_text(_("Error reading data")); + } + + this.timeout = Mainloop.timeout_add_seconds(60, () => { + this.update(); + return false; + }); + }, + + on_desklet_removed: function() { + if (this.timeout) { + Mainloop.source_remove(this.timeout); + } + } +}; + +function main(metadata, desklet_id) { + return new SimpleBatteryDesklet(metadata, desklet_id); +} \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/icon.png b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/icon.png similarity index 100% rename from simple-battery@suckatcoding.com/files/icon.png rename to simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/icon.png diff --git a/simple-battery@suckatcoding.com/files/metadata.json b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/metadata.json similarity index 100% rename from simple-battery@suckatcoding.com/files/metadata.json rename to simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/metadata.json diff --git a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/de.po b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/de.po new file mode 100644 index 000000000..6dcd06685 --- /dev/null +++ b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/de.po @@ -0,0 +1,81 @@ +# SIMPLE BATTERY +# This file is put in the public domain. +# Nick 'Milchreis' Müller, 2026 +# +msgid "" +msgstr "" +"Project-Id-Version: simple-battery@suckatcoding.com 1.0.0\n" +"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-desklets/" +"issues\n" +"POT-Creation-Date: 2026-06-14 10:54+0200\n" +"PO-Revision-Date: 2026-06-14 11:00+0200\n" +"Last-Translator: Nick 'Milchreis' Müller\n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. desklet.js:86 desklet.js:91 +msgid "Error reading data" +msgstr "Fehler beim Auslesen" + +#. desklet.js:115 +msgid "remaining" +msgstr "verbleibend" + +#. desklet.js:117 +msgid "until full" +msgstr "bis voll" + +#. desklet.js:119 +msgid "Fully charged" +msgstr "Vollständig geladen" + +#. desklet.js:121 +msgid "AC Power" +msgstr "Netzbetrieb" + +#. desklet.js:161 desklet.js:163 +msgid "Uptime:" +msgstr "Laufzeit:" + +#. desklet.js:161 +msgid "h" +msgstr "Std" + +#. desklet.js:161 desklet.js:163 +msgid "min" +msgstr "Min" + +#. desklet.js:174 desklet.js:178 +msgid "Usage:" +msgstr "Verbrauch:" + +#. desklet.js:174 desklet.js:176 desklet.js:178 +msgid "since start" +msgstr "seit Start" + +#. desklet.js:176 +msgid "Charged:" +msgstr "Geladen:" + +#. metadata.json->name +msgid "Simple Battery" +msgstr "Schlichter Akku" + +#. metadata.json->description +msgid "" +"Displays battery status, uptime, and usage in a sleek, minimalist progress " +"bar." +msgstr "" +"Zeigt den Akkustand, die Laufzeit und den Verbrauch in einem schlichten, " +"minimalistischen Fortschrittsbalken an." + +#. settings-schema.json->show-background->description +msgid "Show background" +msgstr "Hintergrund anzeigen" + +#. settings-schema.json->bg-opacity->description +msgid "Background opacity (%)" +msgstr "Hintergrund-Deckkraft (%)" \ No newline at end of file diff --git a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/simple-battery@suckatcoding.com.pot b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/simple-battery@suckatcoding.com.pot new file mode 100644 index 000000000..e080810d7 --- /dev/null +++ b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/po/simple-battery@suckatcoding.com.pot @@ -0,0 +1,80 @@ +# SIMPLE BATTERY +# This file is put in the public domain. +# Nick 'Milchreis' Müller, 2026 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: simple-battery@suckatcoding.com 1.0.0\n" +"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-desklets/" +"issues\n" +"POT-Creation-Date: 2026-06-14 10:54+0200\n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. desklet.js:86 desklet.js:91 +msgid "Error reading data" +msgstr "" + +#. desklet.js:115 +msgid "remaining" +msgstr "" + +#. desklet.js:117 +msgid "until full" +msgstr "" + +#. desklet.js:119 +msgid "Fully charged" +msgstr "" + +#. desklet.js:121 +msgid "AC Power" +msgstr "" + +#. desklet.js:161 desklet.js:163 +msgid "Uptime:" +msgstr "" + +#. desklet.js:161 +msgid "h" +msgstr "" + +#. desklet.js:161 desklet.js:163 +msgid "min" +msgstr "" + +#. desklet.js:174 desklet.js:178 +msgid "Usage:" +msgstr "" + +#. desklet.js:174 desklet.js:176 desklet.js:178 +msgid "since start" +msgstr "" + +#. desklet.js:176 +msgid "Charged:" +msgstr "" + +#. metadata.json->name +msgid "Simple Battery" +msgstr "" + +#. metadata.json->description +msgid "" +"Displays battery status, uptime, and usage in a sleek, minimalist progress " +"bar." +msgstr "" + +#. settings-schema.json->show-background->description +msgid "Show background" +msgstr "" + +#. settings-schema.json->bg-opacity->description +msgid "Background opacity (%)" +msgstr "" diff --git a/simple-battery@suckatcoding.com/files/settings-schema.json b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/settings-schema.json similarity index 100% rename from simple-battery@suckatcoding.com/files/settings-schema.json rename to simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/settings-schema.json diff --git a/simple-battery@suckatcoding.com/files/stylesheet.css b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/stylesheet.css similarity index 100% rename from simple-battery@suckatcoding.com/files/stylesheet.css rename to simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/stylesheet.css From a8b475d33e5c1e1d2373f3cd6578337a288db688 Mon Sep 17 00:00:00 2001 From: Milchreis Date: Sun, 14 Jun 2026 11:10:24 +0200 Subject: [PATCH 5/6] fixes for the warnings --- .../desklet.js | 150 +++++++++++------- 1 file changed, 96 insertions(+), 54 deletions(-) diff --git a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js index be40801de..7da84b99c 100644 --- a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js +++ b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js @@ -2,11 +2,13 @@ const Desklet = imports.ui.desklet; const St = imports.gi.St; const Mainloop = imports.mainloop; const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const ByteArray = imports.byteArray; const Settings = imports.ui.settings; const Gettext = imports.gettext; const UUID = "simple-battery@suckatcoding.com"; -const DESKLET_DIR = GLib.get_home_dir() + "/.local/share/cinnamon/desklets/" + UUID; +const DESKLET_DIR = GLib.get_user_data_dir() + "/cinnamon/desklets/" + UUID; Gettext.bindtextdomain(UUID, DESKLET_DIR + "/locale"); function _(str) { @@ -69,73 +71,113 @@ SimpleBatteryDesklet.prototype = { update: function() { try { - let cmdBat = 'bash -c "upower -i $(upower -e | grep -i bat | head -n 1)"'; - let [resBat, outBat] = GLib.spawn_command_line_sync(cmdBat); + let procBat = Gio.Subprocess.new( + ['bash', '-c', 'upower -i $(upower -e | grep -i bat | head -n 1)'], + Gio.SubprocessFlags.STDOUT_PIPE + ); - if (resBat) { - let output = outBat.toString(); - let matchPct = output.match(/percentage:\s+(\d+)%/); - let matchEmpty = output.match(/time to empty:\s+(.*)/); - let matchFull = output.match(/time to full:\s+(.*)/); - let matchState = output.match(/state:\s+(.*)/); - - let pctNum = matchPct ? parseInt(matchPct[1]) : 0; - - this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); - let fillWidth = Math.round(150 * (pctNum / 100)); - this.fill.set_style("width: " + fillWidth + "px;"); - - let state = matchState ? matchState[1] : ""; - if (state === "discharging" && matchEmpty) { - this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); - } else if (state === "charging" && matchFull) { - this.timeLabel.set_text(matchFull[1] + " " + _("until full")); - } else if (state === "fully-charged") { - this.timeLabel.set_text(_("Fully charged")); - } else { - this.timeLabel.set_text(_("AC Power")); - } - - let cmdUsage = `bash -c "if [ ! -f /tmp/desklet_start_bat.txt ]; then echo ${pctNum} > /tmp/desklet_start_bat.txt; fi; cat /tmp/desklet_start_bat.txt"`; - let [resUsage, outUsage] = GLib.spawn_command_line_sync(cmdUsage); - - if (resUsage) { - let startPct = parseInt(outUsage.toString().trim()); - let diff = startPct - pctNum; - - if (diff > 0) { - this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); - } else if (diff < 0) { - this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); - } else { - this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); + procBat.communicate_utf8_async(null, null, (proc, res) => { + try { + let [ok, outBat, stderr] = proc.communicate_utf8_finish(res); + if (ok && outBat) { + this.parseAndUpdate(outBat); } + } catch (e) { + this.timeLabel.set_text(_("Error reading data")); } - } - - let [resUptime, outUptime] = GLib.spawn_command_line_sync("cat /proc/uptime"); - if (resUptime) { - let uptimeSeconds = parseFloat(outUptime.toString().split(" ")[0]); - let hours = Math.floor(uptimeSeconds / 3600); - let minutes = Math.floor((uptimeSeconds % 3600) / 60); - - if (hours > 0) { - this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); - } else { - this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); - } - } + }); } catch (e) { this.timeLabel.set_text(_("Error reading data")); } + if (this.timeout) Mainloop.source_remove(this.timeout); this.timeout = Mainloop.timeout_add_seconds(60, () => { this.update(); return false; }); }, + parseAndUpdate: function(output) { + let matchPct = output.match(/percentage:\s+(\d+)%/); + let matchEmpty = output.match(/time to empty:\s+(.*)/); + let matchFull = output.match(/time to full:\s+(.*)/); + let matchState = output.match(/state:\s+(.*)/); + + let pctNum = matchPct ? parseInt(matchPct[1]) : 0; + + this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); + let fillWidth = Math.round(150 * (pctNum / 100)); + this.fill.set_style("width: " + fillWidth + "px;"); + + let state = matchState ? matchState[1] : ""; + if (state === "discharging" && matchEmpty) { + this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); + } else if (state === "charging" && matchFull) { + this.timeLabel.set_text(matchFull[1] + " " + _("until full")); + } else if (state === "fully-charged") { + this.timeLabel.set_text(_("Fully charged")); + } else { + this.timeLabel.set_text(_("AC Power")); + } + + let tmpPath = "/tmp/desklet_start_bat_" + UUID + ".txt"; + let tmpFile = Gio.File.new_for_path(tmpPath); + + tmpFile.load_contents_async(null, (file, res) => { + try { + let [success, contents] = file.load_contents_finish(res); + if (success) { + let contentStr = ByteArray.toString(contents).trim(); + let startPct = contentStr !== "" ? parseInt(contentStr) : pctNum; + this.updateUsageUI(startPct, pctNum); + } + } catch (e) { + file.replace_contents_async( + pctNum.toString(), + null, + false, + Gio.FileCreateFlags.NONE, + null, + (f, r) => { + try { f.replace_contents_finish(r); } catch (err) {} + } + ); + this.updateUsageUI(pctNum, pctNum); + } + }); + + let uptimeFile = Gio.File.new_for_path("/proc/uptime"); + uptimeFile.load_contents_async(null, (file, res) => { + try { + let [success, contents] = file.load_contents_finish(res); + if (success) { + let outUptime = ByteArray.toString(contents); + let uptimeSeconds = parseFloat(outUptime.split(" ")[0]); + let hours = Math.floor(uptimeSeconds / 3600); + let minutes = Math.floor((uptimeSeconds % 3600) / 60); + + if (hours > 0) { + this.uptimeLabel.set_text(_("Uptime:") + " " + hours + _("h") + " " + minutes + _("min")); + } else { + this.uptimeLabel.set_text(_("Uptime:") + " " + minutes + _("min")); + } + } + } catch (e) {} + }); + }, + + updateUsageUI: function(startPct, currentPct) { + let diff = startPct - currentPct; + if (diff > 0) { + this.usageLabel.set_text(_("Usage:") + " " + diff + "% " + _("since start")); + } else if (diff < 0) { + this.usageLabel.set_text(_("Charged:") + " " + Math.abs(diff) + "% " + _("since start")); + } else { + this.usageLabel.set_text(_("Usage:") + " 0% " + _("since start")); + } + }, + on_desklet_removed: function() { if (this.timeout) { Mainloop.source_remove(this.timeout); From fa92b1d9542cb1f788eea691ffcf9fe9b2b94829 Mon Sep 17 00:00:00 2001 From: Milchreis Date: Sun, 14 Jun 2026 11:28:11 +0200 Subject: [PATCH 6/6] fix: missing capacity in percent on startup --- .../desklet.js | 102 ++++++++++-------- .../stylesheet.css | 3 +- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js index 7da84b99c..98f0bd61c 100644 --- a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js +++ b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/desklet.js @@ -40,15 +40,15 @@ SimpleBatteryDesklet.prototype = { this.track = new St.BoxLayout({style_class: "battery-track"}); this.fill = new St.BoxLayout({style_class: "battery-fill"}); this.track.add_actor(this.fill); - this.pctLabel = new St.Label({style_class: "battery-pct-small"}); + this.pctLabel = new St.Label({style_class: "battery-pct-small", text: "--%"}); this.barContainer.add_actor(this.track); this.barContainer.add_actor(this.pctLabel); - this.timeLabel = new St.Label({style_class: "battery-time"}); + this.timeLabel = new St.Label({style_class: "battery-time", text: "..."}); this.divider = new St.BoxLayout({style_class: "battery-divider"}); - this.uptimeLabel = new St.Label({style_class: "battery-stats"}); - this.usageLabel = new St.Label({style_class: "battery-stats"}); + this.uptimeLabel = new St.Label({style_class: "battery-stats", text: "..."}); + this.usageLabel = new St.Label({style_class: "battery-stats", text: "..."}); this.container.add_actor(this.barContainer); this.container.add_actor(this.timeLabel); @@ -70,6 +70,7 @@ SimpleBatteryDesklet.prototype = { }, update: function() { + let hasBatteryData = false; try { let procBat = Gio.Subprocess.new( ['bash', '-c', 'upower -i $(upower -e | grep -i bat | head -n 1)'], @@ -79,20 +80,25 @@ SimpleBatteryDesklet.prototype = { procBat.communicate_utf8_async(null, null, (proc, res) => { try { let [ok, outBat, stderr] = proc.communicate_utf8_finish(res); - if (ok && outBat) { - this.parseAndUpdate(outBat); + if (ok) { + hasBatteryData = this.parseAndUpdate(outBat || ""); } } catch (e) { this.timeLabel.set_text(_("Error reading data")); } + this.scheduleNextUpdate(hasBatteryData); }); } catch (e) { this.timeLabel.set_text(_("Error reading data")); + this.scheduleNextUpdate(false); } + }, + scheduleNextUpdate: function(hasBatteryData) { if (this.timeout) Mainloop.source_remove(this.timeout); - this.timeout = Mainloop.timeout_add_seconds(60, () => { + let nextUpdate = hasBatteryData ? 60 : 5; + this.timeout = Mainloop.timeout_add_seconds(nextUpdate, () => { this.update(); return false; }); @@ -104,48 +110,54 @@ SimpleBatteryDesklet.prototype = { let matchFull = output.match(/time to full:\s+(.*)/); let matchState = output.match(/state:\s+(.*)/); - let pctNum = matchPct ? parseInt(matchPct[1]) : 0; - - this.pctLabel.set_text(matchPct ? matchPct[1] + "%" : "--%"); - let fillWidth = Math.round(150 * (pctNum / 100)); - this.fill.set_style("width: " + fillWidth + "px;"); - - let state = matchState ? matchState[1] : ""; - if (state === "discharging" && matchEmpty) { - this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); - } else if (state === "charging" && matchFull) { - this.timeLabel.set_text(matchFull[1] + " " + _("until full")); - } else if (state === "fully-charged") { - this.timeLabel.set_text(_("Fully charged")); + let pctNum = 0; + let hasBatteryData = false; + + if (matchPct) { + pctNum = parseInt(matchPct[1]); + hasBatteryData = true; + this.pctLabel.set_text(matchPct[1] + "%"); + let fillWidth = Math.round(150 * (pctNum / 100)); + this.fill.set_style("width: " + fillWidth + "px;"); + + let state = matchState ? matchState[1] : ""; + if (state === "discharging" && matchEmpty) { + this.timeLabel.set_text(matchEmpty[1] + " " + _("remaining")); + } else if (state === "charging" && matchFull) { + this.timeLabel.set_text(matchFull[1] + " " + _("until full")); + } else if (state === "fully-charged") { + this.timeLabel.set_text(_("Fully charged")); + } else { + this.timeLabel.set_text(_("AC Power")); + } } else { - this.timeLabel.set_text(_("AC Power")); + this.pctLabel.set_text("--%"); + this.fill.set_style("width: 0px;"); + this.timeLabel.set_text(_("Connecting...")); } - let tmpPath = "/tmp/desklet_start_bat_" + UUID + ".txt"; - let tmpFile = Gio.File.new_for_path(tmpPath); + if (hasBatteryData) { + let tmpPath = "/tmp/desklet_start_bat_" + UUID + ".txt"; + let tmpFile = Gio.File.new_for_path(tmpPath); - tmpFile.load_contents_async(null, (file, res) => { - try { - let [success, contents] = file.load_contents_finish(res); - if (success) { - let contentStr = ByteArray.toString(contents).trim(); - let startPct = contentStr !== "" ? parseInt(contentStr) : pctNum; - this.updateUsageUI(startPct, pctNum); - } - } catch (e) { - file.replace_contents_async( - pctNum.toString(), - null, - false, - Gio.FileCreateFlags.NONE, - null, - (f, r) => { - try { f.replace_contents_finish(r); } catch (err) {} + tmpFile.load_contents_async(null, (file, res) => { + try { + let [success, contents] = file.load_contents_finish(res); + if (success) { + let contentStr = ByteArray.toString(contents).trim(); + let startPct = contentStr !== "" ? parseInt(contentStr) : pctNum; + this.updateUsageUI(startPct, pctNum); } - ); - this.updateUsageUI(pctNum, pctNum); - } - }); + } catch (e) { + try { + GLib.file_set_contents(tmpPath, pctNum.toString()); + } catch (err) {} + this.updateUsageUI(pctNum, pctNum); + } + }); + } else { + this.usageLabel.set_text(_("Usage:") + " --"); + } let uptimeFile = Gio.File.new_for_path("/proc/uptime"); uptimeFile.load_contents_async(null, (file, res) => { @@ -165,6 +177,8 @@ SimpleBatteryDesklet.prototype = { } } catch (e) {} }); + + return hasBatteryData; }, updateUsageUI: function(startPct, currentPct) { diff --git a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/stylesheet.css b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/stylesheet.css index 5fd9d169b..7739a560c 100644 --- a/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/stylesheet.css +++ b/simple-battery@suckatcoding.com/files/simple-battery@suckatcoding.com/stylesheet.css @@ -4,6 +4,7 @@ padding: 15px 20px; color: #ffffff; font-family: sans-serif; + min-width: 210px; } .battery-track { @@ -24,6 +25,7 @@ font-weight: bold; margin-left: 12px; text-shadow: 1px 1px 2px rgba(0,0,0,0.8); + min-width: 45px; } .battery-time { @@ -74,7 +76,6 @@ margin-bottom: 8px; } -/* NEU: Schriftart für Systemzeit und Verbrauch */ .battery-stats { font-size: 11px; color: #bbbbbb;