feat: Add CallPage for initiating calls with contact details
All checks were successful
/ mirror (push) Successful in 4s

This commit is contained in:
AlexisDanlos 2025-02-16 19:19:03 +01:00
parent ecf4ea16d8
commit d3a0a4740d
2 changed files with 230 additions and 0 deletions

View File

@ -0,0 +1,217 @@
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;
void _toggleMute() {
setState(() {
isMuted = !isMuted;
});
}
void _toggleSpeaker() {
setState(() {
isSpeakerOn = !isSpeakerOn;
});
}
void _toggleKeypad() {
setState(() {
isKeypadVisible = !isKeypadVisible;
});
}
void _toggleIcingProtocol() {
setState(() {
icingProtocolOk = !icingProtocolOk;
});
}
void _hangUp() {
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
final double avatarRadius = isKeypadVisible ? 30.0 : 60.0;
final double nameFontSize = isKeypadVisible ? 20.0 : 32.0;
final double statusFontSize = isKeypadVisible ? 16.0 : 20.0;
return Scaffold(
body: Container(
color: Colors.black,
child: SafeArea(
child: Column(
children: [
// Fixed size header area
Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 20),
ObfuscatedAvatar(
imageBytes: widget.thumbnail,
radius: avatarRadius,
backgroundColor: generateColorFromName(widget.displayName),
fallbackInitial: widget.displayName,
),
const SizedBox(height: 10),
Text(
_obfuscateService.obfuscateData(widget.displayName),
style: TextStyle(
fontSize: nameFontSize,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 5),
Text(
'Calling...',
style: TextStyle(fontSize: statusFontSize, color: Colors.white70),
),
const SizedBox(height: 10),
],
),
// Scrollable middle section
Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Keypad if visible
if (isKeypadVisible)
Container(
margin: const EdgeInsets.symmetric(horizontal: 40),
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.black45,
borderRadius: BorderRadius.circular(10),
),
child: GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
children: List.generate(12, (index) {
String label;
if (index < 9) {
label = '${index + 1}';
} else if (index == 9) {
label = '*';
} else if (index == 10) {
label = '0';
} else {
label = '#';
}
return Center(
child: Text(
label,
style: const TextStyle(
fontSize: 24, color: Colors.white),
),
);
}),
),
),
// Icing protocol status
GestureDetector(
onTap: _toggleIcingProtocol,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icingProtocolOk ? Icons.lock : Icons.lock_open,
color: icingProtocolOk ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
'Icing protocol: ${icingProtocolOk ? "ok" : "ko"}',
style: TextStyle(
color: icingProtocolOk ? Colors.green : Colors.red,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
// Control buttons
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: _toggleMute,
icon: Icon(
isMuted ? Icons.mic_off : Icons.mic,
color: Colors.white,
size: 32,
),
),
IconButton(
onPressed: _toggleKeypad,
icon: Icon(
Icons.dialpad,
color: isKeypadVisible ? Colors.amber : Colors.white,
size: 32,
),
),
IconButton(
onPressed: _toggleSpeaker,
icon: Icon(
isSpeakerOn ? Icons.volume_up : Icons.volume_off,
color: isSpeakerOn ? Colors.amber : Colors.white,
size: 32,
),
),
],
),
),
],
),
),
),
// Fixed size footer with hang up button
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: IconButton(
onPressed: _hangUp,
icon: const Icon(
Icons.call_end,
color: Colors.red,
size: 48,
),
),
),
],
),
),
),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:dialer/widgets/username_color_generator.dart';
import '../../../services/block_service.dart';
import '../../../services/contact_service.dart';
import '../../../features/call/call_page.dart';
class ContactModal extends StatefulWidget {
final Contact contact;
@ -263,6 +264,18 @@ class _ContactModalState extends State<ContactModal> {
_launchPhoneDialer(phoneNumber);
}
},
onLongPress: () {
// Navigate to the beautiful calling page demo
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => CallPage(
displayName: widget.contact.displayName,
thumbnail: widget.contact.thumbnail,
),
),
);
},
),
ListTile(
leading: const Icon(Icons.message, color: Colors.blue),