feat(app): 1:1 voice and video calls
End-to-end encrypted calls between two contacts over WebRTC. Call signalling (offer, answer, hang-up) travels as ordinary Signal-encrypted messages through the relay; media is DTLS-SRTP, peer to peer when possible and through the operator's TURN server otherwise. - Non-trickle ICE (candidates gathered for up to 3 s), 45 s ring timeout, busy handling, and a call log entry in the conversation. - The system call UI rings even when the app is closed: CallKit from a PushKit VoIP push on iOS, a full-screen incoming call from an FCM wake-up on Android. The wake-up carries no caller; the app learns who is calling from the queued offer once it is unlocked. - New permissions: camera for video, audio routing and Bluetooth headsets, network state; iOS background modes audio and voip. Push on Android: a fresh install now picks UnifiedPush when a distributor is installed and FCM otherwise, instead of leaving wake-ups off. Without a wake-up Android puts the app to sleep and messages wait until it is opened. Users can switch at any time in Settings.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sepot/features/calls/call_screen.dart';
|
||||
import 'package:sepot/l10n/generated/app_localizations.dart';
|
||||
import 'package:sepot/models/call_log.dart';
|
||||
|
||||
/// Ikona a text záznamu hovoru — sdílí chat i seznam chatů, ať se
|
||||
/// formulace nerozejdou.
|
||||
({IconData icon, String text, bool alert}) callLogLabel(
|
||||
AppLocalizations l10n, CallLog log) {
|
||||
final icon = log.video ? Icons.videocam_rounded : Icons.call_rounded;
|
||||
return switch (log.outcome) {
|
||||
CallOutcome.completed => (
|
||||
icon: icon,
|
||||
text: log.video
|
||||
? l10n.callLogVideo(formatCallDuration(log.durationSeconds))
|
||||
: l10n.callLogVoice(formatCallDuration(log.durationSeconds)),
|
||||
alert: false,
|
||||
),
|
||||
CallOutcome.missed => (
|
||||
icon: Icons.phone_missed_rounded,
|
||||
text: l10n.callLogMissed,
|
||||
alert: true,
|
||||
),
|
||||
CallOutcome.unanswered => (
|
||||
icon: icon,
|
||||
text: l10n.callLogUnanswered,
|
||||
alert: false,
|
||||
),
|
||||
CallOutcome.rejected => (
|
||||
icon: Icons.call_end_rounded,
|
||||
text: l10n.callLogRejected,
|
||||
alert: false,
|
||||
),
|
||||
CallOutcome.busy => (icon: icon, text: l10n.callLogBusy, alert: false),
|
||||
CallOutcome.failed => (
|
||||
icon: Icons.error_outline_rounded,
|
||||
text: l10n.callLogFailed,
|
||||
alert: true,
|
||||
),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user