Skip to content

Commit 7d36192

Browse files
committed
fix: placeholder avatar not being built
1 parent f061df5 commit 7d36192

File tree

7 files changed

+97
-52
lines changed

7 files changed

+97
-52
lines changed

Code/skyrim_ui/angular.json

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,22 @@
2828
"optimization": false,
2929
"namedChunks": true,
3030
"stylePreprocessorOptions": {
31-
"includePaths": [
32-
"src",
33-
"src/styles"
34-
]
31+
"includePaths": ["src", "src/styles"]
3532
},
3633
"tsConfig": "tsconfig.app.json",
3734
"assets": [
3835
"src/favicon.ico",
3936
"src/assets/sounds/",
40-
"src/assets/i18n/"
41-
],
42-
"styles": [
43-
"src/styles.scss"
37+
"src/assets/i18n/",
38+
{
39+
"glob": "avatar-placeholder.png",
40+
"input": "src/assets/images/group",
41+
"output": "assets/images/group"
42+
}
4443
],
44+
"styles": ["src/styles.scss"],
4545
"scripts": [],
46-
"allowedCommonJsDependencies": [
47-
"flat",
48-
"events"
49-
]
46+
"allowedCommonJsDependencies": ["flat", "events"]
5047
},
5148
"configurations": {
5249
"production": {
@@ -138,9 +135,7 @@
138135
"tsconfig.spec.json",
139136
"e2e/tsconfig.json"
140137
],
141-
"exclude": [
142-
"**/node_modules/**"
143-
]
138+
"exclude": ["**/node_modules/**"]
144139
}
145140
},
146141
"e2e": {

Code/skyrim_ui/src/app/components/group/group.component.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ export class GroupComponent implements OnInit, OnDestroy {
6464
return [];
6565
}
6666
return members
67-
.map(member => ({ ...member, isOwner: member.id === group.owner }))
67+
.map(member => ({
68+
...member,
69+
isOwner: member.id === group.owner,
70+
avatar:
71+
member.avatar && member.avatar.length > 0
72+
? member.avatar
73+
: this.defaultAvatar,
74+
}))
6875
.sort((a, b) =>
6976
(group.owner === a.id) === (group.owner === b.id)
7077
? 0

Code/skyrim_ui/src/app/components/party-menu/party-menu.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ <h3 class="panel-title">
77
</p>
88
<div class="profile-picture-preview" (click)="resetUploadError()">
99
<img
10-
[src]="(profilePreview$ | async) || defaultAvatar"
10+
[src]="profilePreviewSafeUrl$ | async"
1111
[alt]="'Profile picture preview'"
1212
draggable="false"
1313
/>

Code/skyrim_ui/src/app/components/party-menu/party-menu.component.ts

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import { ChangeDetectionStrategy, Component, NgZone, OnDestroy } from '@angular/core';
2-
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
1+
import {
2+
ChangeDetectionStrategy,
3+
Component,
4+
NgZone,
5+
OnDestroy,
6+
} from '@angular/core';
7+
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
8+
import { BehaviorSubject, Observable, Subscription, combineLatest } from 'rxjs';
39
import { filter, map, pluck, startWith } from 'rxjs/operators';
410
import { Player } from 'src/app/models/player';
511
import { ClientService } from 'src/app/services/client.service';
@@ -15,14 +21,26 @@ import { PlayerListService } from 'src/app/services/player-list.service';
1521
})
1622
export class PartyMenuComponent implements OnDestroy {
1723
isLoading$ = this.loadingService.getLoading();
18-
members$ = this.groupService.selectMembers();
24+
members$ = combineLatest([
25+
this.groupService.selectMembers(),
26+
this.clientService.localPlayerIdChange,
27+
]).pipe(
28+
map(([members, localId]) =>
29+
members.filter(member => member.id !== localId),
30+
),
31+
);
1932
memberCount$ = this.groupService.selectMembersLength(true);
2033
group$ = this.groupService.group.asObservable();
2134
isLaunchPartyDisabled$: Observable<boolean>;
2235
invitations$: Observable<Player[]>;
2336
isPartyLeader$: Observable<boolean>;
24-
readonly defaultAvatar = 'assets/images/group/avatar-placeholder.png';
25-
profilePreview$ = new BehaviorSubject<string | null>(null);
37+
readonly defaultAvatarPath = 'assets/images/group/avatar-placeholder.png';
38+
readonly defaultAvatar: SafeUrl;
39+
private readonly profilePreviewSubject = new BehaviorSubject<string | null>(
40+
null,
41+
);
42+
profilePreview$ = this.profilePreviewSubject.asObservable();
43+
profilePreviewSafeUrl$: Observable<SafeUrl>;
2644
uploadError$ = new BehaviorSubject<string | null>(null);
2745
private readonly subscriptions = new Subscription();
2846
private readonly targetImageSize = 128;
@@ -35,7 +53,19 @@ export class PartyMenuComponent implements OnDestroy {
3553
private readonly playerListService: PlayerListService,
3654
private readonly clientService: ClientService,
3755
private readonly zone: NgZone,
56+
private readonly sanitizer: DomSanitizer,
3857
) {
58+
this.defaultAvatar = this.sanitizer.bypassSecurityTrustUrl(
59+
this.defaultAvatarPath,
60+
);
61+
this.profilePreviewSafeUrl$ = this.profilePreviewSubject.pipe(
62+
map(preview =>
63+
preview
64+
? this.sanitizer.bypassSecurityTrustUrl(preview)
65+
: this.defaultAvatar,
66+
),
67+
);
68+
3969
this.invitations$ = this.playerListService.playerList.asObservable().pipe(
4070
filter(playerlist => !!playerlist),
4171
pluck('players'),
@@ -63,23 +93,23 @@ export class PartyMenuComponent implements OnDestroy {
6393

6494
const localPlayer = list.players.find(player => player.id === localId);
6595
if (localPlayer) {
66-
this.profilePreview$.next(localPlayer.avatar || null);
96+
this.profilePreviewSubject.next(localPlayer.avatar || null);
6797
}
6898
}),
6999
);
70100

71101
this.subscriptions.add(
72102
this.clientService.avatarChange.subscribe(player => {
73103
if (player.id === this.clientService.localPlayerId) {
74-
this.profilePreview$.next(player.avatar || null);
104+
this.profilePreviewSubject.next(player.avatar || null);
75105
}
76106
}),
77107
);
78108

79109
this.subscriptions.add(
80110
this.clientService.connectionStateChange.subscribe(isConnected => {
81111
if (!isConnected) {
82-
this.profilePreview$.next(null);
112+
this.profilePreviewSubject.next(null);
83113
}
84114
}),
85115
);
@@ -125,29 +155,20 @@ export class PartyMenuComponent implements OnDestroy {
125155
const allowedExtensions = ['png', 'jpg', 'jpeg'];
126156

127157
if (file.size > this.maxUploadBytes) {
128-
this.uploadError$.next(
129-
'COMPONENT.PARTY_MENU.PROFILE_PICTURE.ERROR_SIZE',
130-
);
158+
this.uploadError$.next('COMPONENT.PARTY_MENU.PROFILE_PICTURE.ERROR_SIZE');
131159
input.value = '';
132160
return;
133161
}
134162

135-
if (
136-
file.type &&
137-
!allowedMimeTypes.includes(file.type.toLowerCase())
138-
) {
139-
this.uploadError$.next(
140-
'COMPONENT.PARTY_MENU.PROFILE_PICTURE.ERROR_TYPE',
141-
);
163+
if (file.type && !allowedMimeTypes.includes(file.type.toLowerCase())) {
164+
this.uploadError$.next('COMPONENT.PARTY_MENU.PROFILE_PICTURE.ERROR_TYPE');
142165
input.value = '';
143166
return;
144167
}
145168

146169
const extension = file.name.split('.').pop()?.toLowerCase();
147170
if (!file.type && extension && !allowedExtensions.includes(extension)) {
148-
this.uploadError$.next(
149-
'COMPONENT.PARTY_MENU.PROFILE_PICTURE.ERROR_TYPE',
150-
);
171+
this.uploadError$.next('COMPONENT.PARTY_MENU.PROFILE_PICTURE.ERROR_TYPE');
151172
input.value = '';
152173
return;
153174
}
@@ -174,7 +195,7 @@ export class PartyMenuComponent implements OnDestroy {
174195
}
175196

176197
this.uploadError$.next(null);
177-
this.profilePreview$.next(normalized);
198+
this.profilePreviewSubject.next(normalized);
178199
this.clientService.setProfilePicture(normalized);
179200
})
180201
.catch(() => {
@@ -197,7 +218,7 @@ export class PartyMenuComponent implements OnDestroy {
197218

198219
public clearProfilePicture() {
199220
this.uploadError$.next(null);
200-
this.profilePreview$.next(null);
221+
this.profilePreviewSubject.next(null);
201222
this.clientService.setProfilePicture('');
202223
}
203224

Code/skyrim_ui/src/app/components/party-pins/party-pins.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ export class PartyPinsComponent implements OnDestroy {
3434
return {
3535
...pin,
3636
name: resolvedName,
37-
avatar: resolvedAvatar,
37+
avatar:
38+
resolvedAvatar && resolvedAvatar.length > 0
39+
? resolvedAvatar
40+
: this.defaultAvatar,
3841
};
3942
});
4043
});

Code/skyrim_ui/src/app/models/player.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export interface Friend {
22
id: number;
33
name: string;
4-
avatar: string;
4+
avatar?: string;
55
online: boolean;
66
}
77

@@ -13,7 +13,7 @@ export class Player implements Friend {
1313
/** Username. */
1414
name: string;
1515

16-
avatar: string;
16+
avatar?: string;
1717

1818
/** Current health. */
1919
health?: number;
@@ -63,7 +63,9 @@ export class Player implements Friend {
6363
) {
6464
this.id = options.id || 0;
6565
this.name = options.name || '';
66-
this.avatar = options.avatar || '';
66+
if (options.avatar) {
67+
this.avatar = options.avatar;
68+
}
6769
this.hasInvitedLocalPlayer = options.hasInvitedLocalPlayer || false;
6870
this.cellName = options.cellName || 'vide';
6971

Code/skyrim_ui/src/app/services/player-list.service.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { PopupNotificationService } from './popup-notification.service';
1414
})
1515
export class PlayerListService implements OnDestroy {
1616
public playerList = new BehaviorSubject<PlayerList | undefined>(undefined);
17+
private readonly defaultAvatar = 'assets/images/group/avatar-placeholder.png';
1718

1819
private debugSubscription: Subscription;
1920
private connectionSubscription: Subscription;
@@ -100,9 +101,20 @@ export class PlayerListService implements OnDestroy {
100101
existing.cellName = player.cellName;
101102
existing.connected = player.connected;
102103
existing.online = player.online;
103-
existing.avatar = player.avatar;
104+
existing.avatar =
105+
player.avatar && player.avatar.length > 0
106+
? player.avatar
107+
: existing.avatar || this.defaultAvatar;
104108
} else {
105-
playerList.players.push(player);
109+
playerList.players.push(
110+
new Player({
111+
...player,
112+
avatar:
113+
player.avatar && player.avatar.length > 0
114+
? player.avatar
115+
: this.defaultAvatar,
116+
}),
117+
);
106118
}
107119
this.playerList.next(playerList);
108120
}
@@ -254,11 +266,10 @@ export class PlayerListService implements OnDestroy {
254266
this.ensureLocalPlayerEntry();
255267
});
256268

257-
this.localPlayerSubscription = this.clientService.localPlayerIdChange.subscribe(
258-
() => {
269+
this.localPlayerSubscription =
270+
this.clientService.localPlayerIdChange.subscribe(() => {
259271
this.ensureLocalPlayerEntry();
260-
},
261-
);
272+
});
262273
}
263274

264275
private ensureLocalPlayerEntry() {
@@ -283,10 +294,16 @@ export class PlayerListService implements OnDestroy {
283294
online: true,
284295
cellName: '',
285296
isLoaded: true,
297+
avatar: this.defaultAvatar,
286298
});
287299
playerList.players.push(existing);
288-
} else if (displayName && displayName.length > 0) {
289-
existing.name = displayName;
300+
} else {
301+
if (displayName && displayName.length > 0) {
302+
existing.name = displayName;
303+
}
304+
if (!existing.avatar) {
305+
existing.avatar = this.defaultAvatar;
306+
}
290307
}
291308

292309
existing.connected = true;

0 commit comments

Comments
 (0)