390 lines
16 KiB
Dart
390 lines
16 KiB
Dart
import 'dart:typed_data';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:dialer/services/obfuscate_service.dart';
|
|
import 'package:dialer/widgets/username_color_generator.dart';
|
|
|
|
class CallPage extends StatefulWidget {
|
|
final String displayName;
|
|
final Uint8List? thumbnail;
|
|
|
|
const CallPage({super.key, required this.displayName, this.thumbnail});
|
|
|
|
@override
|
|
_CallPageState createState() => _CallPageState();
|
|
}
|
|
|
|
class _CallPageState extends State<CallPage> {
|
|
final ObfuscateService _obfuscateService = ObfuscateService();
|
|
bool isMuted = false;
|
|
bool isSpeakerOn = false;
|
|
bool isKeypadVisible = false;
|
|
bool icingProtocolOk = true;
|
|
String _typedDigits = ""; // New state variable for pressed digits
|
|
bool isOnHold = false; // New state variable for hold status
|
|
|
|
void _addDigit(String digit) {
|
|
setState(() {
|
|
_typedDigits += digit;
|
|
});
|
|
}
|
|
|
|
void _toggleMute() {
|
|
setState(() {
|
|
isMuted = !isMuted;
|
|
});
|
|
}
|
|
|
|
void _toggleSpeaker() {
|
|
setState(() {
|
|
isSpeakerOn = !isSpeakerOn;
|
|
});
|
|
}
|
|
|
|
void _toggleKeypad() {
|
|
setState(() {
|
|
isKeypadVisible = !isKeypadVisible;
|
|
});
|
|
}
|
|
|
|
void _toggleIcingProtocol() {
|
|
setState(() {
|
|
icingProtocolOk = !icingProtocolOk;
|
|
});
|
|
}
|
|
|
|
void _toggleHold() {
|
|
setState(() {
|
|
isOnHold = !isOnHold;
|
|
});
|
|
}
|
|
|
|
void _hangUp() {
|
|
Navigator.pop(context);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final double avatarRadius = isKeypadVisible ? 45.0 : 45.0; // Smaller avatar
|
|
final double nameFontSize = isKeypadVisible ? 24.0 : 24.0; // Smaller font
|
|
final double statusFontSize = isKeypadVisible ? 16.0 : 16.0; // Smaller status
|
|
|
|
// Calculate max visible chars based on screen width
|
|
double screenWidth = MediaQuery.of(context).size.width;
|
|
// Estimate ~14 pixels per character for the digit display (fontSize 24)
|
|
// Subtract some padding (40) for the margins
|
|
int estimatedMaxChars = ((screenWidth - 80) ~/ 14).clamp(10, 100) - 1;
|
|
|
|
// Helper function to format the displayed digits with dynamic width
|
|
String _formatDisplayDigits() {
|
|
if (_typedDigits.length <= estimatedMaxChars) {
|
|
return _typedDigits;
|
|
} else {
|
|
// Show ellipsis at the beginning and the most recent digits
|
|
return '...' + _typedDigits.substring(_typedDigits.length - estimatedMaxChars + 3);
|
|
}
|
|
}
|
|
|
|
return Scaffold(
|
|
body: Container(
|
|
color: Colors.black,
|
|
child: SafeArea(
|
|
child: Column(
|
|
children: [
|
|
// Top section - make it more compact
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SizedBox(height: 35),
|
|
ObfuscatedAvatar(
|
|
imageBytes: widget.thumbnail,
|
|
radius: avatarRadius,
|
|
backgroundColor: generateColorFromName(widget.displayName),
|
|
fallbackInitial: widget.displayName,
|
|
),
|
|
const SizedBox(height: 4),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
icingProtocolOk ? Icons.lock : Icons.lock_open,
|
|
color: icingProtocolOk ? Colors.green : Colors.red,
|
|
size: 16,
|
|
),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
'Icing protocol: ${icingProtocolOk ? "ok" : "ko"}',
|
|
style: TextStyle(
|
|
color: icingProtocolOk ? Colors.green : Colors.red,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
_obfuscateService.obfuscateData(widget.displayName),
|
|
style: TextStyle(
|
|
fontSize: nameFontSize,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
Text(
|
|
'Calling...',
|
|
style: TextStyle(fontSize: statusFontSize, color: Colors.white70),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Middle section - make it flexible and scrollable if needed
|
|
Expanded(
|
|
child: Column(
|
|
children: [
|
|
if (isKeypadVisible) ...
|
|
[
|
|
// Updated typed digits display with dynamic width
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
_formatDisplayDigits(),
|
|
maxLines: 1,
|
|
textAlign: TextAlign.right,
|
|
overflow: TextOverflow.visible,
|
|
style: const TextStyle(
|
|
fontSize: 24,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
IconButton(
|
|
padding: EdgeInsets.zero,
|
|
onPressed: _toggleKeypad,
|
|
icon: const Icon(Icons.close, color: Colors.white),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Modified keypad section
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
for (var i = 0; i < 4; i++)
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
for (var j = 1; j <= 3; j++)
|
|
Expanded(
|
|
child: AspectRatio(
|
|
aspectRatio: 1.5,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(4.0),
|
|
child: Material(
|
|
color: Colors.transparent,
|
|
child: InkWell(
|
|
customBorder: const CircleBorder(),
|
|
onTap: () {
|
|
String label;
|
|
if (i < 3) {
|
|
label = '${i * 3 + j}';
|
|
} else {
|
|
if (j == 1) label = '*';
|
|
else if (j == 2) label = '0';
|
|
else label = '#';
|
|
}
|
|
_addDigit(label);
|
|
},
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.grey[900]?.withOpacity(0.5),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
i < 3 ? '${i * 3 + j}'
|
|
: (j == 1 ? '*' : (j == 2 ? '0' : '#')),
|
|
style: const TextStyle(
|
|
fontSize: 32,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
] else ...
|
|
[
|
|
const Spacer(),
|
|
const Spacer(),
|
|
// Control buttons
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 32.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// Main control buttons
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
// Mute
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
onPressed: _toggleMute,
|
|
icon: Icon(
|
|
isMuted ? Icons.mic_off : Icons.mic,
|
|
color: Colors.white,
|
|
size: 32,
|
|
),
|
|
),
|
|
Text(
|
|
isMuted ? 'Unmute' : 'Mute',
|
|
style: const TextStyle(color: Colors.white, fontSize: 14),
|
|
),
|
|
],
|
|
),
|
|
// Keypad
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
onPressed: _toggleKeypad,
|
|
icon: const Icon(Icons.dialpad, color: Colors.white, size: 32),
|
|
),
|
|
const Text(
|
|
'Keypad',
|
|
style: TextStyle(color: Colors.white, fontSize: 14),
|
|
),
|
|
],
|
|
),
|
|
// Speaker
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
onPressed: _toggleSpeaker,
|
|
icon: Icon(
|
|
isSpeakerOn ? Icons.volume_up : Icons.volume_off,
|
|
color: isSpeakerOn ? Colors.amber : Colors.white,
|
|
size: 32,
|
|
),
|
|
),
|
|
const Text(
|
|
'Speaker',
|
|
style: TextStyle(color: Colors.white, fontSize: 14),
|
|
),
|
|
],
|
|
),
|
|
// New "mettre en attente" / Hold button
|
|
],
|
|
),
|
|
const SizedBox(height: 20),
|
|
// Additional buttons
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
// Add Contact
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
onPressed: () {
|
|
// ...existing code...
|
|
},
|
|
icon: const Icon(Icons.person_add, color: Colors.white, size: 32),
|
|
),
|
|
const Text('Add Contact',
|
|
style: TextStyle(color: Colors.white, fontSize: 14)),
|
|
],
|
|
),
|
|
// New "Hold" button inserted between Add Contact and Change SIM
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
onPressed: _toggleHold,
|
|
icon: Icon(
|
|
isOnHold ? Icons.play_arrow : Icons.pause,
|
|
color: Colors.white,
|
|
size: 32,
|
|
),
|
|
),
|
|
Text(
|
|
isOnHold ? 'Resume' : 'Hold',
|
|
style: const TextStyle(color: Colors.white, fontSize: 14),
|
|
),
|
|
],
|
|
),
|
|
// Change SIM
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
IconButton(
|
|
onPressed: () {
|
|
// ...existing code...
|
|
},
|
|
icon: const Icon(Icons.sim_card, color: Colors.white, size: 32),
|
|
),
|
|
const Text('Change SIM',
|
|
style: TextStyle(color: Colors.white, fontSize: 14)),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Spacer(flex: 3),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
|
|
// Bottom section - hang up button
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 16.0),
|
|
child: GestureDetector(
|
|
onTap: _hangUp,
|
|
child: Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.red,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: const Icon(
|
|
Icons.call_end,
|
|
color: Colors.white,
|
|
size: 32,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|