Add TWP Softphone Flutter app and complete mobile backend API
All checks were successful
Create Release / build (push) Successful in 4s
All checks were successful
Create Release / build (push) Successful in 4s
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for mobile VoIP, implement unhold_call() with call leg detection, wire FCM push notifications into call queue and webhook missed call handlers, add data-only FCM message support for Android background wake, and add Twilio API Key / Push Credential settings fields. Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth with auto-refresh, SSE real-time queue updates, FCM push notifications, Material 3 UI with dashboard, active call screen, dialpad, and call controls (mute/speaker/hold/transfer). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
55
mobile/lib/widgets/dialpad.dart
Normal file
55
mobile/lib/widgets/dialpad.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Dialpad extends StatelessWidget {
|
||||
final void Function(String digit) onDigit;
|
||||
final VoidCallback onClose;
|
||||
|
||||
const Dialpad({super.key, required this.onDigit, required this.onClose});
|
||||
|
||||
static const _keys = [
|
||||
['1', '2', '3'],
|
||||
['4', '5', '6'],
|
||||
['7', '8', '9'],
|
||||
['*', '0', '#'],
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 48),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
..._keys.map((row) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: row
|
||||
.map((key) => Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: InkWell(
|
||||
onTap: () => onDigit(key),
|
||||
borderRadius: BorderRadius.circular(40),
|
||||
child: Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
key,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineSmall,
|
||||
),
|
||||
),
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
)),
|
||||
const SizedBox(height: 8),
|
||||
TextButton(
|
||||
onPressed: onClose,
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user