Ajout support WiFi 1-3, icônes officielles Wi-Fi Alliance et affichage par icône dans le panel
- Ajout des générations WiFi 1 (802.11b), 2 (802.11a) et 3 (802.11g) dans les types et la détection legacy (fréquence + débit) - Remplacement des icônes SVG WiFi 4-7 par les PNG officiels Wi-Fi Alliance (reverse signature, blanc sur transparent) - Conservation des icônes SVG custom pour WiFi 1-3 (non fournies par la Wi-Fi Alliance) - Remplacement de St.Label par St.Icon dans le panel avec la classe system-status-icon pour un dimensionnement adaptatif - Fallback sur St.Label texte quand aucune icône n'est disponible (génération inconnue) - Mise à jour du build pour copier les icônes dans dist/
|
|
@ -5,7 +5,7 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc && npm run copy-assets",
|
||||
"copy-assets": "cp metadata.json stylesheet.css dist/",
|
||||
"copy-assets": "cp metadata.json stylesheet.css dist/ && cp -r src/icons dist/",
|
||||
"install-extension": "npm run build && rm -rf ~/.local/share/gnome-shell/extensions/wifi-signal-plus@music-music.music && cp -r dist ~/.local/share/gnome-shell/extensions/wifi-signal-plus@music-music.music",
|
||||
"nested": "npm run install-extension && MUTTER_DEBUG_DUMMY_MODE_SPECS=1920x1080 dbus-run-session gnome-shell --devkit --wayland",
|
||||
"watch": "tsc --watch",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Gio from 'gi://Gio';
|
||||
import GLib from 'gi://GLib';
|
||||
import St from 'gi://St';
|
||||
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
|
|
@ -24,6 +25,7 @@ import {
|
|||
GENERATION_CSS_CLASSES,
|
||||
getGenerationLabel,
|
||||
getGenerationDescription,
|
||||
getGenerationIconFilename,
|
||||
} from './wifiGeneration.js';
|
||||
import type { GenerationCssClass, ChannelWidthMHz, SignalDbm } from './types.js';
|
||||
|
||||
|
|
@ -69,6 +71,7 @@ const MENU_STRUCTURE: readonly MenuItemConfig[][] = [
|
|||
|
||||
export default class WifiSignalPlusExtension extends Extension {
|
||||
private indicator: PanelMenu.Button | null = null;
|
||||
private icon: St.Icon | null = null;
|
||||
private label: St.Label | null = null;
|
||||
private wifiService: WifiInfoService | null = null;
|
||||
private refreshTimeout: number | null = null;
|
||||
|
|
@ -95,6 +98,7 @@ export default class WifiSignalPlusExtension extends Extension {
|
|||
|
||||
this.indicator = null;
|
||||
this.wifiService = null;
|
||||
this.icon = null;
|
||||
this.label = null;
|
||||
this.menuItems.clear();
|
||||
}
|
||||
|
|
@ -103,12 +107,18 @@ export default class WifiSignalPlusExtension extends Extension {
|
|||
this.indicator = new PanelMenu.Button(0.0, this.metadata.name, false);
|
||||
this.indicator.add_style_class_name('wifi-signal-plus-indicator');
|
||||
|
||||
this.icon = new St.Icon({
|
||||
style_class: 'system-status-icon',
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
});
|
||||
|
||||
this.label = new St.Label({
|
||||
text: 'WiFi',
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
style_class: 'wifi-signal-plus-label',
|
||||
});
|
||||
|
||||
this.indicator.add_child(this.icon);
|
||||
this.indicator.add_child(this.label);
|
||||
this.buildMenu();
|
||||
|
||||
|
|
@ -153,17 +163,31 @@ export default class WifiSignalPlusExtension extends Extension {
|
|||
}
|
||||
|
||||
private updateIndicatorLabel(info: WifiConnectionInfo): void {
|
||||
if (!this.label) return;
|
||||
if (!this.icon || !this.label) return;
|
||||
|
||||
this.clearGenerationStyles();
|
||||
|
||||
if (!isConnected(info)) {
|
||||
this.icon.visible = false;
|
||||
this.label.visible = true;
|
||||
this.label.set_text('WiFi --');
|
||||
this.label.add_style_class_name(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.UNKNOWN]);
|
||||
return;
|
||||
}
|
||||
|
||||
const iconFilename = getGenerationIconFilename(info.generation);
|
||||
if (iconFilename) {
|
||||
const iconPath = GLib.build_filenamev([this.path, 'icons', iconFilename]);
|
||||
const file = Gio.File.new_for_path(iconPath);
|
||||
this.icon.gicon = new Gio.FileIcon({ file });
|
||||
this.icon.visible = true;
|
||||
this.label.visible = false;
|
||||
} else {
|
||||
this.icon.visible = false;
|
||||
this.label.visible = true;
|
||||
this.label.set_text(getGenerationLabel(info.generation));
|
||||
}
|
||||
|
||||
this.label.add_style_class_name(GENERATION_CSS_CLASSES[info.generation]);
|
||||
}
|
||||
|
||||
|
|
|
|||
1
src/icons/wifi-1.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 351.257"><path fill="#2B2A29" d="M236.563 284.97c18.304 0 33.144 14.839 33.144 33.143 0 18.303-14.84 33.144-33.144 33.144-18.302 0-33.143-14.841-33.143-33.144 0-18.304 14.841-33.143 33.143-33.143zM29.48 117.684c-7.496 6.414-18.774 5.537-25.188-1.959-6.415-7.496-5.538-18.774 1.958-25.189C76.588 30.265 156.239-.682 236.97.012c78.728.675 157.969 31.439 230.049 94.426a17.777 17.777 0 014.839 6.842c-23.099-15.127-50.711-23.935-80.38-23.935-2.837 0-5.655.09-8.451.248-47.7-27.728-97.255-41.476-146.339-41.898-71.983-.617-143.514 27.41-207.208 81.989zm66.973 71.863c-7.379 6.53-18.66 5.841-25.189-1.538-6.53-7.38-5.841-18.66 1.538-25.189 52.587-46.528 108.414-70.31 165.08-69.359 22.193.374 44.361 4.531 66.356 12.588a147.915 147.915 0 00-28.978 28.332c-12.678-3.288-25.336-5.025-37.937-5.236-47.456-.797-95.11 19.913-140.87 60.402zm63.574 63.823c-7.652 6.221-18.898 5.062-25.12-2.59-6.221-7.651-5.062-18.898 2.59-25.119 31.156-25.297 64.978-38.468 99.403-38.57 4.086-.011 8.171.163 12.254.52-2.917 11.341-4.501 23.214-4.602 35.442a98.454 98.454 0 00-7.652-.278c-25.994.076-52.155 10.524-76.873 30.595z"/><path fill="#2B2A29" d="M391.477 103.761c66.558 0 120.523 53.965 120.523 120.525 0 66.558-53.965 120.522-120.523 120.522-66.56 0-120.524-53.964-120.524-120.522 0-66.56 53.964-120.525 120.524-120.525z"/><text x="391" y="232" font-family="Arial,Helvetica,sans-serif" font-size="235" font-weight="bold" fill="#fff" text-anchor="middle" dominant-baseline="central">1</text></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
1
src/icons/wifi-2.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 351.257"><path fill="#2B2A29" d="M236.563 284.97c18.304 0 33.144 14.839 33.144 33.143 0 18.303-14.84 33.144-33.144 33.144-18.302 0-33.143-14.841-33.143-33.144 0-18.304 14.841-33.143 33.143-33.143zM29.48 117.684c-7.496 6.414-18.774 5.537-25.188-1.959-6.415-7.496-5.538-18.774 1.958-25.189C76.588 30.265 156.239-.682 236.97.012c78.728.675 157.969 31.439 230.049 94.426a17.777 17.777 0 014.839 6.842c-23.099-15.127-50.711-23.935-80.38-23.935-2.837 0-5.655.09-8.451.248-47.7-27.728-97.255-41.476-146.339-41.898-71.983-.617-143.514 27.41-207.208 81.989zm66.973 71.863c-7.379 6.53-18.66 5.841-25.189-1.538-6.53-7.38-5.841-18.66 1.538-25.189 52.587-46.528 108.414-70.31 165.08-69.359 22.193.374 44.361 4.531 66.356 12.588a147.915 147.915 0 00-28.978 28.332c-12.678-3.288-25.336-5.025-37.937-5.236-47.456-.797-95.11 19.913-140.87 60.402zm63.574 63.823c-7.652 6.221-18.898 5.062-25.12-2.59-6.221-7.651-5.062-18.898 2.59-25.119 31.156-25.297 64.978-38.468 99.403-38.57 4.086-.011 8.171.163 12.254.52-2.917 11.341-4.501 23.214-4.602 35.442a98.454 98.454 0 00-7.652-.278c-25.994.076-52.155 10.524-76.873 30.595z"/><path fill="#2B2A29" d="M391.477 103.761c66.558 0 120.523 53.965 120.523 120.525 0 66.558-53.965 120.522-120.523 120.522-66.56 0-120.524-53.964-120.524-120.522 0-66.56 53.964-120.525 120.524-120.525z"/><text x="391" y="232" font-family="Arial,Helvetica,sans-serif" font-size="235" font-weight="bold" fill="#fff" text-anchor="middle" dominant-baseline="central">2</text></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
1
src/icons/wifi-3.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 351.257"><path fill="#2B2A29" d="M236.563 284.97c18.304 0 33.144 14.839 33.144 33.143 0 18.303-14.84 33.144-33.144 33.144-18.302 0-33.143-14.841-33.143-33.144 0-18.304 14.841-33.143 33.143-33.143zM29.48 117.684c-7.496 6.414-18.774 5.537-25.188-1.959-6.415-7.496-5.538-18.774 1.958-25.189C76.588 30.265 156.239-.682 236.97.012c78.728.675 157.969 31.439 230.049 94.426a17.777 17.777 0 014.839 6.842c-23.099-15.127-50.711-23.935-80.38-23.935-2.837 0-5.655.09-8.451.248-47.7-27.728-97.255-41.476-146.339-41.898-71.983-.617-143.514 27.41-207.208 81.989zm66.973 71.863c-7.379 6.53-18.66 5.841-25.189-1.538-6.53-7.38-5.841-18.66 1.538-25.189 52.587-46.528 108.414-70.31 165.08-69.359 22.193.374 44.361 4.531 66.356 12.588a147.915 147.915 0 00-28.978 28.332c-12.678-3.288-25.336-5.025-37.937-5.236-47.456-.797-95.11 19.913-140.87 60.402zm63.574 63.823c-7.652 6.221-18.898 5.062-25.12-2.59-6.221-7.651-5.062-18.898 2.59-25.119 31.156-25.297 64.978-38.468 99.403-38.57 4.086-.011 8.171.163 12.254.52-2.917 11.341-4.501 23.214-4.602 35.442a98.454 98.454 0 00-7.652-.278c-25.994.076-52.155 10.524-76.873 30.595z"/><path fill="#2B2A29" d="M391.477 103.761c66.558 0 120.523 53.965 120.523 120.525 0 66.558-53.965 120.522-120.523 120.522-66.56 0-120.524-53.964-120.524-120.522 0-66.56 53.964-120.525 120.524-120.525z"/><text x="391" y="232" font-family="Arial,Helvetica,sans-serif" font-size="235" font-weight="bold" fill="#fff" text-anchor="middle" dominant-baseline="central">3</text></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/icons/wifi-4.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
src/icons/wifi-5.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
src/icons/wifi-6.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
src/icons/wifi-7.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
15
src/types.ts
|
|
@ -17,6 +17,9 @@ export type GuardIntervalUs = Brand<number, 'GuardIntervalUs'>;
|
|||
|
||||
export const WIFI_GENERATIONS = {
|
||||
UNKNOWN: 0,
|
||||
WIFI_1: 1,
|
||||
WIFI_2: 2,
|
||||
WIFI_3: 3,
|
||||
WIFI_4: 4,
|
||||
WIFI_5: 5,
|
||||
WIFI_6: 6,
|
||||
|
|
@ -25,11 +28,14 @@ export const WIFI_GENERATIONS = {
|
|||
|
||||
export type WifiGeneration = (typeof WIFI_GENERATIONS)[keyof typeof WIFI_GENERATIONS];
|
||||
|
||||
export function isKnownGeneration(gen: WifiGeneration): gen is 4 | 5 | 6 | 7 {
|
||||
return gen >= WIFI_GENERATIONS.WIFI_4 && gen <= WIFI_GENERATIONS.WIFI_7;
|
||||
export function isKnownGeneration(gen: WifiGeneration): gen is 1 | 2 | 3 | 4 | 5 | 6 | 7 {
|
||||
return gen >= WIFI_GENERATIONS.WIFI_1 && gen <= WIFI_GENERATIONS.WIFI_7;
|
||||
}
|
||||
|
||||
export const IEEE_STANDARDS = {
|
||||
[WIFI_GENERATIONS.WIFI_1]: '802.11b',
|
||||
[WIFI_GENERATIONS.WIFI_2]: '802.11a',
|
||||
[WIFI_GENERATIONS.WIFI_3]: '802.11g',
|
||||
[WIFI_GENERATIONS.WIFI_4]: '802.11n',
|
||||
[WIFI_GENERATIONS.WIFI_5]: '802.11ac',
|
||||
[WIFI_GENERATIONS.WIFI_6]: '802.11ax',
|
||||
|
|
@ -64,10 +70,13 @@ export const SECURITY_PROTOCOLS = [
|
|||
|
||||
export type SecurityProtocol = (typeof SECURITY_PROTOCOLS)[number];
|
||||
|
||||
export type GenerationCssClass = `wifi-gen-${4 | 5 | 6 | 7}` | 'wifi-disconnected';
|
||||
export type GenerationCssClass = `wifi-gen-${1 | 2 | 3 | 4 | 5 | 6 | 7}` | 'wifi-disconnected';
|
||||
export type SignalCssClass = `wifi-signal-${Lowercase<Exclude<SignalQuality, 'Unknown'>>}` | '';
|
||||
|
||||
export const GENERATION_CSS_CLASSES = {
|
||||
[WIFI_GENERATIONS.WIFI_1]: 'wifi-gen-1',
|
||||
[WIFI_GENERATIONS.WIFI_2]: 'wifi-gen-2',
|
||||
[WIFI_GENERATIONS.WIFI_3]: 'wifi-gen-3',
|
||||
[WIFI_GENERATIONS.WIFI_4]: 'wifi-gen-4',
|
||||
[WIFI_GENERATIONS.WIFI_5]: 'wifi-gen-5',
|
||||
[WIFI_GENERATIONS.WIFI_6]: 'wifi-gen-6',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
GENERATION_CSS_CLASSES,
|
||||
getGenerationLabel,
|
||||
getGenerationDescription,
|
||||
getGenerationIconFilename,
|
||||
isKnownGeneration,
|
||||
} from './wifiGeneration';
|
||||
import { GUARD_INTERVALS } from './types';
|
||||
|
|
@ -37,6 +38,9 @@ describe('createEmptyIwLinkInfo', () => {
|
|||
|
||||
describe('isKnownGeneration', () => {
|
||||
it('should return true for known generations', () => {
|
||||
expect(isKnownGeneration(WIFI_GENERATIONS.WIFI_1)).toBe(true);
|
||||
expect(isKnownGeneration(WIFI_GENERATIONS.WIFI_2)).toBe(true);
|
||||
expect(isKnownGeneration(WIFI_GENERATIONS.WIFI_3)).toBe(true);
|
||||
expect(isKnownGeneration(WIFI_GENERATIONS.WIFI_4)).toBe(true);
|
||||
expect(isKnownGeneration(WIFI_GENERATIONS.WIFI_5)).toBe(true);
|
||||
expect(isKnownGeneration(WIFI_GENERATIONS.WIFI_6)).toBe(true);
|
||||
|
|
@ -226,8 +230,118 @@ describe('parseIwLinkOutput', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('legacy WiFi detection', () => {
|
||||
describe('WiFi 2 (802.11a) - 5 GHz legacy', () => {
|
||||
it('should detect WiFi 2 for 5 GHz without generation markers', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
SSID: LegacyNetwork
|
||||
freq: 5180
|
||||
signal: -60 dBm
|
||||
tx bitrate: 54.0 MBit/s
|
||||
rx bitrate: 48.0 MBit/s`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.WIFI_2);
|
||||
expect(result.standard).toBe('802.11a');
|
||||
});
|
||||
});
|
||||
|
||||
describe('WiFi 1 (802.11b) - 2.4 GHz low bitrate', () => {
|
||||
it('should detect WiFi 1 for 2.4 GHz with bitrate <= 11 Mbps', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
SSID: VeryOldNetwork
|
||||
freq: 2437
|
||||
signal: -70 dBm
|
||||
tx bitrate: 11.0 MBit/s
|
||||
rx bitrate: 5.5 MBit/s`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.WIFI_1);
|
||||
expect(result.standard).toBe('802.11b');
|
||||
});
|
||||
|
||||
it('should detect WiFi 1 for 2.4 GHz with 1 Mbps bitrate', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
freq: 2412
|
||||
signal: -80 dBm
|
||||
tx bitrate: 1.0 MBit/s`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.WIFI_1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('WiFi 3 (802.11g) - 2.4 GHz high bitrate', () => {
|
||||
it('should detect WiFi 3 for 2.4 GHz with bitrate > 11 Mbps', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
SSID: OlderNetwork
|
||||
freq: 2437
|
||||
signal: -55 dBm
|
||||
tx bitrate: 54.0 MBit/s
|
||||
rx bitrate: 36.0 MBit/s`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.WIFI_3);
|
||||
expect(result.standard).toBe('802.11g');
|
||||
});
|
||||
|
||||
it('should detect WiFi 3 for 2.4 GHz with 12 Mbps bitrate', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
freq: 2462
|
||||
signal: -65 dBm
|
||||
tx bitrate: 12.0 MBit/s`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.WIFI_3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('no legacy detection when generation already known', () => {
|
||||
it('should not override WiFi 4 detection with legacy', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
freq: 2437
|
||||
signal: -65 dBm
|
||||
tx bitrate: 72.2 MBit/s MCS 7 20MHz short GI`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.WIFI_4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('no legacy detection without enough info', () => {
|
||||
it('should remain UNKNOWN without frequency', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
signal: -65 dBm
|
||||
tx bitrate: 54.0 MBit/s`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.UNKNOWN);
|
||||
});
|
||||
|
||||
it('should remain UNKNOWN without bitrate on 2.4 GHz', () => {
|
||||
const iwOutput = `Connected to aa:bb:cc:dd:ee:ff (on wlan0)
|
||||
freq: 2437
|
||||
signal: -65 dBm`;
|
||||
|
||||
const result = parseIwLinkOutput(iwOutput);
|
||||
|
||||
expect(result.generation).toBe(WIFI_GENERATIONS.UNKNOWN);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGenerationLabel', () => {
|
||||
it('should return "WiFi X" for known generations', () => {
|
||||
expect(getGenerationLabel(WIFI_GENERATIONS.WIFI_1)).toBe('WiFi 1');
|
||||
expect(getGenerationLabel(WIFI_GENERATIONS.WIFI_2)).toBe('WiFi 2');
|
||||
expect(getGenerationLabel(WIFI_GENERATIONS.WIFI_3)).toBe('WiFi 3');
|
||||
expect(getGenerationLabel(WIFI_GENERATIONS.WIFI_4)).toBe('WiFi 4');
|
||||
expect(getGenerationLabel(WIFI_GENERATIONS.WIFI_5)).toBe('WiFi 5');
|
||||
expect(getGenerationLabel(WIFI_GENERATIONS.WIFI_6)).toBe('WiFi 6');
|
||||
|
|
@ -241,6 +355,9 @@ describe('getGenerationLabel', () => {
|
|||
|
||||
describe('getGenerationDescription', () => {
|
||||
it('should return full description with IEEE standard', () => {
|
||||
expect(getGenerationDescription(WIFI_GENERATIONS.WIFI_1)).toBe('WiFi 1 (802.11b)');
|
||||
expect(getGenerationDescription(WIFI_GENERATIONS.WIFI_2)).toBe('WiFi 2 (802.11a)');
|
||||
expect(getGenerationDescription(WIFI_GENERATIONS.WIFI_3)).toBe('WiFi 3 (802.11g)');
|
||||
expect(getGenerationDescription(WIFI_GENERATIONS.WIFI_4)).toBe('WiFi 4 (802.11n)');
|
||||
expect(getGenerationDescription(WIFI_GENERATIONS.WIFI_5)).toBe('WiFi 5 (802.11ac)');
|
||||
expect(getGenerationDescription(WIFI_GENERATIONS.WIFI_6)).toBe('WiFi 6 (802.11ax)');
|
||||
|
|
@ -252,8 +369,30 @@ describe('getGenerationDescription', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getGenerationIconFilename', () => {
|
||||
it('should return PNG filename for WiFi 4-7', () => {
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_4)).toBe('wifi-4.png');
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_5)).toBe('wifi-5.png');
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_6)).toBe('wifi-6.png');
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_7)).toBe('wifi-7.png');
|
||||
});
|
||||
|
||||
it('should return SVG filename for WiFi 1-3', () => {
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_1)).toBe('wifi-1.svg');
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_2)).toBe('wifi-2.svg');
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.WIFI_3)).toBe('wifi-3.svg');
|
||||
});
|
||||
|
||||
it('should return null for UNKNOWN', () => {
|
||||
expect(getGenerationIconFilename(WIFI_GENERATIONS.UNKNOWN)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('IEEE_STANDARDS', () => {
|
||||
it('should map all generations to their IEEE standards', () => {
|
||||
expect(IEEE_STANDARDS[WIFI_GENERATIONS.WIFI_1]).toBe('802.11b');
|
||||
expect(IEEE_STANDARDS[WIFI_GENERATIONS.WIFI_2]).toBe('802.11a');
|
||||
expect(IEEE_STANDARDS[WIFI_GENERATIONS.WIFI_3]).toBe('802.11g');
|
||||
expect(IEEE_STANDARDS[WIFI_GENERATIONS.WIFI_4]).toBe('802.11n');
|
||||
expect(IEEE_STANDARDS[WIFI_GENERATIONS.WIFI_5]).toBe('802.11ac');
|
||||
expect(IEEE_STANDARDS[WIFI_GENERATIONS.WIFI_6]).toBe('802.11ax');
|
||||
|
|
@ -264,6 +403,9 @@ describe('IEEE_STANDARDS', () => {
|
|||
|
||||
describe('GENERATION_CSS_CLASSES', () => {
|
||||
it('should map all generations to CSS classes', () => {
|
||||
expect(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.WIFI_1]).toBe('wifi-gen-1');
|
||||
expect(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.WIFI_2]).toBe('wifi-gen-2');
|
||||
expect(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.WIFI_3]).toBe('wifi-gen-3');
|
||||
expect(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.WIFI_4]).toBe('wifi-gen-4');
|
||||
expect(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.WIFI_5]).toBe('wifi-gen-5');
|
||||
expect(GENERATION_CSS_CLASSES[WIFI_GENERATIONS.WIFI_6]).toBe('wifi-gen-6');
|
||||
|
|
@ -272,8 +414,10 @@ describe('GENERATION_CSS_CLASSES', () => {
|
|||
});
|
||||
|
||||
it('should use template literal type pattern', () => {
|
||||
// Type check: all values should match the GenerationCssClass type
|
||||
const classes = Object.values(GENERATION_CSS_CLASSES);
|
||||
expect(classes).toContain('wifi-gen-1');
|
||||
expect(classes).toContain('wifi-gen-2');
|
||||
expect(classes).toContain('wifi-gen-3');
|
||||
expect(classes).toContain('wifi-gen-4');
|
||||
expect(classes).toContain('wifi-gen-5');
|
||||
expect(classes).toContain('wifi-gen-6');
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ export function parseIwLinkOutput(iwOutput: string): IwLinkInfo {
|
|||
parseLine(line.trim(), result);
|
||||
}
|
||||
|
||||
detectLegacyGeneration(result);
|
||||
|
||||
return freezeResult(result);
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +103,28 @@ function createMutableResult(): MutableParseResult {
|
|||
};
|
||||
}
|
||||
|
||||
const WIFI_1_MAX_BITRATE = 11;
|
||||
const FREQ_5GHZ_START = 5000;
|
||||
|
||||
function detectLegacyGeneration(result: MutableParseResult): void {
|
||||
if (result.generation !== WIFI_GENERATIONS.UNKNOWN) return;
|
||||
if (result.frequency === null) return;
|
||||
|
||||
if (result.frequency >= FREQ_5GHZ_START) {
|
||||
result.generation = WIFI_GENERATIONS.WIFI_2;
|
||||
return;
|
||||
}
|
||||
|
||||
const maxBitrate = Math.max(
|
||||
(result.txBitrate as number | null) ?? 0,
|
||||
(result.rxBitrate as number | null) ?? 0
|
||||
);
|
||||
if (maxBitrate === 0) return;
|
||||
|
||||
result.generation =
|
||||
maxBitrate <= WIFI_1_MAX_BITRATE ? WIFI_GENERATIONS.WIFI_1 : WIFI_GENERATIONS.WIFI_3;
|
||||
}
|
||||
|
||||
function freezeResult(result: MutableParseResult): IwLinkInfo {
|
||||
if (isKnownGeneration(result.generation)) {
|
||||
result.standard = IEEE_STANDARDS[result.generation];
|
||||
|
|
@ -285,3 +309,18 @@ export function getGenerationDescription(generation: WifiGeneration): string {
|
|||
? `WiFi ${generation} (${IEEE_STANDARDS[generation]})`
|
||||
: 'WiFi';
|
||||
}
|
||||
|
||||
const GENERATION_ICON_FILENAMES: Record<WifiGeneration, string | null> = {
|
||||
[WIFI_GENERATIONS.WIFI_1]: 'wifi-1.svg',
|
||||
[WIFI_GENERATIONS.WIFI_2]: 'wifi-2.svg',
|
||||
[WIFI_GENERATIONS.WIFI_3]: 'wifi-3.svg',
|
||||
[WIFI_GENERATIONS.WIFI_4]: 'wifi-4.png',
|
||||
[WIFI_GENERATIONS.WIFI_5]: 'wifi-5.png',
|
||||
[WIFI_GENERATIONS.WIFI_6]: 'wifi-6.png',
|
||||
[WIFI_GENERATIONS.WIFI_7]: 'wifi-7.png',
|
||||
[WIFI_GENERATIONS.UNKNOWN]: null,
|
||||
} as const;
|
||||
|
||||
export function getGenerationIconFilename(generation: WifiGeneration): string | null {
|
||||
return GENERATION_ICON_FILENAMES[generation];
|
||||
}
|
||||
|
|
|
|||