From b7993dfb40bf1b3960a7cf90c418524494b83dbf Mon Sep 17 00:00:00 2001 From: Sam Lanning Date: Sat, 12 Feb 2022 11:30:04 +0000 Subject: [PATCH 1/3] Introduce type-definitions for `node-gtk` Beyond this, a few improvements were made, including: * Explicitly returning `null` instead of an empty object when given falsy objects from node-gtk * filtering out falsy objects from gobject lists * removing unnecessary / unsafe use of "as" * Improved types for `reduceArray` to improve type inference and remove requirement for using `any` as parameter types for conversion functions * Removed use of `any` in `bridge_objects` functions * Correct type of `ac_status` which was incorrect --- ts/bridge/bridge.ts | 52 +++++++-------- ts/bridge/bridge_objects.ts | 29 +++++--- ts/ldm_interfaces.ts | 2 +- ts/lib/node-gtk-lightdm.d.ts | 126 +++++++++++++++++++++++++++++++++++ ts/lib/node-gtk.d.ts | 16 +++++ 5 files changed, 187 insertions(+), 38 deletions(-) create mode 100644 ts/lib/node-gtk-lightdm.d.ts create mode 100644 ts/lib/node-gtk.d.ts diff --git a/ts/bridge/bridge.ts b/ts/bridge/bridge.ts index 63be7c3..81d487d 100644 --- a/ts/bridge/bridge.ts +++ b/ts/bridge/bridge.ts @@ -1,5 +1,4 @@ import { dialog, ipcMain } from "electron"; -// @ts-ignore Until there's a @types/node-gtk import * as gi from "node-gtk"; import * as fs from "fs"; import * as os from "os"; @@ -150,7 +149,7 @@ export class Greeter { * @readonly * @deprecated Use `battery_data` */ - get batteryData(): LightDMBattery | object { + get batteryData(): LightDMBattery | null { return battery_to_obj(this._battery); } @@ -158,7 +157,7 @@ export class Greeter { * Gets the battery data. * @readonly */ - get battery_data(): LightDMBattery | object { + get battery_data(): LightDMBattery | null { return battery_to_obj(this._battery); } @@ -276,7 +275,7 @@ export class Greeter { * The current language or "null" if no language. * @readonly */ - get language(): LightDMLanguage | object { + get language(): LightDMLanguage | null { return language_to_obj(LightDM.getLanguage()); } @@ -285,22 +284,23 @@ export class Greeter { * @readonly */ get languages(): LightDMLanguage[] { - return reduceArray( - LightDM.getLanguages(), - language_to_obj - ) as LightDMLanguage[]; + return reduceArray(LightDM.getLanguages(), language_to_obj).filter( + isDefined + ); } /** * The currently active layout for the selected user. */ - get layout(): LightDMLayout | object { + get layout(): LightDMLayout | null { return layout_to_obj(LightDM.getLayout()); } - set layout(layout: LightDMLayout | object) { - LightDM.getLayout(); - LightDM.setLayout(new LightDM.Layout(layout)); + set layout(layout: LightDMLayout | null) { + if (layout) { + LightDM.getLayout(); + LightDM.setLayout(new LightDM.Layout(layout)); + } } /** @@ -308,7 +308,7 @@ export class Greeter { * @readonly */ get layouts(): LightDMLayout[] { - return reduceArray(LightDM.getLayouts(), layout_to_obj) as LightDMLayout[]; + return reduceArray(LightDM.getLayouts(), layout_to_obj).filter(isDefined); } /** @@ -324,10 +324,9 @@ export class Greeter { * @readonly */ get remote_sessions(): LightDMSession[] { - return reduceArray( - LightDM.getRemoteSessions(), - session_to_obj - ) as LightDMSession[]; + return reduceArray(LightDM.getRemoteSessions(), session_to_obj).filter( + isDefined + ); } /** @@ -351,10 +350,7 @@ export class Greeter { * @readonly */ get sessions(): LightDMSession[] { - return reduceArray( - LightDM.getSessions(), - session_to_obj - ) as LightDMSession[]; + return reduceArray(LightDM.getSessions(), session_to_obj).filter(isDefined); } /** @@ -390,7 +386,7 @@ export class Greeter { * @readonly */ get users(): LightDMUser[] { - return reduceArray(LightDMUsers.getUsers(), user_to_obj) as LightDMUser[]; + return reduceArray(LightDMUsers.getUsers(), user_to_obj).filter(isDefined); } /** @@ -553,8 +549,8 @@ function get_layouts(config_layouts: string[]): LightDMLayout[] { for (let conf_lay of config_layouts) { conf_lay = conf_lay.replace(/\s/g, "\t"); if (ldm_lay.getName() == conf_lay) { - const lays_chips = layout_to_obj(ldm_lay) as LightDMLayout; - if (Object.keys(lays_chips).length == 0) continue; + const lays_chips = layout_to_obj(ldm_lay); + if (!lays_chips) continue; final.push(lays_chips); } } @@ -715,15 +711,19 @@ export class ThemeUtils { } } -function reduceArray(arr: unknown[], func: (arg: unknown) => T): T[] { +function reduceArray(arr: I[], func: (arg: I) => O): O[] { if (!Array.isArray(arr)) return []; - return arr.reduce((acc: T[], val) => { + return arr.reduce((acc: O[], val) => { const v = func(val); acc.push(v); return acc; }, []); } +function isDefined(val: T | null | undefined): val is T { + return val !== null && val !== undefined; +} + function hasKey(obj: T, key: PropertyKey): key is keyof T { return key in obj; } diff --git a/ts/bridge/bridge_objects.ts b/ts/bridge/bridge_objects.ts index c74b8c5..8d2bdfe 100644 --- a/ts/bridge/bridge_objects.ts +++ b/ts/bridge/bridge_objects.ts @@ -6,9 +6,14 @@ import { LightDMUser, } from "../ldm_interfaces"; +import { LightDM } from "node-gtk"; +import { Battery } from "../utils/battery"; + // eslint-disable-next-line -function session_to_obj(session: any): LightDMSession | object { - if (!session) return {}; +function session_to_obj( + session: LightDM.LightDMSession +): LightDMSession | null { + if (!session) return null; return { comment: session.getComment(), key: session.getKey(), @@ -18,8 +23,8 @@ function session_to_obj(session: any): LightDMSession | object { } // eslint-disable-next-line -function user_to_obj(user: any): LightDMUser | object { - if (!user) return {}; +function user_to_obj(user: LightDM.LightDMUser): LightDMUser | null { + if (!user) return null; return { background: user.getBackground(), display_name: user.getDisplayName(), @@ -35,8 +40,10 @@ function user_to_obj(user: any): LightDMUser | object { } // eslint-disable-next-line -function language_to_obj(lang: any): LightDMLanguage | object { - if (!lang) return {}; +function language_to_obj( + lang: LightDM.LightDMLanguage +): LightDMLanguage | null { + if (!lang) return null; return { code: lang.getCode(), name: lang.getName(), @@ -45,8 +52,8 @@ function language_to_obj(lang: any): LightDMLanguage | object { } // eslint-disable-next-line -function layout_to_obj(layout: any): LightDMLayout | object { - if (!layout) return {}; +function layout_to_obj(layout: LightDM.LightDMLayout): LightDMLayout | null { + if (!layout) return null; return { description: layout.getDescription(), name: layout.getName(), @@ -55,9 +62,9 @@ function layout_to_obj(layout: any): LightDMLayout | object { } // eslint-disable-next-line -function battery_to_obj(battery: any): LightDMBattery | object { - if (!battery) return {}; - if (battery._batteries.length == 0) return {}; +function battery_to_obj(battery: Battery): LightDMBattery | null { + if (!battery) return null; + if (battery._batteries.length == 0) return null; return { name: battery.name, level: battery.level, diff --git a/ts/ldm_interfaces.ts b/ts/ldm_interfaces.ts index a152068..94bd741 100644 --- a/ts/ldm_interfaces.ts +++ b/ts/ldm_interfaces.ts @@ -34,7 +34,7 @@ interface LightDMBattery { name: string; level: number; status: string; - ac_status: boolean; + ac_status: string | number; capacity: number; time: string; watt: number; diff --git a/ts/lib/node-gtk-lightdm.d.ts b/ts/lib/node-gtk-lightdm.d.ts new file mode 100644 index 0000000..1518a5b --- /dev/null +++ b/ts/lib/node-gtk-lightdm.d.ts @@ -0,0 +1,126 @@ +/* + * TODO: remove once @types/node-gtk exists + * (or an equivalent that provides the lightdm specific types). + * + * It is unlikely that a library such as @types/node-gtk will be sufficient to + * provide safe types, as the types exposed by `node-gtk` depend on the gobject + * library that is being used. However if separate `.d.ts` libraries are made + * available for different gobject libraries, then that would work. + */ + +declare module "node-gtk" { + /** + * Namespace for all LightDM related types. + */ + export namespace LightDM { + class LightDMGreeter { + connectToDaemonSync(): void; + ensureSharedDataDirSync(name: string): string; + getLockHint(): boolean; + getAuthenticationUser(): string | undefined; + getAutologinGuestHint(): boolean; + getAutologinTimeoutHint(): number; + getAutologinUserHint(): string; + getDefaultSessionHint(): string; + getHasGuestAccountHint(): boolean; + getHideUsersHint(): boolean; + getInAuthentication(): boolean; + getIsAuthenticated(): boolean; + getSelectGuestHint(): boolean; + getSelectUserHint(): string; + getShowManualLoginHint(): boolean; + getShowRemoteLoginHint(): boolean; + + connect(ev: "authentication-complete", handler: () => void); + connect(ev: "autologin-timer-expired", handler: () => void); + connect( + ev: "show-message", + handler: (text: string, type: number) => void + ); + connect(ev: "show-prompt", handler: (text: string, type: number) => void); + connect(ev: "idle", handler: () => void); + connect(ev: "reset", handler: () => void); + + authenticate(username: string | null): boolean; + authenticateAsGuest(): boolean; + cancelAuthentication(): boolean; + cancelAutologin(): boolean; + respond(prompt: string); + setLanguage(language: string); + startSessionSync(session: string | null): boolean; + } + + export type { LightDMGreeter }; + + export interface LightDMUser { + name: string; + getBackground(): string; + getDisplayName(): string; + getHomeDirectory(): string; + getImage(): string; + getLanguage(): string; + getLayout(): string; + getLayouts(): string[]; + getLoggedIn(): boolean; + getSession(): string; + getName(): string; + } + + class LightDMUserList { + getUsers(): LightDMUser[]; + } + + export type { LightDMUserList }; + + export interface LightDMLanguage { + getCode(): string; + getName(): string; + getTerritory(): string; + } + + export interface LightDMSession { + getComment(): string; + getKey(): string; + getName(): string; + getSessionType(): string; + } + + class LightDMLayout { + constructor(layout: { + name: string; + description: string; + short_description: string; + }); + getDescription(): string; + getName(): string; + getShortDescription(): string; + } + + export type { LightDMLayout }; + + export interface LightDM { + Greeter: typeof LightDMGreeter; + UserList: typeof LightDMUserList; + Layout: typeof LightDMLayout; + getCanHibernate(): boolean; + getCanRestart(): boolean; + getCanShutdown(): boolean; + getCanSuspend(): boolean; + getHostname(): string; + getLanguage(): LightDMLanguage; + getLanguages(): LightDMLanguage[]; + getLayout(): LightDMLayout; + getLayouts(): LightDMLayout[]; + setLayout(layout: LightDMLayout): void; + getRemoteSessions(): LightDMSession[]; + getSessions(): LightDMSession[]; + hibernate(): boolean; + restart(): boolean; + shutdown(): boolean; + suspend(): boolean; + } + } + + export function require(name: "LightDM", version: "1"): LightDM.LightDM; + export function require(name: "LightDM2", version: "1"): LightDM.LightDM; +} diff --git a/ts/lib/node-gtk.d.ts b/ts/lib/node-gtk.d.ts new file mode 100644 index 0000000..2f9c645 --- /dev/null +++ b/ts/lib/node-gtk.d.ts @@ -0,0 +1,16 @@ +/** + * TODO: remove once @types/node-gtk exists + * + * These type definitions for `node-gtk` do not include the individual + * type-definitions for most libraries. Instead you must include the specific + * type definitions for the gobject library you wish to use. + */ + +declare module "node-gtk" { + /** + * These type definitions for `node-gtk` do not include the individual + * type-definitions for most libraries. Instead you must include the specific + * type definitions for the gobject library you wish to use. + */ + export function require(name: never, version?: never): never; +} From 1c8fe69adae704908bfedf87b96f837caa750d21 Mon Sep 17 00:00:00 2001 From: JezerM Date: Thu, 17 Feb 2022 10:58:36 -0600 Subject: [PATCH 2/3] More types and improvements --- ts/lib/node-gtk-gio.d.ts | 16 +++++++ ts/lib/node-gtk-gobject.d.ts | 10 ++++ ts/lib/node-gtk-lightdm.d.ts | 90 ++++++++++++++++++++++++++++++++++-- 3 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 ts/lib/node-gtk-gio.d.ts create mode 100644 ts/lib/node-gtk-gobject.d.ts diff --git a/ts/lib/node-gtk-gio.d.ts b/ts/lib/node-gtk-gio.d.ts new file mode 100644 index 0000000..ca1f28d --- /dev/null +++ b/ts/lib/node-gtk-gio.d.ts @@ -0,0 +1,16 @@ +declare module "node-gtk" { + export namespace Gio { + abstract class AsyncResult {} + class Task implements AsyncResult {} + class SimpleAsyncResult implements AsyncResult {} + class Cancellable {} + + export interface Gio { + Cancellable: typeof Cancellable; + Task: typeof Task; + SimpleAsyncResult: typeof SimpleAsyncResult; + AsyncResult: typeof AsyncResult; + } + } + export function require(name: "Gio", version: "2.0"): Gio.Gio; +} diff --git a/ts/lib/node-gtk-gobject.d.ts b/ts/lib/node-gtk-gobject.d.ts new file mode 100644 index 0000000..c51f8b1 --- /dev/null +++ b/ts/lib/node-gtk-gobject.d.ts @@ -0,0 +1,10 @@ +declare module "node-gtk" { + export namespace GObject { + class Object {} + + export interface GObject { + Object: typeof Object; + } + } + export function require(name: "GObject", version: "2.0"): GObject.GObject; +} diff --git a/ts/lib/node-gtk-lightdm.d.ts b/ts/lib/node-gtk-lightdm.d.ts index 1518a5b..054cfa3 100644 --- a/ts/lib/node-gtk-lightdm.d.ts +++ b/ts/lib/node-gtk-lightdm.d.ts @@ -14,8 +14,33 @@ declare module "node-gtk" { */ export namespace LightDM { class LightDMGreeter { - connectToDaemonSync(): void; + connectToDaemon( + cancellable?: Gio.Cancellable | null, + callback?: + | (( + object: GObject.Object, + res: Gio.AsyncResult, + user_data: unknown + ) => void) + | null, + user_data?: unknown + ): void; + connectToDaemonFinish(result: Gio.AsyncResult): boolean; + connectToDaemonSync(): boolean; + ensureSharedDataDir( + name: string, + cancellable?: Gio.Cancellable | null, + callback?: + | (( + object: GObject.Object, + res: Gio.AsyncResult, + user_data: unknown + ) => void) + | null, + user_data?: unknown + ): void; ensureSharedDataDirSync(name: string): string; + ensureSharedDataDirFinish(result: Gio.AsyncResult): boolean; getLockHint(): boolean; getAuthenticationUser(): string | undefined; getAutologinGuestHint(): boolean; @@ -47,38 +72,86 @@ declare module "node-gtk" { cancelAutologin(): boolean; respond(prompt: string); setLanguage(language: string); + setResettable(resettable: boolean): void; + startSession( + session: string | null, + cancellable?: Gio.Cancellable | null, + callback?: + | (( + object: GObject.Object, + res: Gio.AsyncResult, + user_data: unknown + ) => void) + | null, + user_data?: unknown + ): boolean; startSessionSync(session: string | null): boolean; } export type { LightDMGreeter }; export interface LightDMUser { + background: string; + displayName: string; + hasMessages: boolean; + homeDirectory: string; + image: string; + language: string; + layout: string; + layouts: string[]; + loggedIn: boolean; name: string; + realName: string; + session: string; + uid: number; + getBackground(): string; getDisplayName(): string; + getHasMessages(): boolean; getHomeDirectory(): string; getImage(): string; getLanguage(): string; getLayout(): string; getLayouts(): string[]; getLoggedIn(): boolean; - getSession(): string; getName(): string; + getRealName(): string; + getSession(): string; + getUid(): number; } class LightDMUserList { + length: number; + getUsers(): LightDMUser[]; + getLength(): number; + getUserByName(username: string): LightDMUser | null; + connect(ev: "user-added", handler: (user: LightDMUser) => void); + connect(ev: "user-changed", handler: (user: LightDMUser) => void); + connect(ev: "user-removed", handler: (user: LightDMUser) => void); } export type { LightDMUserList }; - export interface LightDMLanguage { + class LightDMLanguage { + constructor(language: { code: string }); + code: string; + name: string; + territory: string; + getCode(): string; getName(): string; getTerritory(): string; + matches(code: string): boolean; } + export type { LightDMLanguage }; + export interface LightDMSession { + comment: string; + key: string; + name: string; + getComment(): string; getKey(): string; getName(): string; @@ -91,6 +164,10 @@ declare module "node-gtk" { description: string; short_description: string; }); + name: string; + description: string; + short_description: string; + getDescription(): string; getName(): string; getShortDescription(): string; @@ -112,6 +189,12 @@ declare module "node-gtk" { getLayout(): LightDMLayout; getLayouts(): LightDMLayout[]; setLayout(layout: LightDMLayout): void; + getMotd(): string | null; + getOsName(): string | null; + getOsId(): string | null; + getOsPrettyName(): string | null; + getOsVersion(): string | null; + getOsVersionId(): string | null; getRemoteSessions(): LightDMSession[]; getSessions(): LightDMSession[]; hibernate(): boolean; @@ -122,5 +205,4 @@ declare module "node-gtk" { } export function require(name: "LightDM", version: "1"): LightDM.LightDM; - export function require(name: "LightDM2", version: "1"): LightDM.LightDM; } From 335eadaf301330befc6e27d3a2962fca6a7682dd Mon Sep 17 00:00:00 2001 From: JezerM Date: Wed, 9 Mar 2022 20:20:22 -0600 Subject: [PATCH 3/3] Fix explicit-member-accessibility and Battery accesibility --- ts/ldm_interfaces.ts | 2 +- ts/lib/node-gtk-lightdm.d.ts | 125 ++++++++++++++++++----------------- ts/utils/battery.ts | 4 +- 3 files changed, 67 insertions(+), 64 deletions(-) diff --git a/ts/ldm_interfaces.ts b/ts/ldm_interfaces.ts index 94bd741..a152068 100644 --- a/ts/ldm_interfaces.ts +++ b/ts/ldm_interfaces.ts @@ -34,7 +34,7 @@ interface LightDMBattery { name: string; level: number; status: string; - ac_status: string | number; + ac_status: boolean; capacity: number; time: string; watt: number; diff --git a/ts/lib/node-gtk-lightdm.d.ts b/ts/lib/node-gtk-lightdm.d.ts index 054cfa3..6b0118e 100644 --- a/ts/lib/node-gtk-lightdm.d.ts +++ b/ts/lib/node-gtk-lightdm.d.ts @@ -14,7 +14,7 @@ declare module "node-gtk" { */ export namespace LightDM { class LightDMGreeter { - connectToDaemon( + public connectToDaemon( cancellable?: Gio.Cancellable | null, callback?: | (( @@ -25,9 +25,9 @@ declare module "node-gtk" { | null, user_data?: unknown ): void; - connectToDaemonFinish(result: Gio.AsyncResult): boolean; - connectToDaemonSync(): boolean; - ensureSharedDataDir( + public connectToDaemonFinish(result: Gio.AsyncResult): boolean; + public connectToDaemonSync(): boolean; + public ensureSharedDataDir( name: string, cancellable?: Gio.Cancellable | null, callback?: @@ -39,41 +39,44 @@ declare module "node-gtk" { | null, user_data?: unknown ): void; - ensureSharedDataDirSync(name: string): string; - ensureSharedDataDirFinish(result: Gio.AsyncResult): boolean; - getLockHint(): boolean; - getAuthenticationUser(): string | undefined; - getAutologinGuestHint(): boolean; - getAutologinTimeoutHint(): number; - getAutologinUserHint(): string; - getDefaultSessionHint(): string; - getHasGuestAccountHint(): boolean; - getHideUsersHint(): boolean; - getInAuthentication(): boolean; - getIsAuthenticated(): boolean; - getSelectGuestHint(): boolean; - getSelectUserHint(): string; - getShowManualLoginHint(): boolean; - getShowRemoteLoginHint(): boolean; - - connect(ev: "authentication-complete", handler: () => void); - connect(ev: "autologin-timer-expired", handler: () => void); - connect( + public ensureSharedDataDirSync(name: string): string; + public ensureSharedDataDirFinish(result: Gio.AsyncResult): boolean; + public getLockHint(): boolean; + public getAuthenticationUser(): string | undefined; + public getAutologinGuestHint(): boolean; + public getAutologinTimeoutHint(): number; + public getAutologinUserHint(): string; + public getDefaultSessionHint(): string; + public getHasGuestAccountHint(): boolean; + public getHideUsersHint(): boolean; + public getInAuthentication(): boolean; + public getIsAuthenticated(): boolean; + public getSelectGuestHint(): boolean; + public getSelectUserHint(): string; + public getShowManualLoginHint(): boolean; + public getShowRemoteLoginHint(): boolean; + + public connect(ev: "authentication-complete", handler: () => void); + public connect(ev: "autologin-timer-expired", handler: () => void); + public connect( ev: "show-message", handler: (text: string, type: number) => void ); - connect(ev: "show-prompt", handler: (text: string, type: number) => void); - connect(ev: "idle", handler: () => void); - connect(ev: "reset", handler: () => void); - - authenticate(username: string | null): boolean; - authenticateAsGuest(): boolean; - cancelAuthentication(): boolean; - cancelAutologin(): boolean; - respond(prompt: string); - setLanguage(language: string); - setResettable(resettable: boolean): void; - startSession( + public connect( + ev: "show-prompt", + handler: (text: string, type: number) => void + ); + public connect(ev: "idle", handler: () => void); + public connect(ev: "reset", handler: () => void); + + public authenticate(username: string | null): boolean; + public authenticateAsGuest(): boolean; + public cancelAuthentication(): boolean; + public cancelAutologin(): boolean; + public respond(prompt: string); + public setLanguage(language: string); + public setResettable(resettable: boolean): void; + public startSession( session: string | null, cancellable?: Gio.Cancellable | null, callback?: @@ -85,7 +88,7 @@ declare module "node-gtk" { | null, user_data?: unknown ): boolean; - startSessionSync(session: string | null): boolean; + public startSessionSync(session: string | null): boolean; } export type { LightDMGreeter }; @@ -121,28 +124,28 @@ declare module "node-gtk" { } class LightDMUserList { - length: number; - - getUsers(): LightDMUser[]; - getLength(): number; - getUserByName(username: string): LightDMUser | null; - connect(ev: "user-added", handler: (user: LightDMUser) => void); - connect(ev: "user-changed", handler: (user: LightDMUser) => void); - connect(ev: "user-removed", handler: (user: LightDMUser) => void); + public length: number; + + public getUsers(): LightDMUser[]; + public getLength(): number; + public getUserByName(username: string): LightDMUser | null; + public connect(ev: "user-added", handler: (user: LightDMUser) => void); + public connect(ev: "user-changed", handler: (user: LightDMUser) => void); + public connect(ev: "user-removed", handler: (user: LightDMUser) => void); } export type { LightDMUserList }; class LightDMLanguage { - constructor(language: { code: string }); - code: string; - name: string; - territory: string; - - getCode(): string; - getName(): string; - getTerritory(): string; - matches(code: string): boolean; + public constructor(language: { code: string }); + public code: string; + public name: string; + public territory: string; + + public getCode(): string; + public getName(): string; + public getTerritory(): string; + public matches(code: string): boolean; } export type { LightDMLanguage }; @@ -159,18 +162,18 @@ declare module "node-gtk" { } class LightDMLayout { - constructor(layout: { + public constructor(layout: { name: string; description: string; short_description: string; }); - name: string; - description: string; - short_description: string; + public name: string; + public description: string; + public short_description: string; - getDescription(): string; - getName(): string; - getShortDescription(): string; + public getDescription(): string; + public getName(): string; + public getShortDescription(): string; } export type { LightDMLayout }; diff --git a/ts/utils/battery.ts b/ts/utils/battery.ts index 34f9c0e..0f1a0c5 100644 --- a/ts/utils/battery.ts +++ b/ts/utils/battery.ts @@ -14,9 +14,9 @@ interface battery { let running_update = false; class Battery { - private _batteries: battery[] = []; - private _ac = "AC0"; + public _batteries: battery[] = []; public ps_path = "/sys/class/power_supply/"; + private _ac = "AC0"; private _perc = -1; private _status = "N/A"; private _ac_status = false;