From c1a54ee466edb610917ba6d43979e7a15f8a127d Mon Sep 17 00:00:00 2001 From: Kiryl Fando Date: Wed, 9 Apr 2025 19:05:39 +0200 Subject: [PATCH 1/2] fix: group sorting logic --- package-lock.json | 8 ++++---- package.json | 2 +- .../channel-list-container.component.html | 2 +- .../channel-list-container.component.ts | 13 ++++++++++++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcf0d45b4..73cad6ce3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "date-fns": "2.29.3", "dplayer": "1.27.1", "epg-parser": "0.1.6", - "hls.js": "1.6.0", + "hls.js": "1.6.1", "iptv-playlist-parser": "github:4gray/iptv-playlist-parser", "lodash": "4.17.21", "moment": "2.30.1", @@ -12527,9 +12527,9 @@ } }, "node_modules/hls.js": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.0.tgz", - "integrity": "sha512-AlW8ymcDKZuKtzXCUmEy4nOcHRkebnShH6t6hC2+QJQP0WXlTUSSO9Kp22uSEYdCgpwkXEJsfOhqxrgO2tDctQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.1.tgz", + "integrity": "sha512-7GOkcqn0Y9EqU2OJZlzkwxj9Uynuln7URvr7dRjgqNJNZ5UbbjL/v1BjAvQogy57Psdd/ek1u2s6IDEFYlabrA==", "license": "Apache-2.0" }, "node_modules/hmac-drbg": { diff --git a/package.json b/package.json index f367194d6..59f8904b8 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "date-fns": "2.29.3", "dplayer": "1.27.1", "epg-parser": "0.1.6", - "hls.js": "1.6.0", + "hls.js": "1.6.1", "iptv-playlist-parser": "github:4gray/iptv-playlist-parser", "lodash": "4.17.21", "moment": "2.30.1", diff --git a/src/app/player/components/channel-list-container/channel-list-container.component.html b/src/app/player/components/channel-list-container/channel-list-container.component.html index ac4539969..95f34c71b 100644 --- a/src/app/player/components/channel-list-container/channel-list-container.component.html +++ b/src/app/player/components/channel-list-container/channel-list-container.component.html @@ -57,7 +57,7 @@ - @for (groups of groupedChannels | keyvalue; track $index) { + @for (groups of groupedChannels | keyvalue: groupsComparator; track $index) { @if (groups.value.length > 0) { diff --git a/src/app/player/components/channel-list-container/channel-list-container.component.ts b/src/app/player/components/channel-list-container/channel-list-container.component.ts index e38d2e4ab..b10c54ca2 100644 --- a/src/app/player/components/channel-list-container/channel-list-container.component.ts +++ b/src/app/player/components/channel-list-container/channel-list-container.component.ts @@ -4,7 +4,7 @@ import { moveItemInArray, } from '@angular/cdk/drag-drop'; import { ScrollingModule } from '@angular/cdk/scrolling'; -import { CommonModule, TitleCasePipe } from '@angular/common'; +import { CommonModule, TitleCasePipe, KeyValue } from '@angular/common'; import { Component, ElementRef, @@ -171,4 +171,15 @@ export class ChannelListContainerComponent { ngOnDestroy() { this.store.dispatch(PlaylistActions.setChannels({ channels: [] })); } + + groupsComparator = (a: KeyValue, b: KeyValue): number => { + const numA = parseInt(a.key.replace(/\D/g, '')); + const numB = parseInt(b.key.replace(/\D/g, '')); + + if (!isNaN(numA) && !isNaN(numB)) { + return numA - numB; + } + + return a.key.localeCompare(b.key); + } } From ae7544076ed212932b02e8a86b184559b360c70f Mon Sep 17 00:00:00 2001 From: Kiryl Fando Date: Wed, 9 Apr 2025 19:13:14 +0200 Subject: [PATCH 2/2] test: add tests --- .../channel-list-container.component.spec.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/app/player/components/channel-list-container/channel-list-container.component.spec.ts b/src/app/player/components/channel-list-container/channel-list-container.component.spec.ts index 14aab18da..b3c2d5dc3 100644 --- a/src/app/player/components/channel-list-container/channel-list-container.component.spec.ts +++ b/src/app/player/components/channel-list-container/channel-list-container.component.spec.ts @@ -24,6 +24,7 @@ import { ElectronServiceStub } from '../../../services/electron.service.stub'; import { createChannel } from '../../../shared/channel.model'; import { FilterPipe } from '../../../shared/pipes/filter.pipe'; import { ChannelListContainerComponent } from './channel-list-container.component'; +import { KeyValue } from '@angular/common'; class MatSnackBarStub { open(): void {} @@ -187,4 +188,48 @@ describe('ChannelListContainerComponent', () => { }); expect(mockStore.dispatch).toHaveBeenCalledTimes(1); }); + + describe('groupsComparator', () => { + it('should sort numeric groups in correct order', () => { + const groups: KeyValue[] = [ + { key: '10', value: [] }, + { key: '2', value: [] }, + { key: '1', value: [] } + ]; + + const sorted = [...groups].sort(component.groupsComparator); + + expect(sorted[0].key).toBe('1'); + expect(sorted[1].key).toBe('2'); + expect(sorted[2].key).toBe('10'); + }); + + it('should sort mixed text and numeric groups', () => { + const groups: KeyValue[] = [ + { key: 'Group 10', value: [] }, + { key: 'Group 2', value: [] }, + { key: 'Group A', value: [] } + ]; + + const sorted = [...groups].sort(component.groupsComparator); + + expect(sorted[0].key).toBe('Group 2'); + expect(sorted[1].key).toBe('Group 10'); + expect(sorted[2].key).toBe('Group A'); + }); + + it('should fall back to alphabetical sort for non-numeric groups', () => { + const groups: KeyValue[] = [ + { key: 'C', value: [] }, + { key: 'A', value: [] }, + { key: 'B', value: [] } + ]; + + const sorted = [...groups].sort(component.groupsComparator); + + expect(sorted[0].key).toBe('A'); + expect(sorted[1].key).toBe('B'); + expect(sorted[2].key).toBe('C'); + }); + }); });