Skip to content

Commit 82d4105

Browse files
authored
Merge pull request #10 from byrdsandbytes/feature/sc-2032-allow-user-to-name-clients
Feature/sc 2032 allow user to name clients
2 parents 9bcc4e6 + f0b3b98 commit 82d4105

File tree

11 files changed

+212
-8
lines changed

11 files changed

+212
-8
lines changed

src/app/app-routing.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ const routes: Routes = [
1919
loadChildren: () => import('./pages/server-status/server-status.module').then( m => m.ServerStatusPageModule)
2020
},
2121
// {
22+
// path: 'client-details',
23+
// loadChildren: () => import('./pages/client-details/client-details.module').then( m => m.ClientDetailsPageModule)
24+
// },
25+
// {
2226
// path: 'settings',
2327
// loadChildren: () => import('./pages/settings/settings.module').then( m => m.SettingsPageModule)
2428
// },
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { NgModule } from '@angular/core';
2+
import { Routes, RouterModule } from '@angular/router';
3+
4+
import { ClientDetailsPage } from './client-details.page';
5+
6+
const routes: Routes = [
7+
{
8+
path: '',
9+
component: ClientDetailsPage
10+
}
11+
];
12+
13+
@NgModule({
14+
imports: [RouterModule.forChild(routes)],
15+
exports: [RouterModule],
16+
})
17+
export class ClientDetailsPageRoutingModule {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NgModule } from '@angular/core';
2+
import { CommonModule } from '@angular/common';
3+
import { FormsModule } from '@angular/forms';
4+
5+
import { IonicModule } from '@ionic/angular';
6+
7+
import { ClientDetailsPageRoutingModule } from './client-details-routing.module';
8+
9+
import { ClientDetailsPage } from './client-details.page';
10+
11+
@NgModule({
12+
imports: [
13+
CommonModule,
14+
FormsModule,
15+
IonicModule,
16+
ClientDetailsPageRoutingModule
17+
],
18+
declarations: [ClientDetailsPage]
19+
})
20+
export class ClientDetailsPageModule {}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<ion-header [translucent]="true">
2+
<ion-toolbar>
3+
<ion-title>client-details</ion-title>
4+
</ion-toolbar>
5+
</ion-header>
6+
7+
<ion-content [fullscreen]="true">
8+
<ion-header collapse="condense">
9+
<ion-toolbar>
10+
<ion-title size="large">client-details</ion-title>
11+
</ion-toolbar>
12+
</ion-header>
13+
14+
<ion-list *ngIf="serverState | async as state">
15+
<ion-item>
16+
<ion-label>
17+
<h2>Client ID: {{ id }}</h2>
18+
</ion-label>
19+
</ion-item>
20+
<ion-item >
21+
<ion-input type="text" placeholder="Enter client name" [(ngModel)]="client.config.name" (ngModelChange)="setClientName()"></ion-input>
22+
</ion-item>
23+
24+
<ng-container *ngIf="state.server.groups">
25+
<ng-container *ngFor="let group of state.server.groups">
26+
<ng-container *ngFor="let client of group.clients">
27+
<ion-item *ngIf="client.id === id">
28+
<ion-label>
29+
<h2>{{ client.id }}</h2>
30+
<p>Group: {{ group.name || group.id }}</p>
31+
<p>Volume: {{ client.config.volume.percent || 'N/A' }}%</p>
32+
<p>Last Seen: {{ client.lastSeen.sec * 1000 | date }}</p>
33+
<p>Connected: {{ client.connected }}</p>
34+
</ion-label>
35+
</ion-item>
36+
</ng-container>
37+
</ng-container>
38+
</ng-container>
39+
</ion-list>
40+
41+
<ion-accordion-group *ngIf="client">
42+
<ion-accordion value="{{ client.id }}">
43+
<ion-item slot="header">
44+
<ion-label>
45+
<h2>{{ client.id }}</h2>
46+
<p>{{ client.connected}}</p>
47+
</ion-label>
48+
</ion-item>
49+
<ion-item slot="content" lines="none" color="dark">
50+
<pre>{{ client| json }}</pre>
51+
</ion-item>
52+
</ion-accordion>
53+
</ion-accordion-group>
54+
</ion-content>

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

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { ClientDetailsPage } from './client-details.page';
3+
4+
describe('ClientDetailsPage', () => {
5+
let component: ClientDetailsPage;
6+
let fixture: ComponentFixture<ClientDetailsPage>;
7+
8+
beforeEach(() => {
9+
fixture = TestBed.createComponent(ClientDetailsPage);
10+
component = fixture.componentInstance;
11+
fixture.detectChanges();
12+
});
13+
14+
it('should create', () => {
15+
expect(component).toBeTruthy();
16+
});
17+
});
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { ActivatedRoute } from '@angular/router';
3+
import { Observable } from 'rxjs';
4+
import { Client, SnapCastServerStatusResponse } from 'src/app/model/snapcast.model';
5+
import { SnapcastService } from 'src/app/services/snapcast.service';
6+
7+
@Component({
8+
selector: 'app-client-details',
9+
templateUrl: './client-details.page.html',
10+
styleUrls: ['./client-details.page.scss'],
11+
standalone: false
12+
})
13+
export class ClientDetailsPage implements OnInit {
14+
15+
16+
id?: string;
17+
18+
serverState?: Observable<SnapCastServerStatusResponse>;
19+
client?: Client;
20+
21+
22+
constructor(
23+
private avtivateRoute: ActivatedRoute,
24+
private snapcastService: SnapcastService
25+
) { }
26+
27+
async ngOnInit() {
28+
this.serverState = this.snapcastService.state$;
29+
this.id = this.avtivateRoute.snapshot.paramMap.get('id') || undefined;
30+
if (!this.id) {
31+
console.error('ClientDetailsPage: No ID found in route parameters');
32+
return;
33+
}
34+
console.log('ClientDetailsPage: ID from route parameters:', this.id);
35+
this.subscribeToClient();
36+
}
37+
38+
subscribeToClient() {
39+
if (!this.id) {
40+
console.error('ClientDetailsPage: No ID available to subscribe to client');
41+
return;
42+
}
43+
this.serverState.subscribe((state) => {
44+
this.client = state.server.groups.flatMap(group => group.clients).find(client => client.id === this.id);
45+
if (!this.client) {
46+
console.error(`ClientDetailsPage: Client with ID ${this.id} not found in server state`);
47+
} else {
48+
console.log('ClientDetailsPage: Found client:', this.client);
49+
}
50+
});
51+
}
52+
53+
setClientName() {
54+
if (!this.client || !this.client.id) {
55+
console.error('ClientDetailsPage: No client or client ID available to set name');
56+
return;
57+
}
58+
this.snapcastService.setClientName(this.client.id, this.client.config.name).subscribe({
59+
next: () => {
60+
console.log(`ClientDetailsPage: Successfully set name for client ${this.client.id} to ${name}`);
61+
},
62+
error: (err) => {
63+
console.error(`ClientDetailsPage: Failed to set name for client ${this.client.id}`, err);
64+
}
65+
});
66+
}
67+
68+
69+
70+
}

src/app/pages/devices/device-details/device-details.page.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<ion-select slot="end" interface="action-sheet" [(ngModel)]="group.clients" multiple="true"
4242
placeholder="Select Clients">
4343
<ion-select-option *ngFor="let client of group.clients" [value]="client">
44-
{{ client.id }}
44+
{{ client.config.name || client.id }}
4545
</ion-select-option>
4646
</ion-select>
4747
</ion-item>

src/app/pages/devices/devices.page.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ <h2>{{ group.name || group.id }}</h2>
2525
<ion-list-header>
2626
<ion-label>Clients</ion-label>
2727
</ion-list-header>
28-
<ng-container *ngFor="let group of state.server.groups">
28+
<ng-container *ngFor="let group of state.server.groups">
2929
<ng-container *ngFor="let client of group.clients">
30-
<ion-item [routerLink]="['/tabs/devices', client.id]">
30+
<ion-item [routerLink]="['/tabs/clients', client.id]">
3131
<ion-label>
32-
<h2>{{ client.id }}</h2>
32+
<h2> {{ client.config.name || client.id }}
33+
</h2>
3334
<p>Group: {{ group.name || group.id }}</p>
3435
<p>Volume: {{ client.config.volume.percent || 'N/A' }}%</p>
3536
<p>Last Seen: {{ client.lastSeen.sec *1000 | date }}</p>
3637
<p>Connected: {{ client.connected }}</p>
37-
3838
</ion-label>
3939
</ion-item>
4040
</ng-container>
4141

42-
</ng-container>
43-
42+
</ng-container>
43+
4444
</ion-list>
4545
</div>
4646
<ng-template #noState>

src/app/services/snapcast.service.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,16 @@ export class SnapcastService implements OnDestroy {
368368

369369
}
370370

371+
setClientName(clientId: string, name: string): Observable<void> {
372+
return this.rpc('Client.SetName', { id: clientId, name }).pipe(
373+
map((): void => void 0),
374+
catchError(err => {
375+
console.error(`SnapcastService: Failed to set name for client ${clientId}`, err);
376+
return throwError(() => err);
377+
})
378+
);
379+
}
380+
371381
// TODO ... Implement other action methods like.
372382
// They just need to call `this.rpc` with the correct parameters.
373383

@@ -376,7 +386,7 @@ export class SnapcastService implements OnDestroy {
376386
return this.state$.pipe(map(state => state?.server?.groups.flatMap(g => g.clients).find(c => c.id === clientId)));
377387
}
378388

379-
// TODO: ... other get... methods ...
389+
// TODO: ... other get methods ...
380390

381391

382392

0 commit comments

Comments
 (0)