接听挂断电话

This commit is contained in:
GYJ 2024-11-28 13:49:26 +08:00
parent 1da1683adc
commit b6cd0d0f2b
13 changed files with 305 additions and 13 deletions

View File

@ -17,6 +17,8 @@ import org.json.JSONObject;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import cn.kaer.callmodule.ctrl.CallController;
import cn.kaer.callmodule.exceptions.CallException;
import io.flutter.Log; import io.flutter.Log;
public class CallManager { public class CallManager {
@ -68,4 +70,22 @@ public class CallManager {
broad.putExtra("callLog", callLogArray.toString()); broad.putExtra("callLog", callLogArray.toString());
mainActivityContext.sendBroadcast(broad); mainActivityContext.sendBroadcast(broad);
} }
public static void acceptCall() {
try {
CallController.get().answer();
} catch (CallException e) {
e.printStackTrace();
}
}
public static void rejectCall() {
try {
CallController.get().term();
} catch (CallException e) {
e.printStackTrace();
}
}
public static void endCall() {}
} }

View File

@ -8,6 +8,9 @@ public class ChannelNames {
public static final String CALL_LOG_CALLBACK = "callLogCallback"; public static final String CALL_LOG_CALLBACK = "callLogCallback";
public static final String CALL_STATUS_CHANGE = "callStatusChange"; public static final String CALL_STATUS_CHANGE = "callStatusChange";
public static final String ACCEPT_CALL = "acceptCall";
public static final String REJECT_CALL = "rejectCall";
public static final String END_CALL = "endCall";
public static String getChannelName(String name) { public static String getChannelName(String name) {
return BASE_NAME + name; return BASE_NAME + name;

View File

@ -8,6 +8,9 @@ import io.flutter.plugin.common.MethodChannel;
public class MessageChannel { public class MessageChannel {
public static void addMessageChannel(BinaryMessenger messenger) { public static void addMessageChannel(BinaryMessenger messenger) {
callLogChannel(messenger); callLogChannel(messenger);
acceptCallChannel(messenger);
rejectCallChannel(messenger);
endCallChannel(messenger);
} }
public static void callLogChannel(BinaryMessenger messenger) { public static void callLogChannel(BinaryMessenger messenger) {
@ -26,4 +29,55 @@ public class MessageChannel {
}; };
}); });
} }
public static void acceptCallChannel(BinaryMessenger messenger) {
if (messenger == null) {
return;
}
MethodChannel methodChannel = new MethodChannel(messenger, ChannelNames.getChannelName(ChannelNames.ACCEPT_CALL));
methodChannel.setMethodCallHandler((call, result) -> {
System.out.println("call.method: " + call.method);
if (call.method.equals(ChannelNames.ACCEPT_CALL)) {
System.out.println("接听电话");
result.success(null);
CallManager.acceptCall();
}
});
}
public static void rejectCallChannel(BinaryMessenger messenger) {
if (messenger == null) {
return;
}
MethodChannel methodChannel = new MethodChannel(messenger, ChannelNames.getChannelName(ChannelNames.REJECT_CALL));
methodChannel.setMethodCallHandler((call, result) -> {
System.out.println("call.method: " + call.method);
if (call.method.equals(ChannelNames.REJECT_CALL)) {
System.out.println("拒接电话");
result.success(null);
CallManager.rejectCall();
}
});
}
public static void endCallChannel(BinaryMessenger messenger) {
if (messenger == null) {
return;
}
MethodChannel methodChannel = new MethodChannel(messenger, ChannelNames.getChannelName(ChannelNames.END_CALL));
methodChannel.setMethodCallHandler((call, result) -> {
System.out.println("call.method: " + call.method);
if (call.method.equals(ChannelNames.END_CALL)) {
System.out.println("结束通话");
result.success(null);
CallManager.endCall();
}
});
}
} }

BIN
images/call/accept.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
images/call/reject.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -1,10 +1,14 @@
import 'dart:async';
import 'package:cashier_reserve/common/base/ui.dart'; import 'package:cashier_reserve/common/base/ui.dart';
import 'package:cashier_reserve/common/channel/model/call_status_change_model.dart'; import 'package:cashier_reserve/common/channel/model/call_status_change_model.dart';
import 'package:cashier_reserve/common/manager/event_manager.dart';
class CallView extends StatefulWidget { class CallView extends StatefulWidget {
final CallStatusChangeModel statusModel; final CallStatusChangeModel statusModel;
final Function(String action)? onAction;
const CallView({super.key, required this.statusModel}); const CallView({super.key, required this.statusModel, this.onAction});
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {
@ -13,6 +17,26 @@ class CallView extends StatefulWidget {
} }
class _CallViewState extends State<CallView> { class _CallViewState extends State<CallView> {
int _callDuration = 0;
Timer? _callDurationTimer;
bool _isAccept = false;
@override
void initState() {
super.initState();
EventManager.addListener<CallReceivedEvent>(this, (event) {
_acceptCall();
});
}
@override
void dispose() {
_cancelDurationTimer();
EventManager.cancelListener(this);
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -27,11 +51,118 @@ class _CallViewState extends State<CallView> {
child: Container( child: Container(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
color: Colors.blue, color: const Color(0x55000000),
child: Container(), child: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
height: MediaQuery.of(context).size.height * 0.8,
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.9),
borderRadius: BorderRadius.circular(10),
),
child: _buildCallInfo(context),
),
),
), ),
), ),
), ),
); );
} }
String _getCallDuration() {
//
int hour = _callDuration ~/ 3600;
int minute = _callDuration % 3600 ~/ 60;
int second = _callDuration % 60;
return "${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}:${second.toString().padLeft(2, '0')}";
}
_acceptCall() {
if (_isAccept) {
return;
}
_isAccept = true;
_startDurationTimer();
}
_startDurationTimer() {
_callDurationTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
_callDuration++;
});
});
}
_cancelDurationTimer() {
_callDurationTimer?.cancel();
}
Widget _buildCallInfo(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildIncomingInfo(context),
const SizedBox(height: 70),
_buildActionBtn(context),
],
);
}
Widget _buildIncomingInfo(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"${widget.statusModel.number}",
style: const TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Text(
"${widget.statusModel.region}",
style: const TextStyle(fontSize: 15, color: Colors.white),
),
const SizedBox(height: 20),
Text(_getCallDuration(),
style: const TextStyle(fontSize: 20, color: Colors.white)),
],
);
}
Widget _buildActionBtn(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {
//
if (widget.onAction != null) {
widget.onAction!("reject");
}
},
child: Container(
padding: const EdgeInsets.all(10),
child: Image.asset('images/call/reject.png', width: 60, height: 60),
),
),
if (!_isAccept) const SizedBox(width: 80),
if (!_isAccept) InkWell(
onTap: () {
//
if (widget.onAction != null) {
widget.onAction!("accept");
}
_acceptCall();
},
child: Container(
padding: const EdgeInsets.all(10),
child: Image.asset('images/call/accept.png', width: 60, height: 60),
),
),
],
);
}
} }

View File

@ -13,4 +13,34 @@ class ChannelManager {
yjPrint('$kGetCallLog 发生异常:$e'); yjPrint('$kGetCallLog 发生异常:$e');
} }
} }
static Future<void> acceptCall() async {
MethodChannel channel = MethodChannel(getChannelName(kAcceptCall));
try {
final result = await channel.invokeMethod(kAcceptCall);
yjPrint(result);
} on PlatformException catch (e) {
yjPrint('$kAcceptCall 发生异常:$e');
}
}
static Future<void> rejectCall() async {
MethodChannel channel = MethodChannel(getChannelName(kRejectCall));
try {
final result = await channel.invokeMethod(kRejectCall);
yjPrint(result);
} on PlatformException catch (e) {
yjPrint('$kRejectCall 发生异常:$e');
}
}
static Future<void> endCall() async {
MethodChannel channel = MethodChannel(getChannelName(kEndCall));
try {
final result = await channel.invokeMethod(kEndCall);
yjPrint(result);
} on PlatformException catch (e) {
yjPrint('$kEndCall 发生异常:$e');
}
}
} }

View File

@ -5,6 +5,9 @@ const String kGetCallLog = 'getCallLog';
const String kCallLogCallback = 'callLogCallback'; const String kCallLogCallback = 'callLogCallback';
const String kCallStatusChange = 'callStatusChange'; const String kCallStatusChange = 'callStatusChange';
const String kAcceptCall = 'acceptCall';
const String kEndCall = 'endCall';
const String kRejectCall = 'rejectCall';
String getChannelName(name) { String getChannelName(name) {
return kChannelBaseName + name; return kChannelBaseName + name;

View File

@ -55,7 +55,15 @@ class GetCallLogEvent extends MyEvent {
} }
class CallStatusChangeEvent extends MyEvent { class CallStatusChangeEvent extends MyEvent {
/// state = IncomingNumberReceived
/// state = OutGoing
/// state = End
/// state = Incoming
CallStatusChangeModel model; CallStatusChangeModel model;
CallStatusChangeEvent({required this.model}); CallStatusChangeEvent({required this.model});
} }
class CallReceivedEvent extends MyEvent {
CallReceivedEvent();
}

View File

@ -1,6 +1,7 @@
import 'package:cashier_reserve/call/call_view.dart'; import 'package:cashier_reserve/call/call_view.dart';
import 'package:cashier_reserve/common/base/ui.dart'; import 'package:cashier_reserve/common/base/ui.dart';
import 'package:cashier_reserve/common/base/ui_model.dart'; import 'package:cashier_reserve/common/base/ui_model.dart';
import 'package:cashier_reserve/common/channel/channel_manager.dart';
import 'package:cashier_reserve/common/channel/model/call_status_change_model.dart'; import 'package:cashier_reserve/common/channel/model/call_status_change_model.dart';
import 'package:cashier_reserve/common/manager/app_manager.dart'; import 'package:cashier_reserve/common/manager/app_manager.dart';
import 'package:cashier_reserve/common/manager/event_manager.dart'; import 'package:cashier_reserve/common/manager/event_manager.dart';
@ -51,11 +52,27 @@ class HomeViewModel extends BaseUIModel {
}); });
EventManager.addListener<CallStatusChangeEvent>(this, (event) { EventManager.addListener<CallStatusChangeEvent>(this, (event) {
yjPrint("HomeViewModel CallStatusChangeEvent state: ${event.model.state}"); yjPrint(
if (event.model.state == "Incoming") { "HomeViewModel CallStatusChangeEvent state: ${event.model.state}");
showCallInfoView(event.model);
} else { /// state = IncomingNumberReceived
hideCallInfoView(); /// state = OutGoing
/// state = End
/// state = Incoming
/// state = Idle
switch (event.model.state) {
case "IncomingNumberReceived":
EventManager.postEvent(CallReceivedEvent());
break;
case "OutGoing":
break;
case "Incoming":
showCallInfoView(event.model);
break;
default:
hideCallInfoView();
break;
} }
}); });
} }
@ -85,7 +102,19 @@ class HomeViewModel extends BaseUIModel {
if (isShowCallView) { if (isShowCallView) {
return; return;
} }
YJPush.presentWidget(context!, CallView(statusModel: model)); YJPush.presentWidget(
context!,
CallView(
statusModel: model,
onAction: (action) {
yjPrint("call view action: $action");
if (action == "accept") {
ChannelManager.acceptCall();
} else {
ChannelManager.rejectCall();
hideCallInfoView();
}
}));
isShowCallView = true; isShowCallView = true;
} }

View File

@ -78,7 +78,9 @@ class ReserveView extends BaseUI with TickerProviderStateMixin {
width: 15, width: 15,
), ),
InkWell( InkWell(
onTap: () { }, onTap: () {
provider.testCallIncoming();
},
child: SizedBox( child: SizedBox(
width: 40, width: 40,
height: 40, height: 40,
@ -95,9 +97,7 @@ class ReserveView extends BaseUI with TickerProviderStateMixin {
width: 5, width: 5,
), ),
InkWell( InkWell(
onTap: () { onTap: () { },
provider.loadTableAreaList();
},
child: SizedBox( child: SizedBox(
width: 40, width: 40,
height: 40, height: 40,

View File

@ -1,6 +1,7 @@
import 'package:cashier_reserve/common/base/ui_model.dart'; import 'package:cashier_reserve/common/base/ui_model.dart';
import 'package:cashier_reserve/common/channel/model/call_log_model.dart'; import 'package:cashier_reserve/common/channel/model/call_log_model.dart';
import 'package:cashier_reserve/common/channel/channel_manager.dart'; import 'package:cashier_reserve/common/channel/channel_manager.dart';
import 'package:cashier_reserve/common/channel/model/call_status_change_model.dart';
import 'package:cashier_reserve/common/manager/app_manager.dart'; import 'package:cashier_reserve/common/manager/app_manager.dart';
import 'package:cashier_reserve/common/manager/event_manager.dart'; import 'package:cashier_reserve/common/manager/event_manager.dart';
import 'package:cashier_reserve/common/print/print.dart'; import 'package:cashier_reserve/common/print/print.dart';
@ -138,6 +139,17 @@ class ReserveViewModel extends BaseUIModel {
loadReserveSms(); loadReserveSms();
} }
void testCallIncoming() {
CallStatusChangeModel model = CallStatusChangeModel(
state: "Incoming",
number: "123456789",
name: "测试",
region: "陕西省 西安市",
);
EventManager.postEvent(CallStatusChangeEvent(model: model));
}
void loadCallLog() { void loadCallLog() {
ChannelManager.getCallLog("getCallLog"); ChannelManager.getCallLog("getCallLog");
} }

View File

@ -84,6 +84,8 @@ flutter:
- images/reserve/ - images/reserve/
- images/call/
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images # https://flutter.dev/to/resolution-aware-images