feat: Rename to Toju and add translation
Some checks failed
Deploy Web Apps / deploy (push) Successful in 5m52s
Build Android APK / build-android-apk (push) Failing after 23m15s
Queue Release Build / prepare (push) Successful in 1m42s
Queue Release Build / build-linux (push) Failing after 9m33s
Queue Release Build / build-windows (push) Successful in 26m5s
Queue Release Build / finalize (push) Has been skipped

This commit is contained in:
2026-06-05 17:13:03 +02:00
parent 8ecfc9a1fe
commit ee293d7daf
301 changed files with 8247 additions and 2218 deletions

View File

@@ -9,7 +9,8 @@ import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { Subject } from 'rxjs';
import { NotificationAudioService, AppSound } from '../../../../core/services/notification-audio.service';
import { MobileCallSessionService, MobileNotificationsService } from '../../../../infrastructure/mobile';
import { MobileCallSessionService, MobileMediaService, MobileNotificationsService } from '../../../../infrastructure/mobile';
import { initializeAppI18nForTests, provideAppI18nForTests } from '../../../../core/i18n/app-i18n.testing';
import { ViewportService } from '../../../../core/platform';
import {
VoiceActivityService,
@@ -564,9 +565,17 @@ function createServiceContext(options: ServiceContextOptions): ServiceContext {
startActiveCall: vi.fn(async () => undefined),
endActiveCall: vi.fn(async () => undefined)
}
}
},
{
provide: MobileMediaService,
useValue: {
setSpeakerphoneEnabled: vi.fn(async () => undefined)
}
},
...provideAppI18nForTests()
]
});
initializeAppI18nForTests(injector);
return {
audio,

View File

@@ -8,6 +8,7 @@ import {
} from '@angular/core';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { AppI18nService } from '../../../../core/i18n';
import { NotificationAudioService, AppSound } from '../../../../core/services/notification-audio.service';
import { ViewportService } from '../../../../core/platform';
import {
@@ -48,6 +49,7 @@ export class DirectCallService {
private readonly mobileNotifications = inject(MobileNotificationsService);
private readonly mobileCallSession = inject(MobileCallSessionService);
private readonly mobileMedia = inject(MobileMediaService);
private readonly i18n = inject(AppI18nService);
private readonly currentUser = this.store.selectSignal(selectCurrentUser);
private readonly users = this.store.selectSignal(selectAllUsers);
private readonly sessionsSignal = signal<DirectCallSession[]>([]);
@@ -229,7 +231,7 @@ export class DirectCallService {
const peerId = conversation.participants.find((participantId) => participantId !== meId);
if (!peerId) {
throw new Error('Direct message conversation has no recipient to call.');
throw new Error(this.i18n.instant('call.errors.noRecipient'));
}
const peer = this.userForParticipant(peerId) ?? participantToUser(this.participantFromConversation(conversation, peerId));
@@ -992,7 +994,7 @@ export class DirectCallService {
return remoteNames.join(', ');
}
return 'Call in progress';
return this.i18n.instant('call.notifications.inProgress');
}
private uniqueParticipants(participants: DirectMessageParticipant[]): DirectMessageParticipant[] {
@@ -1026,7 +1028,7 @@ export class DirectCallService {
const user = this.currentUser();
if (!user) {
throw new Error('Cannot use calls without a current user.');
throw new Error(this.i18n.instant('call.errors.noCurrentUser'));
}
return user;

View File

@@ -35,12 +35,12 @@
</div>
</div>
<p class="mt-5 text-[11px] font-semibold uppercase tracking-[0.18em] text-primary">Incoming call</p>
<p class="mt-5 text-[11px] font-semibold uppercase tracking-[0.18em] text-primary">{{ 'call.incoming.badge' | translate }}</p>
<h2
id="incoming-call-title"
class="mt-2 text-xl font-semibold text-foreground"
>
{{ callerName() }} is calling
{{ callerCallingLabel() }}
</h2>
<p class="mt-1 text-sm text-muted-foreground">{{ callKindLabel() }}</p>
@@ -54,7 +54,7 @@
name="lucidePhoneOff"
class="h-4 w-4"
/>
Decline
{{ 'call.incoming.decline' | translate }}
</button>
<button
@@ -67,7 +67,7 @@
name="lucidePhone"
class="h-4 w-4"
/>
Answer
{{ 'call.incoming.answer' | translate }}
</button>
</div>
</div>

View File

@@ -9,6 +9,7 @@ import { CommonModule } from '@angular/common';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucidePhone, lucidePhoneOff } from '@ng-icons/lucide';
import { AppI18nService, APP_TRANSLATE_IMPORTS } from '../../../../core/i18n';
import { ModalBackdropComponent, UserAvatarComponent } from '../../../../shared';
import { selectCurrentUser } from '../../../../store/users/users.selectors';
import { User } from '../../../../shared-kernel';
@@ -22,7 +23,8 @@ import { DirectCallSession, participantToUser } from '../../domain/models/direct
CommonModule,
NgIcon,
UserAvatarComponent,
ModalBackdropComponent
ModalBackdropComponent,
...APP_TRANSLATE_IMPORTS
],
viewProviders: [
provideIcons({
@@ -34,6 +36,7 @@ import { DirectCallSession, participantToUser } from '../../domain/models/direct
})
export class IncomingCallModalComponent {
readonly calls = inject(DirectCallService);
private readonly i18n = inject(AppI18nService);
readonly currentUser = inject(Store).selectSignal(selectCurrentUser);
readonly session = this.calls.incomingCall;
readonly answering = signal(false);
@@ -50,11 +53,16 @@ export class IncomingCallModalComponent {
return (callerId ? this.calls.userForParticipant(callerId) : null)
?? (participant ? participantToUser(participant) : null);
});
readonly callerName = computed(() => this.caller()?.displayName || 'Someone');
readonly callerName = computed(() => this.caller()?.displayName || this.i18n.instant('call.incoming.someone'));
readonly callerCallingLabel = computed(() =>
this.i18n.instant('call.incoming.callerCalling', { name: this.callerName() })
);
readonly callKindLabel = computed(() => {
const participantCount = this.session()?.participantIds.length ?? 0;
return participantCount > 2 ? `${participantCount} person call` : 'Direct call';
return participantCount > 2
? this.i18n.instant('call.incoming.groupCall', { count: participantCount })
: this.i18n.instant('call.incoming.directCall');
});
@HostListener('document:keydown.escape')