Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
import 'package:flutter/material.dart';
|
2026-03-06 15:32:22 -08:00
|
|
|
import 'package:flutter/services.dart';
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
import '../providers/auth_provider.dart';
|
|
|
|
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
|
|
|
|
|
|
|
|
class LoginScreen extends StatefulWidget {
|
|
|
|
|
const LoginScreen({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<LoginScreen> createState() => _LoginScreenState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _LoginScreenState extends State<LoginScreen> {
|
|
|
|
|
final _formKey = GlobalKey<FormState>();
|
|
|
|
|
final _serverController = TextEditingController();
|
|
|
|
|
final _usernameController = TextEditingController();
|
|
|
|
|
final _passwordController = TextEditingController();
|
|
|
|
|
bool _obscurePassword = true;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
_loadSavedServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _loadSavedServer() async {
|
|
|
|
|
const storage = FlutterSecureStorage();
|
|
|
|
|
final saved = await storage.read(key: 'server_url');
|
|
|
|
|
if (saved != null && mounted) {
|
|
|
|
|
_serverController.text = saved;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _submit() {
|
|
|
|
|
if (!_formKey.currentState!.validate()) return;
|
|
|
|
|
|
|
|
|
|
var serverUrl = _serverController.text.trim();
|
|
|
|
|
if (!serverUrl.startsWith('http')) {
|
|
|
|
|
serverUrl = 'https://$serverUrl';
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 15:32:22 -08:00
|
|
|
TextInput.finishAutofillContext();
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
context.read<AuthProvider>().login(
|
|
|
|
|
serverUrl,
|
|
|
|
|
_usernameController.text.trim(),
|
|
|
|
|
_passwordController.text,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
final auth = context.watch<AuthProvider>();
|
|
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
|
body: SafeArea(
|
|
|
|
|
child: Center(
|
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
|
padding: const EdgeInsets.all(24),
|
2026-03-06 15:32:22 -08:00
|
|
|
child: AutofillGroup(
|
|
|
|
|
child: Form(
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
key: _formKey,
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
|
|
|
|
Icon(
|
|
|
|
|
Icons.phone_in_talk,
|
|
|
|
|
size: 64,
|
|
|
|
|
color: Theme.of(context).colorScheme.primary,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
Text(
|
|
|
|
|
'TWP Softphone',
|
|
|
|
|
style: Theme.of(context).textTheme.headlineMedium,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
|
TextFormField(
|
|
|
|
|
controller: _serverController,
|
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
|
labelText: 'Server URL',
|
|
|
|
|
hintText: 'https://your-site.com',
|
|
|
|
|
prefixIcon: Icon(Icons.dns),
|
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
|
),
|
|
|
|
|
keyboardType: TextInputType.url,
|
2026-03-06 15:32:22 -08:00
|
|
|
autofillHints: const [AutofillHints.url],
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
validator: (v) =>
|
|
|
|
|
v == null || v.trim().isEmpty ? 'Required' : null,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
TextFormField(
|
|
|
|
|
controller: _usernameController,
|
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
|
labelText: 'Username',
|
|
|
|
|
prefixIcon: Icon(Icons.person),
|
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
|
),
|
2026-03-06 15:32:22 -08:00
|
|
|
autofillHints: const [AutofillHints.username],
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
validator: (v) =>
|
|
|
|
|
v == null || v.trim().isEmpty ? 'Required' : null,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
TextFormField(
|
|
|
|
|
controller: _passwordController,
|
|
|
|
|
decoration: InputDecoration(
|
|
|
|
|
labelText: 'Password',
|
|
|
|
|
prefixIcon: const Icon(Icons.lock),
|
|
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
|
suffixIcon: IconButton(
|
|
|
|
|
icon: Icon(_obscurePassword
|
|
|
|
|
? Icons.visibility_off
|
|
|
|
|
: Icons.visibility),
|
|
|
|
|
onPressed: () =>
|
|
|
|
|
setState(() => _obscurePassword = !_obscurePassword),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
obscureText: _obscurePassword,
|
2026-03-06 15:32:22 -08:00
|
|
|
autofillHints: const [AutofillHints.password],
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
validator: (v) =>
|
|
|
|
|
v == null || v.isEmpty ? 'Required' : null,
|
|
|
|
|
),
|
|
|
|
|
if (auth.error != null) ...[
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
Text(
|
|
|
|
|
auth.error!,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
color: Theme.of(context).colorScheme.error),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
const SizedBox(height: 24),
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
height: 48,
|
|
|
|
|
child: FilledButton(
|
|
|
|
|
onPressed: auth.state == AuthState.authenticating
|
|
|
|
|
? null
|
|
|
|
|
: _submit,
|
|
|
|
|
child: auth.state == AuthState.authenticating
|
|
|
|
|
? const SizedBox(
|
|
|
|
|
width: 24,
|
|
|
|
|
height: 24,
|
|
|
|
|
child: CircularProgressIndicator(
|
|
|
|
|
strokeWidth: 2, color: Colors.white),
|
|
|
|
|
)
|
|
|
|
|
: const Text('Connect'),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-03-06 15:32:22 -08:00
|
|
|
),
|
Add TWP Softphone Flutter app and complete mobile backend API
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>
2026-03-06 13:01:23 -08:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
_serverController.dispose();
|
|
|
|
|
_usernameController.dispose();
|
|
|
|
|
_passwordController.dispose();
|
|
|
|
|
super.dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|