parent
4d750d6316
commit
175ffa873c
|
|
@ -36,7 +36,10 @@ class MeetingRoomUser extends Object{
|
|||
@JsonKey(name: 'isRoomManager')
|
||||
bool isRoomManager;
|
||||
|
||||
MeetingRoomUser(this.uid,this.connectId,this.account,this.enableMicr,this.enableCamera,this.screenShareId,this.userName,this.roleId,this.roleName,this.isRoomManager,);
|
||||
@JsonKey(name: 'volume')
|
||||
double? volume = 0.0;
|
||||
|
||||
MeetingRoomUser(this.uid,this.connectId,this.account,this.enableMicr,this.enableCamera,this.screenShareId,this.userName,this.roleId,this.roleName,this.isRoomManager,this.volume);
|
||||
|
||||
factory MeetingRoomUser.fromJson(Map<String, dynamic> srcJson) => _$MeetingRoomUserFromJson(srcJson);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:get/get.dart';
|
||||
import 'package:signalr_core/signalr_core.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
import 'package:wgshare/utils/count_microphone_volume.dart';
|
||||
import '../../common/config/request_config.dart';
|
||||
import '../../common/mixins/request_tool_mixin.dart';
|
||||
import '../../common/models/common/base_structure_result.dart';
|
||||
|
|
@ -137,9 +138,10 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
/// 结束发言
|
||||
Future<void> doHttpCancelSpeak() async {
|
||||
BaseStructureResult res = await getClient().cancelSpeak(state.meetingRoomInfo.value!.id, state.meetingRoomInfo.value!.roomNum, UserStore.to.userInfoEntity.value!.uid);
|
||||
setClientRole("观众");
|
||||
}
|
||||
|
||||
/// 设置麦克风是否静音
|
||||
/// 设置麦克风是否开启
|
||||
void setMicrophoneOpen(bool isOpen){
|
||||
state.isOpenMicrophone.value = isOpen;
|
||||
for(var i = 0; i < state.cacheUsers.value.length; i++){
|
||||
|
|
@ -148,7 +150,22 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
}
|
||||
}
|
||||
state.users.value = state.cacheUsers.value;
|
||||
setEnableLocalAudio(isOpen);
|
||||
if(isOpen == true){
|
||||
setClientRole("主播");
|
||||
}else{
|
||||
setClientRole("观众");
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置视频是否打开
|
||||
void setCameraOpen(bool isOpen){
|
||||
state.isOpenCamera.value = isOpen;
|
||||
if(isOpen == true){
|
||||
setEnableLocalVideo(isOpen);
|
||||
setClientRole("主播");
|
||||
}else{
|
||||
setClientRole("观众");
|
||||
}
|
||||
}
|
||||
|
||||
/// --------------------------signalR Socket相关
|
||||
|
|
@ -207,7 +224,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
if(UserStore.to.userInfoEntity.value!.uid == meetingRoomUser.uid){
|
||||
state.isSpeak.value = true;
|
||||
state.isOpenMicrophone.value = true;
|
||||
setEnableLocalAudio(true);
|
||||
setClientRole("主播");
|
||||
}
|
||||
}else{
|
||||
debugPrint("wgs输出===:Socket-停止发言:${e?[0]}--${e?[1]}");
|
||||
|
|
@ -221,7 +238,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
if(UserStore.to.userInfoEntity.value!.uid == meetingRoomUser.uid){
|
||||
state.isSpeak.value = false;
|
||||
state.isOpenMicrophone.value = false;
|
||||
setEnableLocalAudio(false);
|
||||
setClientRole("观众");
|
||||
}
|
||||
}
|
||||
update();
|
||||
|
|
@ -268,7 +285,6 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
}
|
||||
state.users.value = state.cacheUsers.value;
|
||||
state.isOpenMicrophone.value = e?[0];
|
||||
setEnableLocalAudio(e?[0]);
|
||||
});
|
||||
|
||||
/// 单独用户开闭麦回调
|
||||
|
|
@ -284,7 +300,6 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
}
|
||||
}
|
||||
state.isOpenMicrophone.value = true;
|
||||
setEnableLocalAudio(true);
|
||||
}else{
|
||||
debugPrint("wgs输出===:Socket-单独用户闭麦");
|
||||
for(MeetingRoomUser mru in state.cacheUsers.value){
|
||||
|
|
@ -293,7 +308,6 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
}
|
||||
}
|
||||
state.isOpenMicrophone.value = false;
|
||||
setEnableLocalAudio(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -340,7 +354,11 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
));
|
||||
|
||||
// 设置默认音频路由为听筒
|
||||
state.rctEngine.value?.setDefaultAudioRouteToSpeakerphone(false);
|
||||
await state.rctEngine.value?.setDefaultAudioRouteToSpeakerphone(false);
|
||||
// 打开用户音量回调
|
||||
await state.rctEngine.value?.enableAudioVolumeIndication(interval: 200, smooth: 3, reportVad: true);
|
||||
// 启用音频模块
|
||||
await state.rctEngine.value?.enableAudio();
|
||||
|
||||
joinMeetingToRtc();
|
||||
|
||||
|
|
@ -384,6 +402,49 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
// 音频采集开关回调
|
||||
onLocalAudioStateChanged: (RtcConnection connection, LocalAudioStreamState state, LocalAudioStreamReason reason){
|
||||
debugPrint("wgs输出===:RTC-音频采集开关:$state");
|
||||
},
|
||||
|
||||
// 视频采集开关回调
|
||||
onRemoteVideoStateChanged: (RtcConnection connection,
|
||||
int remoteUid,
|
||||
RemoteVideoState state,
|
||||
RemoteVideoStateReason reason,
|
||||
int elapsed){
|
||||
debugPrint("wgs输出===:RTC-视频采集开关:$state");
|
||||
},
|
||||
|
||||
// 用户音量提示回调
|
||||
onAudioVolumeIndication: (
|
||||
RtcConnection connection,
|
||||
List<AudioVolumeInfo> speakers,
|
||||
int speakerNumber,
|
||||
int totalVolume){
|
||||
if(speakers.isNotEmpty){
|
||||
for(AudioVolumeInfo avi in speakers){
|
||||
for(MeetingRoomUser mru in state.cacheUsers.value){
|
||||
if(avi.uid == 0){
|
||||
debugPrint("wgs输出===:RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
state.microphoneVolume.value = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
}else{
|
||||
if(avi.uid.toString() == mru.uid){
|
||||
debugPrint("wgs输出===:RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
// 切换用户角色回调
|
||||
onClientRoleChanged: (
|
||||
RtcConnection connection,
|
||||
ClientRoleType oldRole,
|
||||
ClientRoleType newRole,
|
||||
ClientRoleOptions newRoleOptions){
|
||||
debugPrint("wgs输出===:RTC-切换用户角色");
|
||||
}
|
||||
),
|
||||
);
|
||||
|
|
@ -394,21 +455,21 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
await state.rctEngine.value?.joinChannel(
|
||||
token: state.meetingToken.value,
|
||||
channelId: state.roomNumber.value,
|
||||
uid: 0,
|
||||
uid: int.parse(UserStore.to.userInfoEntity.value!.uid),
|
||||
options: const ChannelMediaOptions(
|
||||
// 自动订阅所有视频流
|
||||
autoSubscribeVideo: true,
|
||||
// 自动订阅所有音频流
|
||||
autoSubscribeAudio: true,
|
||||
// 发布摄像头采集的视频
|
||||
publishCameraTrack: false,
|
||||
publishCameraTrack: true,
|
||||
// 发布麦克风采集的音频
|
||||
publishMicrophoneTrack: false,
|
||||
publishMicrophoneTrack: true,
|
||||
// 设置用户角色为 clientRoleBroadcaster(主播)或 clientRoleAudience(观众)
|
||||
// 这里设置角色为clientRoleBroadcaster(主播)
|
||||
// 主播:可以在频道内发布音视频,同时也可以订阅其他主播发布的音视频
|
||||
// 观众:可以在频道内订阅音视频,不具备发布音视频权限
|
||||
clientRoleType: ClientRoleType.clientRoleBroadcaster),
|
||||
clientRoleType: ClientRoleType.clientRoleAudience),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -420,14 +481,34 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
|
|||
await state.rctEngine.value?.release();
|
||||
}
|
||||
|
||||
/// 设置用户角色
|
||||
Future<void> setClientRole(String roleStr) async {
|
||||
if(roleStr == "主播"){
|
||||
await state.rctEngine.value?.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
|
||||
}else{
|
||||
await state.rctEngine.value?.setClientRole(role: ClientRoleType.clientRoleAudience);
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置音频输出路由(没有外接设备时生效)
|
||||
Future<void> setEnableSpeakerphone(int mode) async {
|
||||
state.communicationMode.value = mode;
|
||||
await state.rctEngine.value?.setEnableSpeakerphone(mode == 1 ? false : true);
|
||||
}
|
||||
|
||||
/// 设置是否打开本地音频采集
|
||||
Future<void> setEnableLocalAudio(bool enabled) async {
|
||||
await state.rctEngine.value?.enableLocalAudio(enabled);
|
||||
/// 设置是否打开本地视频采集
|
||||
Future<void> setEnableLocalVideo(bool enabled) async {
|
||||
state.isOpenCamera.value = enabled;
|
||||
if(enabled == true){
|
||||
// 启用视频模块
|
||||
await state.rctEngine.value?.enableVideo();
|
||||
// 启用本地预览
|
||||
await state.rctEngine.value?.startPreview();
|
||||
}else{
|
||||
// 关闭视频模块
|
||||
await state.rctEngine.value?.disableVideo();
|
||||
// 关闭本地预览
|
||||
await state.rctEngine.value?.stopPreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ class MeetingMainState {
|
|||
late RxBool isSpeak = false.obs;
|
||||
/// 是否打开麦克风
|
||||
late RxBool isOpenMicrophone = false.obs;
|
||||
/// 麦克风音量
|
||||
late RxDouble microphoneVolume = 0.0.obs;
|
||||
/// 是否打开摄像头
|
||||
late RxBool isOpenCamera = false.obs;
|
||||
|
||||
/// 聊天数据
|
||||
late RxList<MeetingRoomMsg> meetingRoomMsgs = RxList([]);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:liquid_progress_indicator_v2/liquid_progress_indicator.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
import 'package:wgshare/pages/metting/share/meeting_main_share_view.dart';
|
||||
import 'package:wgshare/pages/metting/video/meeting_main_video_view.dart';
|
||||
|
|
@ -9,6 +10,7 @@ import 'package:wgshare/utils/toast_utils.dart';
|
|||
|
||||
import '../../utils/color_util.dart';
|
||||
import '../../utils/cus_behavior.dart';
|
||||
import '../../view/view_svg_path.dart';
|
||||
import 'meeting_main_logic.dart';
|
||||
import 'meeting_main_state.dart';
|
||||
import 'voice/meeting_main_voice_view.dart';
|
||||
|
|
@ -167,19 +169,21 @@ class MeetingMainPage extends StatelessWidget {
|
|||
|
||||
// 语音
|
||||
Visibility(
|
||||
visible: true,
|
||||
visible: state.pageState.value == 0,
|
||||
child: MeetingMainVoiceComponent(users: state.cacheUsers.value)
|
||||
),
|
||||
|
||||
// 视频
|
||||
Visibility(
|
||||
visible: false,
|
||||
child: MeetingMainVideoComponent()
|
||||
visible: state.pageState.value == 1,
|
||||
child: null != state.rctEngine.value
|
||||
? MeetingMainVideoComponent(rtcEngine: state.rctEngine.value!, channelId: state.roomNumber.value,isOpenCamera: state.isOpenCamera.value)
|
||||
: Container()
|
||||
),
|
||||
|
||||
// 共享屏幕
|
||||
Visibility(
|
||||
visible: false,
|
||||
visible: state.pageState.value == 2,
|
||||
child: MeetingMainShareComponent()
|
||||
),
|
||||
|
||||
|
|
@ -247,15 +251,33 @@ class MeetingMainPage extends StatelessWidget {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
state.isSpeak.value == false
|
||||
? Image.asset(
|
||||
state.isSpeak.value == false
|
||||
? 'assets/images/meeting_main_sqfy.png'
|
||||
: state.isOpenMicrophone.value == true
|
||||
? 'assets/images/meeting_main_microphone_default.png'
|
||||
: 'assets/images/meeting_main_sqfy.png',
|
||||
width: 22.w,
|
||||
height: 22.h,
|
||||
),
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
)
|
||||
: state.isOpenMicrophone.value == true
|
||||
? Container(
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
child: LiquidCustomProgressIndicator(
|
||||
value: state.microphoneVolume.value,
|
||||
valueColor: const AlwaysStoppedAnimation(ColorUtil.Color_2_177_136),
|
||||
backgroundColor: ColorUtil.Color_255_255_255,
|
||||
direction: Axis.vertical,
|
||||
shapePath: ViewSvgPath.getMicrpphonePath()
|
||||
),
|
||||
)
|
||||
: Image.asset(
|
||||
'assets/images/meeting_main_sqfy.png',
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
) ,
|
||||
SizedBox(height: 4.h),
|
||||
Text(
|
||||
state.isSpeak.value == false ? '申请发言' : state.isOpenMicrophone.value == true ? "手动静音" : "解除静音",
|
||||
|
|
@ -288,13 +310,13 @@ class MeetingMainPage extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/meeting_main_sp.png',
|
||||
state.isSpeak.value == true ? state.isOpenCamera.value == true ? 'assets/images/meeting_main_camera_open.png' : 'assets/images/meeting_main_camera_default.png' : 'assets/images/meeting_main_sp.png',
|
||||
width: 22.w,
|
||||
height: 22.h,
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
Text(
|
||||
'开启视频',
|
||||
state.isOpenCamera.value == true ? "关闭视频" : "开启视频",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_202_202_202),
|
||||
|
|
@ -302,7 +324,13 @@ class MeetingMainPage extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
onTap: (){
|
||||
ToastUtils.getErrFluttertoast(context: context, msg: '开启视频...');
|
||||
if(state.isSpeak.value == true){
|
||||
if(state.isOpenCamera.value == true){
|
||||
logic.setCameraOpen(false);
|
||||
}else{
|
||||
logic.setCameraOpen(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
|
||||
import '../../../utils/color_util.dart';
|
||||
import 'meeting_main_video_logic.dart';
|
||||
import 'meeting_main_video_state.dart';
|
||||
|
||||
class MeetingMainVideoComponent extends StatelessWidget {
|
||||
MeetingMainVideoComponent({Key? key}) : super(key: key);
|
||||
MeetingMainVideoComponent({super.key, required this.rtcEngine, required this.channelId, required this.isOpenCamera});
|
||||
|
||||
final RtcEngine rtcEngine;
|
||||
final String channelId;
|
||||
final bool isOpenCamera;
|
||||
|
||||
final MeetingMainVideoLogic logic = Get.put(MeetingMainVideoLogic());
|
||||
final MeetingMainVideoState state = Get.find<MeetingMainVideoLogic>().state;
|
||||
|
|
@ -85,23 +91,28 @@ class MeetingMainVideoComponent extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
/// 右上角小窗
|
||||
Positioned(
|
||||
top: 58,
|
||||
right: 13,
|
||||
right: 12,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: 120.w,
|
||||
height: 150.h,
|
||||
padding: const EdgeInsets.only(left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.fill,
|
||||
image: NetworkImage(
|
||||
"https://tse1-mm.cn.bing.net/th/id/OIP-C.hdhK40Dw3yN_2mjNQNqFCgAAAA?w=186&h=186&c=7&r=0&o=5&pid=1.7",
|
||||
),
|
||||
Visibility(
|
||||
visible: isOpenCamera,
|
||||
child: SizedBox(
|
||||
width: 120.w,
|
||||
height: 150.h,
|
||||
child: Center(
|
||||
child: isOpenCamera
|
||||
? AgoraVideoView(
|
||||
controller: VideoViewController(
|
||||
rtcEngine: rtcEngine,
|
||||
canvas: VideoCanvas(uid: int.parse(UserStore.to.userInfoEntity.value!.uid)),
|
||||
),
|
||||
)
|
||||
: const CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 4,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:liquid_progress_indicator_v2/liquid_progress_indicator.dart';
|
||||
|
||||
import '../../../common/models/meeting_room_user.dart';
|
||||
import '../../../utils/color_util.dart';
|
||||
import '../../../utils/cus_behavior.dart';
|
||||
import '../../../view/view_svg_path.dart';
|
||||
import 'meeting_main_voice_logic.dart';
|
||||
import 'meeting_main_voice_state.dart';
|
||||
|
||||
|
|
@ -54,13 +56,21 @@ class MeetingMainVoiceComponent extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
SizedBox(height: 6.h),
|
||||
Row(
|
||||
users[index].enableMicr == true
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
users[index].enableMicr == true ? 'assets/images/meeting_main_speak1.png' : 'assets/images/meeting_main_microphone_open.png',
|
||||
width: 22.w,
|
||||
height: 22.h,
|
||||
Container(
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
child: LiquidCustomProgressIndicator(
|
||||
value: users[index].volume ?? 0.0,
|
||||
valueColor: const AlwaysStoppedAnimation(ColorUtil.Color_2_177_136),
|
||||
backgroundColor: ColorUtil.Color_255_255_255,
|
||||
direction: Axis.vertical,
|
||||
shapePath: ViewSvgPath.getMicrpphonePath()
|
||||
),
|
||||
),
|
||||
Text(
|
||||
users[index].userName,
|
||||
|
|
@ -69,6 +79,23 @@ class MeetingMainVoiceComponent extends StatelessWidget {
|
|||
color: ColorUtil.Color_255_255_255),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/meeting_main_microphone_open.png',
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
),
|
||||
Text(
|
||||
users[index].userName,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_255_255_255),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
/// 计算声网SDK返回的用户音量
|
||||
class CountMicrophoneVolume {
|
||||
|
||||
static double getVolume(int volume){
|
||||
var resultVolume = 0.0;
|
||||
if(volume == 0){
|
||||
resultVolume = 0;
|
||||
}else if(volume > 0 && volume < 200){
|
||||
resultVolume = volume / 200;
|
||||
}else{
|
||||
resultVolume = 1;
|
||||
}
|
||||
return resultVolume;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 各类SVG路径
|
||||
class ViewSvgPath {
|
||||
|
||||
/// 麦克风
|
||||
static Path getMicrpphonePath(){
|
||||
Path mPath = Path();
|
||||
mPath.moveTo(10.2188, 11.875);
|
||||
mPath.cubicTo(11.9375, 11.875, 13.3438, 10.4688, 13.3438, 8.75);
|
||||
mPath.lineTo(13.3438, 5);
|
||||
mPath.cubicTo(13.3438, 3.28125, 11.9375, 1.875, 10.2188, 1.875);
|
||||
mPath.cubicTo(8.5, 1.875, 7.09375, 3.28125, 7.09375, 5);
|
||||
mPath.lineTo(7.09375, 8.75);
|
||||
mPath.cubicTo(7.09375, 10.4688, 8.5, 11.875, 10.2188, 11.875);
|
||||
|
||||
mPath.moveTo(15.777, 9.61683);
|
||||
mPath.cubicTo(15.8297, 9.27504, 15.5973, 8.95668, 15.2555, 8.90394);
|
||||
mPath.cubicTo(14.9137, 8.85316, 14.5954, 9.08558, 14.5426, 9.42543);
|
||||
mPath.cubicTo(14.2145, 11.5348, 12.3571, 13.1246, 10.2184, 13.1246);
|
||||
mPath.cubicTo(8.07973, 13.1246, 6.22035, 11.5329, 5.89418, 9.42348);
|
||||
mPath.cubicTo(5.84144, 9.08168, 5.52113, 8.84926, 5.18129, 8.90199);
|
||||
mPath.cubicTo(4.83949, 8.95473, 4.60707, 9.27308, 4.6598, 9.61488);
|
||||
mPath.cubicTo(5.05433, 12.1637, 7.08168, 14.0641, 9.5934, 14.3375);
|
||||
mPath.lineTo(9.5934, 16.2496);
|
||||
mPath.lineTo(7.7184, 16.2496);
|
||||
mPath.cubicTo(7.37269, 16.2496, 7.0934, 16.5289, 7.0934, 16.8746);
|
||||
mPath.cubicTo(7.0934, 17.2204, 7.37269, 17.4996, 7.7184, 17.4996);
|
||||
mPath.lineTo(12.7184, 17.4996);
|
||||
mPath.cubicTo(13.0641, 17.4996, 13.3434, 17.2204, 13.3434, 16.8746);
|
||||
mPath.cubicTo(13.3434, 16.5289, 13.0641, 16.2496, 12.7184, 16.2496);
|
||||
mPath.lineTo(10.8434, 16.2496);
|
||||
mPath.lineTo(10.8434, 14.3375);
|
||||
mPath.cubicTo(13.3532, 14.0641, 15.3825, 12.1657, 15.777, 9.61683);
|
||||
mPath.close();
|
||||
return mPath;
|
||||
}
|
||||
}
|
||||
|
|
@ -594,6 +594,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
liquid_progress_indicator_v2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: liquid_progress_indicator_v2
|
||||
sha256: "6bb2c675bab4936864a63ccd503be417e407974e11c62711917a4006bb9288b8"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
logger:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ dependencies:
|
|||
# .net socket通信插件
|
||||
signalr_core: ^1.1.1
|
||||
|
||||
# 水波效果的进度器
|
||||
liquid_progress_indicator_v2: ^0.5.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|
|
|||
Loading…
Reference in New Issue