Skip to content

Commit 5d13b6a

Browse files
committed
choose speaker POC
1 parent e208318 commit 5d13b6a

17 files changed

+281
-9
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
3+
<ion-header>
4+
<ion-toolbar>
5+
<ion-title>Choose Speakers</ion-title>
6+
<ion-buttons slot="end">
7+
<ion-button (click)="closeModal()">
8+
<ion-icon name="close"></ion-icon>
9+
</ion-button>
10+
</ion-buttons>
11+
</ion-toolbar>
12+
</ion-header>
13+
14+
<ion-content>
15+
<div class="choose-speakers-container">
16+
<p>Select the speakers you want to use:</p>
17+
<!-- Add your speaker selection logic here -->
18+
<div class="row">
19+
<div class="col-6" *ngFor="let speaker of speakers">
20+
<img [src]="speaker.image" alt="{{ speaker.manufacturer }} {{ speaker.model }}" class="speaker-image">
21+
<ion-item lines="none" (click)="selectSpeaker(speaker.id)">
22+
<ion-icon slot="end" [name]="'checkmark-circle'" *ngIf="selectedId === speaker.id"></ion-icon>
23+
<ion-label> <h2>{{ speaker.manufacturer }} {{ speaker.model }}</h2></ion-label>
24+
</ion-item>
25+
</div>
26+
</div>
27+
28+
<ion-button expand="full" color="primary" (click)="saveSelection()">
29+
Save Selection
30+
</ion-button>
31+
</div>
32+
</ion-content>

src/app/components/choose-speakers/choose-speakers.component.scss

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2+
import { IonicModule } from '@ionic/angular';
3+
4+
import { ChooseSpeakersComponent } from './choose-speakers.component';
5+
6+
describe('ChooseSpeakersComponent', () => {
7+
let component: ChooseSpeakersComponent;
8+
let fixture: ComponentFixture<ChooseSpeakersComponent>;
9+
10+
beforeEach(waitForAsync(() => {
11+
TestBed.configureTestingModule({
12+
declarations: [ ChooseSpeakersComponent ],
13+
imports: [IonicModule.forRoot()]
14+
}).compileComponents();
15+
16+
fixture = TestBed.createComponent(ChooseSpeakersComponent);
17+
component = fixture.componentInstance;
18+
fixture.detectChanges();
19+
}));
20+
21+
it('should create', () => {
22+
expect(component).toBeTruthy();
23+
});
24+
});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { CommonModule } from '@angular/common';
2+
import { HttpClient } from '@angular/common/http';
3+
import { Component, Input, OnInit } from '@angular/core';
4+
import { FormsModule } from '@angular/forms';
5+
import { IonicModule, ModalController } from '@ionic/angular';
6+
import { first, firstValueFrom } from 'rxjs';
7+
import { Speaker } from 'src/app/model/speaker.model';
8+
import { SnapcastService } from 'src/app/services/snapcast.service';
9+
10+
@Component({
11+
selector: 'app-choose-speakers',
12+
templateUrl: './choose-speakers.component.html',
13+
styleUrls: ['./choose-speakers.component.scss'],
14+
// import ionic module here if needed
15+
imports: [
16+
IonicModule,
17+
FormsModule,
18+
CommonModule
19+
],
20+
standalone: true
21+
})
22+
export class ChooseSpeakersComponent implements OnInit {
23+
24+
@Input() clientId?: string;
25+
26+
selectedId: string | undefined;
27+
speakers: Speaker[] = [];
28+
29+
constructor(
30+
private modalController: ModalController,
31+
private http: HttpClient,
32+
private snapcastService: SnapcastService
33+
) { }
34+
35+
ngOnInit() {
36+
this.loadSpeakerJson();
37+
}
38+
39+
closeModal() {
40+
this.modalController.dismiss(null, null, 'choose-speakers-modal');
41+
}
42+
43+
saveSelection() {
44+
if (this.selectedId) {
45+
console.log('Selected speaker ID:', this.selectedId);
46+
// Here you would typically save the selection to the server or state
47+
this.modalController.dismiss({ selectedId: this.selectedId }, 'save', 'choose-speakers-modal');
48+
} else {
49+
console.error('No speaker selected');
50+
}
51+
}
52+
53+
async loadSpeakerJson() {
54+
// get speaker data as promise
55+
try {
56+
const response = await firstValueFrom(
57+
this.http.get<{ speakers: Speaker[] }>('assets/speakers/speakers-data.json')
58+
);
59+
this.speakers = response.speakers;
60+
console.log('Speakers loaded:', this.speakers);
61+
return this.speakers;
62+
} catch (error) {
63+
console.error('Error loading speakers:', error);
64+
return [];
65+
}
66+
}
67+
68+
async selectSpeaker(speakerId: string) {
69+
// set speaker id as client name
70+
this.selectedId = speakerId;
71+
console.log('Selected speaker:', this.selectedId);
72+
this.snapcastService.setClientName(this.clientId, speakerId).subscribe({
73+
next: (response) => {
74+
console.log(`Successfully set speaker for client ${this.clientId} to ${speakerId}`, response);
75+
},
76+
error: (error) => {
77+
console.error(`Failed to set speaker for client ${this.clientId}`, error);
78+
}
79+
});
80+
}
81+
82+
}

src/app/components/snapcast-group-preview/snapcast-group-preview.component.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
<ion-card *ngIf="group" class="card ion-text-center" color="light" (click)="navToGroupDetails()">
22
<div class="img-container">
3-
<img [src]="'assets/mock/JSE_small.png'" class="img" alt="Placeholder Image">
3+
<ng-container *ngIf="activeSpeaker else defaultImage">
4+
<img [src]="activeSpeaker.image" class="img" alt="{{ activeSpeaker.manufacturer }} {{ activeSpeaker.model }}">
45

6+
</ng-container>
7+
<ng-template #defaultImage>
8+
<img [src]="'assets/mock/JSE_small.png'" class="img" alt="Placeholder Image">
9+
</ng-template>
510
</div>
611
<ng-container *ngIf="activeStream && activeStream.properties.metadata">
712

8-
<img *ngIf="activeStream.properties.metadata.artData as artData" [src]="convertCoverDataBase64(artData.data, artData.extension)" class="cover">
13+
<img *ngIf="activeStream.properties.metadata.artData as artData"
14+
[src]="convertCoverDataBase64(artData.data, artData.extension)" class="cover">
915
<ng-conainer [ngSwitch]="activeStream.status">
1016
<ng-container *ngSwitchCase="'playing'">
1117
<ion-icon class="status-icon" name="play-circle"></ion-icon>

src/app/components/snapcast-group-preview/snapcast-group-preview.component.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component, Input, OnChanges, OnInit } from '@angular/core';
22
import { Router } from '@angular/router';
33
import { Group, Stream } from 'src/app/model/snapcast.model';
4+
import { Speaker } from 'src/app/model/speaker.model';
45

56
@Component({
67
selector: 'app-snapcast-group-preview',
@@ -12,15 +13,18 @@ export class SnapcastGroupPreviewComponent implements OnInit, OnChanges {
1213

1314
@Input() group?: Group;
1415
@Input() streams?: Stream[] | null;
16+
@Input() speakerData?: Speaker[] | null;
1517

1618
activeStream?: Stream;
19+
activeSpeaker?: Speaker;
1720

1821
constructor(
1922
private router: Router
2023
) { }
2124

2225
ngOnInit() {
2326
this.getActiveStream();
27+
this.getActiveSpeaker();
2428
}
2529

2630
ngOnChanges() {
@@ -68,4 +72,19 @@ export class SnapcastGroupPreviewComponent implements OnInit, OnChanges {
6872
return `data:image/${extension};base64,${coverData}`;
6973
}
7074

75+
getActiveSpeaker(): Speaker | undefined {
76+
if (!this.group || !this.speakerData) {
77+
return undefined;
78+
}
79+
// Hacky implementation of speaker selection
80+
this.activeSpeaker = this.speakerData.find(speaker => speaker.id === this.group.clients[0].config.name);
81+
if (!this.activeSpeaker) {
82+
console.warn('No active speaker found for the group:', this.group.id);
83+
return undefined;
84+
}
85+
console.log('Active speaker for group:', this.group.id, this.activeSpeaker);
86+
87+
return this.activeSpeaker;
88+
}
89+
7190
}

src/app/model/speaker.model.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export interface Speaker {
2+
id: string;
3+
image: string;
4+
manufacturer: string;
5+
model: string;
6+
year: number;
7+
}

src/app/pages/clients/client-details/client-details.page.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ <h2>Connection Status</h2>
5757
</ion-range>
5858
</ion-item>
5959

60+
<ion-button expand="full" color="primary" (click)="chooseSpeakers()">
61+
Choose Speakers
62+
</ion-button>
63+
6064
<!-- group selector -->
6165

6266

src/app/pages/clients/client-details/client-details.page.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Component, OnInit } from '@angular/core';
22
import { ActivatedRoute } from '@angular/router';
3+
import { ModalController } from '@ionic/angular';
34
import { Observable } from 'rxjs';
5+
import { ChooseSpeakersComponent } from 'src/app/components/choose-speakers/choose-speakers.component';
46
import { Client, SnapCastServerStatusResponse } from 'src/app/model/snapcast.model';
57
import { SnapcastService } from 'src/app/services/snapcast.service';
68

@@ -21,7 +23,8 @@ export class ClientDetailsPage implements OnInit {
2123

2224
constructor(
2325
private avtivateRoute: ActivatedRoute,
24-
private snapcastService: SnapcastService
26+
private snapcastService: SnapcastService,
27+
private modalController: ModalController
2528
) { }
2629

2730
async ngOnInit() {
@@ -112,6 +115,20 @@ export class ClientDetailsPage implements OnInit {
112115
});
113116
}
114117

118+
chooseSpeakers() {
119+
console.log('Choose speakers for client:', this.client?.id);
120+
// Here you would typically open a modal to select speakers
121+
this.modalController.create({
122+
component: ChooseSpeakersComponent,
123+
id: 'choose-speakers-modal',
124+
componentProps: { clientId: this.client?.id }
125+
}).then(modal => {
126+
modal.present();
127+
}).catch(err => {
128+
console.error('Error opening speaker selection modal:', err);
129+
});
130+
}
131+
115132

116133

117134
}

src/app/pages/dashboard/dashboard.page.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
<ng-container *ngFor="let group of state.server.groups; let i = index">
6262
<ng-template swiperSlide *ngIf="group.clients[0].connected">
6363

64-
<app-snapcast-group-preview [streams]="state.server.streams" [group]="group"></app-snapcast-group-preview>
64+
<app-snapcast-group-preview [streams]="state.server.streams" [group]="group" [speakerData]="speakerData"></app-snapcast-group-preview>
6565
</ng-template>
6666

6767
</ng-container>
@@ -90,8 +90,8 @@
9090
</ng-container>
9191

9292
<!-- <app-snapcast-status></app-snapcast-status> -->
93-
<div class="page-padding-bottom">
94-
</div>
93+
<!-- <div class="page-padding-bottom">
94+
</div> -->
9595

9696
</ion-content>
9797

0 commit comments

Comments
 (0)