feat: Android APP V1 - Experimental Alpha

This commit is contained in:
2026-06-05 07:40:25 +02:00
parent bf4e6891d1
commit 9a1305f976
179 changed files with 8031 additions and 120 deletions

View File

@@ -27,6 +27,24 @@
/>
</button>
@if (showSpeakerphoneButton()) {
<button
type="button"
class="grid h-12 w-12 place-items-center rounded-full bg-secondary text-foreground transition-colors hover:bg-secondary/80 disabled:opacity-45"
[class.ring-2]="speakerphoneEnabled()"
[class.ring-primary]="speakerphoneEnabled()"
[disabled]="!connected()"
(click)="speakerphoneToggled.emit()"
[attr.aria-label]="speakerphoneEnabled() ? 'Use earpiece' : 'Use speakerphone'"
[title]="speakerphoneEnabled() ? 'Use earpiece' : 'Use speakerphone'"
>
<ng-icon
name="lucideVolume2"
class="h-5 w-5"
/>
</button>
}
<button
type="button"
class="grid h-12 w-12 place-items-center rounded-full bg-secondary text-foreground transition-colors hover:bg-secondary/80 disabled:opacity-45"

View File

@@ -12,7 +12,8 @@ import {
lucidePhone,
lucidePhoneOff,
lucideVideo,
lucideVideoOff
lucideVideoOff,
lucideVolume2
} from '@ng-icons/lucide';
@Component({
@@ -28,7 +29,8 @@ import {
lucidePhone,
lucidePhoneOff,
lucideVideo,
lucideVideoOff
lucideVideoOff,
lucideVolume2
})
],
templateUrl: './private-call-controls.component.html'
@@ -38,10 +40,13 @@ export class PrivateCallControlsComponent {
readonly muted = input.required<boolean>();
readonly cameraEnabled = input.required<boolean>();
readonly screenSharing = input.required<boolean>();
readonly showSpeakerphoneButton = input(false);
readonly speakerphoneEnabled = input(false);
readonly joinRequested = output<void>();
readonly muteToggled = output<void>();
readonly cameraToggled = output<void>();
readonly screenShareToggled = output<void>();
readonly leaveRequested = output<void>();
readonly joinRequested = output();
readonly muteToggled = output();
readonly cameraToggled = output();
readonly screenShareToggled = output();
readonly speakerphoneToggled = output();
readonly leaveRequested = output();
}

View File

@@ -198,10 +198,13 @@
[muted]="isMuted()"
[cameraEnabled]="isCameraEnabled()"
[screenSharing]="isScreenSharing()"
[showSpeakerphoneButton]="showSpeakerphoneButton()"
[speakerphoneEnabled]="speakerphoneEnabled()"
(joinRequested)="join()"
(muteToggled)="toggleMute()"
(cameraToggled)="toggleCamera()"
(screenShareToggled)="toggleScreenShare()"
(speakerphoneToggled)="toggleSpeakerphone()"
(leaveRequested)="leave()"
/>
</div>

View File

@@ -43,6 +43,7 @@ import {
import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../domains/voice-session';
import { ScreenShareQualityDialogComponent } from '../../shared';
import { ViewportService } from '../../core/platform';
import { MobileMediaService, MobilePlatformService } from '../../infrastructure/mobile';
import { selectAllUsers, selectCurrentUser } from '../../store/users/users.selectors';
import { UsersActions } from '../../store/users/users.actions';
import { User } from '../../shared-kernel';
@@ -87,11 +88,15 @@ export class PrivateCallComponent {
private readonly playback = inject(VoicePlaybackService);
private readonly screenShare = inject(ScreenShareFacade);
private readonly viewport = inject(ViewportService);
private readonly mobilePlatform = inject(MobilePlatformService);
private readonly mobileMedia = inject(MobileMediaService);
private chatResizing = false;
readonly allUsers = this.store.selectSignal(selectAllUsers);
readonly currentUser = this.store.selectSignal(selectCurrentUser);
readonly isMobile = this.viewport.isMobile;
readonly showSpeakerphoneButton = computed(() => this.mobilePlatform.isNativeMobile());
readonly speakerphoneEnabled = signal(true);
readonly callIdInput = input<string | null>(null);
readonly overlayMode = input(false);
readonly routeCallId = toSignal(this.route.paramMap.pipe(map((params) => params.get('callId'))), {
@@ -342,6 +347,13 @@ export class PrivateCallComponent {
this.broadcastLocalVoiceState();
}
async toggleSpeakerphone(): Promise<void> {
const nextEnabled = !this.speakerphoneEnabled();
this.speakerphoneEnabled.set(nextEnabled);
await this.mobileMedia.setSpeakerphoneEnabled(nextEnabled);
}
toggleDeafen(): void {
const nextDeafened = !this.isDeafened();