-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
320 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
class CallActions extends StatelessWidget { | ||
final bool canCall; | ||
final VoidCallback? onPerformCall; | ||
|
||
const CallActions({ | ||
super.key, | ||
this.canCall = true, | ||
this.onPerformCall, | ||
}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Row( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: [ | ||
if(canCall) | ||
_CallAction(onPressed: onPerformCall, text: "Make Call"), | ||
], | ||
); | ||
} | ||
} | ||
|
||
class _CallAction extends StatelessWidget { | ||
final VoidCallback? onPressed; | ||
final String text; | ||
|
||
const _CallAction({super.key, required this.onPressed, required this.text}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return ElevatedButton( | ||
onPressed: onPressed, | ||
child: Text(text), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter/widgets.dart'; | ||
import 'package:twilio_voice/twilio_voice.dart'; | ||
|
||
import 'state_toggle.dart'; | ||
|
||
class CallControls extends StatefulWidget { | ||
const CallControls({super.key}); | ||
|
||
@override | ||
State<CallControls> createState() => _CallControlsState(); | ||
} | ||
|
||
class _CallControlsState extends State<CallControls> { | ||
|
||
late final StreamSubscription<CallEvent> _subscription; | ||
final _events = <CallEvent>[]; | ||
|
||
//#region #region State Getters | ||
bool _stateHold = false; | ||
|
||
set stateHold(bool value) { | ||
setState(() { | ||
_stateHold = value; | ||
}); | ||
} | ||
|
||
bool _stateMute = false; | ||
|
||
set stateMute(bool value) { | ||
setState(() { | ||
_stateMute = value; | ||
}); | ||
} | ||
|
||
bool _stateSpeaker = false; | ||
|
||
set stateSpeaker(bool value) { | ||
setState(() { | ||
_stateSpeaker = value; | ||
}); | ||
} | ||
|
||
bool _stateBluetooth = false; | ||
|
||
set stateBluetooth(bool value) { | ||
setState(() { | ||
_stateBluetooth = value; | ||
}); | ||
} | ||
|
||
//#endregion | ||
|
||
final _tv = TwilioVoice.instance; | ||
bool activeCall = false; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_subscription = _tv.callEventsListener.listen((event) { | ||
_events.add(event); | ||
switch (event) { | ||
case CallEvent.unhold: | ||
case CallEvent.hold: | ||
case CallEvent.unmute: | ||
case CallEvent.mute: | ||
case CallEvent.speakerOn: | ||
case CallEvent.speakerOff: | ||
case CallEvent.bluetoothOn: | ||
case CallEvent.bluetoothOff: | ||
_updateStates(); | ||
break; | ||
|
||
case CallEvent.connected: | ||
activeCall = true; | ||
_updateStates(); | ||
break; | ||
|
||
case CallEvent.callEnded: | ||
activeCall = false; | ||
_updateStates(); | ||
break; | ||
|
||
case CallEvent.incoming: | ||
case CallEvent.ringing: | ||
case CallEvent.declined: | ||
case CallEvent.answer: | ||
case CallEvent.missedCall: | ||
case CallEvent.returningCall: | ||
case CallEvent.reconnecting: | ||
case CallEvent.reconnected: | ||
_updateStates(); | ||
break; | ||
|
||
case CallEvent.log: | ||
break; | ||
|
||
case CallEvent.permission: | ||
// Using app lifecycle states, we don't have to update permissions here - convenience only. | ||
break; | ||
} | ||
}); | ||
_updateStates(); | ||
} | ||
|
||
void _updateStates() { | ||
// get all states from call | ||
_tv.call.isMuted().then((value) => stateMute = value ?? false); | ||
_tv.call.isHolding().then((value) => stateHold = value ?? false); | ||
_tv.call.isOnSpeaker().then((value) => stateSpeaker = value ?? false); | ||
_tv.call.isBluetoothOn().then((value) => stateBluetooth = value ?? false); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Column( | ||
children: [ | ||
// state | ||
Text("State", style: Theme.of(context).textTheme.titleLarge), | ||
|
||
Row( | ||
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
children: [ | ||
Expanded( | ||
child: StateToggle( | ||
state: _stateMute, | ||
icon: _stateMute ? Icons.mic : Icons.mic_off, | ||
title: "Mute", | ||
onTap: () => _tv.call.toggleMute(!_stateMute), | ||
), | ||
), | ||
Expanded( | ||
child: StateToggle( | ||
state: _stateHold, | ||
icon: Icons.pause, | ||
title: "Hold", | ||
iconColor: _stateHold ? Colors.orange : null, | ||
onTap: () => _tv.call.holdCall(holdCall: !_stateHold), | ||
), | ||
), | ||
Expanded( | ||
child: StateToggle( | ||
state: _stateSpeaker, | ||
icon: Icons.volume_up, | ||
title: "Speaker", | ||
iconColor: _stateSpeaker ? Colors.green : null, | ||
onTap: () => _tv.call.toggleSpeaker(!_stateSpeaker), | ||
), | ||
), | ||
Expanded( | ||
child: StateToggle( | ||
state: _stateBluetooth, | ||
icon: Icons.bluetooth, | ||
title: "Bluetooth", | ||
iconColor: _stateBluetooth ? Colors.blue : null, | ||
onTap: () => _tv.call.toggleBluetooth(bluetoothOn: !_stateBluetooth), | ||
), | ||
), | ||
], | ||
), | ||
|
||
Row( | ||
children: [ | ||
Expanded( | ||
child: StateToggle( | ||
state: activeCall, | ||
icon: Icons.call_end, | ||
title: "Hangup", | ||
iconColor: Colors.red, | ||
onTap: activeCall ? () => _tv.call.hangUp() : null, | ||
), | ||
), | ||
], | ||
), | ||
|
||
const SizedBox(height: 12), | ||
] | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_subscription.cancel(); | ||
super.dispose(); | ||
} | ||
} |
8 changes: 4 additions & 4 deletions
8
...e/lib/screens/widgets/on_call_widget.dart → example/lib/screens/widgets/call_status.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.