Update lot features

This commit is contained in:
2026-05-28 16:29:23 +07:00
parent 6272ece15d
commit 1110e5a42d
81 changed files with 4306 additions and 29813 deletions
@@ -47,8 +47,10 @@ class _CallScreenState extends State<CallScreen>
vsync: this,
duration: const Duration(milliseconds: 1200),
)..repeat(reverse: true);
late final Animation<double> _pulseScale = Tween(begin: 0.95, end: 1.08)
.animate(CurvedAnimation(parent: _pulseCtrl, curve: Curves.easeInOut));
late final Animation<double> _pulseScale = Tween(
begin: 0.95,
end: 1.08,
).animate(CurvedAnimation(parent: _pulseCtrl, curve: Curves.easeInOut));
@override
void initState() {
@@ -85,7 +87,7 @@ class _CallScreenState extends State<CallScreen>
);
_startAcceptedPolling();
_ringTimeout?.cancel();
_ringTimeout = Timer(const Duration(seconds: 45), () {
_ringTimeout = Timer(const Duration(seconds: 35), () {
if (!mounted || _phase == _CallPhase.connected) return;
_failCall('Panggilan tidak dijawab.');
});
@@ -93,12 +95,12 @@ class _CallScreenState extends State<CallScreen>
void _startAcceptedPolling() {
_acceptedPoll?.cancel();
_acceptedPoll = Timer.periodic(const Duration(seconds: 2), (_) async {
_acceptedPoll = Timer.periodic(const Duration(seconds: 1), (_) async {
if (!mounted || _activeChannel == null) return;
final state = await runFriendly<Map<String, dynamic>>(
() => sl<CallService>()
.getCallState(_activeChannel)
.timeout(const Duration(seconds: 3)),
.timeout(const Duration(seconds: 2)),
onError: (_) {},
fallback: 'Polling panggilan gagal.',
);
@@ -114,9 +116,9 @@ class _CallScreenState extends State<CallScreen>
}
final accepted = await runFriendly<Map<String, dynamic>>(
() => sl<CallService>()
.getAcceptedCall()
.timeout(const Duration(seconds: 3)),
() => sl<CallService>().getAcceptedCall().timeout(
const Duration(seconds: 2),
),
onError: (_) {},
fallback: 'Polling panggilan diterima gagal.',
);
@@ -283,6 +285,7 @@ class IncomingCallScreen extends StatefulWidget {
final int? callerId;
final String? channelName;
final String? agoraToken;
final String? agoraAppId;
const IncomingCallScreen({
super.key,
@@ -290,6 +293,7 @@ class IncomingCallScreen extends StatefulWidget {
this.callerId,
this.channelName,
this.agoraToken,
this.agoraAppId,
});
@override
@@ -360,12 +364,12 @@ class _IncomingCallScreenState extends State<IncomingCallScreen> {
void _startIncomingStatePolling() {
_statePoll?.cancel();
_statePoll = Timer.periodic(const Duration(seconds: 2), (_) async {
_statePoll = Timer.periodic(const Duration(seconds: 1), (_) async {
if (!mounted || _joinedChannel == null) return;
final state = await runFriendly<Map<String, dynamic>>(
() => sl<CallService>()
.getCallState(_joinedChannel)
.timeout(const Duration(seconds: 3)),
.timeout(const Duration(seconds: 2)),
onError: (_) {},
fallback: 'Polling panggilan masuk gagal.',
);
@@ -389,8 +393,10 @@ class _IncomingCallScreenState extends State<IncomingCallScreen> {
setState(() => _responding = true);
sl<TtsService>().speak('Panggilan ditolak.');
sl<CallService>().setRemoteUserOfflineCallback(null);
await sl<CallService>()
.endCall(widget.callerId, channelName: widget.channelName);
await sl<CallService>().endCall(
widget.callerId,
channelName: widget.channelName,
);
await sl<CallService>().clearPendingCall();
await sl<CallService>().leave();
if (mounted) context.go(await _homeRoute());
@@ -401,16 +407,19 @@ class _IncomingCallScreenState extends State<IncomingCallScreen> {
unawaited(_finishIncomingRemoteEnded());
});
if (widget.callerId != null) {
final tokenData =
await sl<CallService>().requestToken(receiverId: widget.callerId!);
final tokenData = await sl<CallService>().requestToken(
receiverId: widget.callerId!,
);
final channelName = tokenData?['channelName']?.toString();
final token = tokenData?['token']?.toString();
final appId = tokenData?['appId']?.toString();
final uid = (tokenData?['uid'] as num?)?.toInt() ?? 0;
if (channelName != null && channelName.isNotEmpty) {
_joinedChannel = channelName;
return sl<CallService>().joinChannel(
channelName: channelName,
token: token,
appId: appId,
uid: uid,
);
}
@@ -422,6 +431,7 @@ class _IncomingCallScreenState extends State<IncomingCallScreen> {
return sl<CallService>().joinChannel(
channelName: fallbackChannel,
token: widget.agoraToken,
appId: widget.agoraAppId,
);
}
@@ -429,8 +439,10 @@ class _IncomingCallScreenState extends State<IncomingCallScreen> {
_callTimer?.cancel();
_statePoll?.cancel();
sl<CallService>().setRemoteUserOfflineCallback(null);
await sl<CallService>()
.endCall(widget.callerId, channelName: _joinedChannel);
await sl<CallService>().endCall(
widget.callerId,
channelName: _joinedChannel,
);
await sl<CallService>().leave();
sl<TtsService>().speak('Panggilan diakhiri.');
if (mounted) context.go(await _homeRoute());
@@ -713,8 +725,10 @@ class _EndCallButton extends StatelessWidget {
Container(
width: 74,
height: 74,
decoration:
const BoxDecoration(shape: BoxShape.circle, color: _kRed),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: _kRed,
),
child: const Icon(Icons.call_end, color: Colors.white, size: 32),
),
const SizedBox(height: 6),