aboutsummaryrefslogtreecommitdiff
path: root/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx')
-rwxr-xr-xusers/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx183
1 files changed, 183 insertions, 0 deletions
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx
new file mode 100755
index 0000000..1f08af6
--- /dev/null
+++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx
@@ -0,0 +1,183 @@
1import * as Uebersicht from "uebersicht";
2import * as DataWidget from "./data-widget.jsx";
3import * as DataWidgetLoader from "./data-widget-loader.jsx";
4import * as Icons from "../icons/icons.jsx";
5import { SuspenseIcon } from "../icons/icon.jsx";
6import useWidgetRefresh from "../../hooks/use-widget-refresh";
7import useServerSocket from "../../hooks/use-server-socket";
8import { useSimpleBarContext } from "../simple-bar-context.jsx";
9import * as Utils from "../../utils";
10
11export { batteryStyles as styles } from "../../styles/components/data/battery";
12
13const { React } = Uebersicht;
14
15const DEFAULT_REFRESH_FREQUENCY = 10000;
16
17/**
18 * Battery widget component
19 * @returns {JSX.Element|null} The battery widget component
20 */
21export const Widget = React.memo(() => {
22 const { displayIndex, settings, pushMissive } = useSimpleBarContext();
23 const { widgets, batteryWidgetOptions } = settings;
24 const { batteryWidget } = widgets;
25 const {
26 refreshFrequency,
27 toggleCaffeinateOnClick,
28 caffeinateOption,
29 disableCaffeinateInvertedBackground,
30 showOnDisplay,
31 showIcon,
32 } = batteryWidgetOptions;
33
34 // Determine if the widget should be visible based on display settings
35 const visible =
36 Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && batteryWidget;
37
38 // Calculate the refresh frequency for the widget
39 const refresh = React.useMemo(
40 () =>
41 Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY),
42 [refreshFrequency],
43 );
44
45 const [state, setState] = React.useState();
46 const [loading, setLoading] = React.useState(visible);
47
48 // Reset the widget state
49 const resetWidget = () => {
50 setState(undefined);
51 setLoading(false);
52 };
53
54 /**
55 * Fetch battery information and update the state
56 */
57 const getBattery = React.useCallback(async () => {
58 if (!visible) return;
59 // Fetch battery information and parse the results
60 const [system, percentage, status, caffeinate, lowPowerMode] =
61 await Promise.all([
62 Utils.getSystem(),
63 Utils.cachedRun(
64 `pmset -g batt | grep -Eo '[0-9]+%' | head -1 | tr -d '%'`,
65 refresh,
66 ),
67 Utils.cachedRun(
68 `pmset -g batt | head -1 | grep -q 'AC Power' && echo 'AC' || echo 'Batt'`,
69 refresh,
70 ),
71 Uebersicht.run(`pgrep caffeinate -d`),
72 Utils.cachedRun(
73 `pmset -g | awk '/lowpowermode|powermode/ {print $2; exit}'`,
74 refresh,
75 ),
76 ]);
77 setState({
78 system,
79 percentage: parseInt(percentage, 10),
80 charging: Utils.cleanupOutput(status) === "AC",
81 caffeinate: Utils.cleanupOutput(caffeinate),
82 lowPowerMode: Utils.cleanupOutput(lowPowerMode) === "1",
83 });
84 setLoading(false);
85 }, [visible, refresh]);
86
87 // Use server socket to fetch battery data
88 useServerSocket("battery", visible, getBattery, resetWidget, setLoading);
89 // Refresh the widget at the specified interval
90 useWidgetRefresh(visible, getBattery, refresh);
91
92 if (loading) return <DataWidgetLoader.Widget className="battery" />;
93 if (!state) return null;
94
95 const { system, percentage, charging, caffeinate, lowPowerMode } = state;
96 const isLowBattery = !charging && percentage < 20;
97
98 const classes = Utils.classNames("battery", {
99 "battery--low": isLowBattery,
100 "battery--low-power-mode": lowPowerMode,
101 "battery--caffeinate":
102 !disableCaffeinateInvertedBackground && caffeinate.length > 0,
103 });
104
105 const transformValue = getTransform(percentage);
106
107 /**
108 * Handle click event to toggle caffeinate mode
109 * @param {React.MouseEvent} e - The click event
110 */
111 const onClick = async (e) => {
112 Utils.clickEffect(e);
113 await toggleCaffeinate(system, caffeinate, caffeinateOption, pushMissive);
114 getBattery();
115 };
116
117 const onClickProp = toggleCaffeinateOnClick ? { onClick } : {};
118
119 const Icon = () => (
120 <div className="battery__icon">
121 <div className="battery__icon-inner">
122 <div
123 className="battery__icon-filler"
124 style={{ transform: transformValue }}
125 />
126 {charging && (
127 <SuspenseIcon>
128 <Icons.Charging className="battery__charging-icon" />
129 </SuspenseIcon>
130 )}
131 </div>
132 </div>
133 );
134
135 return (
136 <DataWidget.Widget
137 classes={classes}
138 Icon={showIcon ? Icon : null}
139 disableSlider
140 {...onClickProp}
141 >
142 {caffeinate.length > 0 && (
143 <SuspenseIcon>
144 <Icons.Coffee className="battery__caffeinate-icon" />
145 </SuspenseIcon>
146 )}
147 {percentage}%
148 </DataWidget.Widget>
149 );
150});
151
152Widget.displayName = "Battery";
153
154/**
155 * Get the transform value for the battery icon based on the percentage
156 * @param {number} value - The battery percentage
157 * @returns {string} The transform value
158 */
159function getTransform(value) {
160 let transform = `0.${value}`;
161 if (value === 100) transform = "1";
162 if (value < 10) transform = `0.0${value}`;
163 return `scaleX(${transform})`;
164}
165
166/**
167 * Toggle caffeinate mode on or off
168 * @param {string} system - The system architecture
169 * @param {string} caffeinate - The current caffeinate state
170 * @param {string} option - The caffeinate option
171 * @param {function} pushMissive - Function to push notifications
172 */
173async function toggleCaffeinate(system, caffeinate, option, pushMissive) {
174 const command =
175 system === "x86_64" ? "caffeinate" : "arch -arch arm64 caffeinate";
176 if (caffeinate.length === 0) {
177 Uebersicht.run(`${command} ${option} &`);
178 Utils.notification("Enabling caffeinate...", pushMissive);
179 } else {
180 await Uebersicht.run("pkill -f caffeinate");
181 Utils.notification("Disabling caffeinate...", pushMissive);
182 }
183}