From 4eb0b94ec45b331bbd287a8a38b1adb0b832dac3 Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Sat, 3 Jun 2023 18:07:16 -0500 Subject: [PATCH] Add battery extension (#504) --- extensions/battery.js | 136 ++++++++++++++++++++++++++++++++++++++++++ images/README.md | 3 + images/battery.svg | 1 + website/index.ejs | 6 ++ 4 files changed, 146 insertions(+) create mode 100644 extensions/battery.js create mode 100644 images/battery.svg diff --git a/extensions/battery.js b/extensions/battery.js new file mode 100644 index 0000000000..bf67e4ead6 --- /dev/null +++ b/extensions/battery.js @@ -0,0 +1,136 @@ +(function (Scratch) { + 'use strict'; + + /** @type {Promise|null} */ + let getBatteryPromise = null; + /** @type {BatteryManager|null} */ + let cachedBattery = null; + /** @type {boolean} */ + let batteryError = false; + const withBattery = (callback) => { + // Getting the BatteryManager is async the first time. Usually it's very fast, but we shouldn't assume that it is. + // All the logic here lets us return values immediately when we have already got the battery instead of forcing + // a delay by returning a promise. + if (!navigator.getBattery || batteryError) { + return callback(null); + } + if (cachedBattery) { + return callback(cachedBattery); + } + if (!getBatteryPromise) { + getBatteryPromise = navigator.getBattery() + .then(battery => { + getBatteryPromise = null; + cachedBattery = battery; + + cachedBattery.addEventListener('chargingchange', () => { + Scratch.vm.runtime.startHats('battery_chargingChanged'); + }); + cachedBattery.addEventListener('levelchange', () => { + Scratch.vm.runtime.startHats('battery_levelChanged'); + }); + cachedBattery.addEventListener('chargingtimechange', () => { + Scratch.vm.runtime.startHats('battery_chargeTimeChanged'); + }); + cachedBattery.addEventListener('dischargingtimechange', () => { + Scratch.vm.runtime.startHats('battery_dischargeTimeChanged'); + }); + + return cachedBattery; + }) + .catch(error => { + getBatteryPromise = null; + console.error('Could not get battery', error); + batteryError = true; + return null; + }); + } + return getBatteryPromise.then(battery => { + return callback(battery); + }); + }; + + // Try to get the battery immediately so that event blocks work. + withBattery(() => {}); + + class BatteryExtension { + getInfo () { + return { + name: 'Battery', + id: 'battery', + blocks: [ + { + opcode: 'charging', + blockType: Scratch.BlockType.BOOLEAN, + text: 'charging?' + }, + { + opcode: 'level', + blockType: Scratch.BlockType.REPORTER, + text: 'battery level' + }, + { + opcode: 'chargeTime', + blockType: Scratch.BlockType.REPORTER, + text: 'seconds until charged' + }, + { + opcode: 'dischargeTime', + blockType: Scratch.BlockType.REPORTER, + text: 'seconds until empty' + }, + { + opcode: 'chargingChanged', + blockType: Scratch.BlockType.HAT, + text: 'when charging changed', + isEdgeActivated: false + }, + { + opcode: 'levelChanged', + blockType: Scratch.BlockType.HAT, + text: 'when battery level changed', + isEdgeActivated: false + }, + { + opcode: 'chargeTimeChanged', + blockType: Scratch.BlockType.HAT, + text: 'when time until charged changed', + isEdgeActivated: false + }, + { + opcode: 'dischargeTimeChanged', + blockType: Scratch.BlockType.HAT, + text: 'when time until empty changed', + isEdgeActivated: false + }, + ] + }; + } + charging () { + return withBattery(battery => { + if (!battery) return true; + return battery.charging; + }); + } + level () { + return withBattery(battery => { + if (!battery) return 100; + return battery.level * 100; + }); + } + chargeTime () { + return withBattery(battery => { + if (!battery) return 0; + return battery.chargingTime; + }); + } + dischargeTime () { + return withBattery(battery => { + if (!battery) return Infinity; + return battery.dischargingTime; + }); + } + } + + Scratch.extensions.register(new BatteryExtension()); +})(Scratch); diff --git a/images/README.md b/images/README.md index 5838112b49..04e857b06a 100644 --- a/images/README.md +++ b/images/README.md @@ -192,3 +192,6 @@ All images in this folder are licensed under the [GNU General Public License ver - Created by [@True-Fantom](https://scratch.mit.edu/users/TrueFantom/) in https://github.com/TurboWarp/extensions/pull/498. - File icons based on https://icon-icons.com/icon/file-pdf/153412 under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). - Background based on https://bgjar.com/contour-line under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). + +## battery.svg + - Created by [@Martinelplayz](https://github.com/Martinelplayz) in https://github.com/TurboWarp/extensions/pull/504#issuecomment-1574243161 diff --git a/images/battery.svg b/images/battery.svg new file mode 100644 index 0000000000..7f67491b0f --- /dev/null +++ b/images/battery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/index.ejs b/website/index.ejs index e6e4482612..0b2176bcd0 100644 --- a/website/index.ejs +++ b/website/index.ejs @@ -476,6 +476,12 @@

Details about the user's browser and operating system.

+
+ <%- banner('battery') %> +

Battery

+

Access information about the battery of phones or laptops. May not work on all devices and browsers.

+
+
<%- banner('mdwalters/notifications') %>

Notifications