1.新增一键登录
2.视频对讲优化--优化帧选择算法,缓冲区管理优化
This commit is contained in:
parent
749b79f2b1
commit
dfb368d822
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/flavors.dart';
|
||||
@ -38,6 +39,10 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
AppFirstEnterHandle().getAppFirstEnter(isAgreePrivacy);
|
||||
// 获取手机号
|
||||
if (state.isChinaUser.value) {
|
||||
// state.getPhoneNumber();
|
||||
}
|
||||
});
|
||||
// StartChartManage().init();
|
||||
}
|
||||
@ -83,193 +88,202 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
child: ListView(
|
||||
padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w),
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(10.w),
|
||||
child: Center(child: Image.asset('images/icon_main_sky_1024.png', width: 110.w, height: 110.w))),
|
||||
SizedBox(height: 50.w),
|
||||
Obx(() => CommonItem(
|
||||
leftTitel: '你所在的国家/地区'.tr,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isPadding: false,
|
||||
isHaveRightWidget: true,
|
||||
isHaveDirection: true,
|
||||
rightWidget: Text(
|
||||
'${state.countryName} +${state.countryCode.value}',
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(fontSize: 22.sp, color: AppColors.darkGrayTextColor),
|
||||
),
|
||||
action: () async {
|
||||
final result = await Get.toNamed(Routers.selectCountryRegionPage);
|
||||
if (result != null) {
|
||||
result as Map<String, dynamic>;
|
||||
state.countryCode.value = result['code'];
|
||||
state.countryKey.value = result['countryName'];
|
||||
logic.checkIpAction();
|
||||
child: state.isChinaUser.value ? _buildChinaUser() : _buildForeignUser()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChinaUser() {
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w),
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(10.w),
|
||||
alignment: Alignment.center,
|
||||
child: Column(children: [
|
||||
Image.asset('images/icon_main_sky_1024.png', width: 110.w, height: 110.w),
|
||||
SizedBox(height: 50.w),
|
||||
Text(state.emailOrPhone.value.isNotEmpty ? state.emailOrPhone.value : '获取手机号中...'),
|
||||
SizedBox(height: 50.w),
|
||||
SubmitBtn(
|
||||
btnName: '一键登录',
|
||||
fontSize: 28.sp,
|
||||
borderRadius: 20.w,
|
||||
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
|
||||
onClick: () {
|
||||
if (state.agree.value == false) {
|
||||
logic.showToast('请先同意用户协议及隐私政策'.tr);
|
||||
return;
|
||||
} else {
|
||||
logic.oneClickLoginAction(context);
|
||||
}
|
||||
},
|
||||
)),
|
||||
LoginInput(
|
||||
focusNode: logic.state.emailOrPhoneFocusNode,
|
||||
controller: state.emailOrPhoneController,
|
||||
onchangeAction: (v) {
|
||||
logic.checkNext(state.emailOrPhoneController);
|
||||
},
|
||||
leftWidget: Padding(
|
||||
padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
|
||||
child: Image.asset(
|
||||
'images/icon_login_account.png',
|
||||
width: 36.w,
|
||||
height: 36.w,
|
||||
),
|
||||
),
|
||||
hintText: '请输入手机号或者邮箱'.tr,
|
||||
// keyboardType: TextInputType.number,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
// FilteringTextInputFormatter.allow(RegExp('[0-9]')),
|
||||
LengthLimitingTextInputFormatter(30),
|
||||
FilteringTextInputFormatter.singleLineFormatter
|
||||
]),
|
||||
SizedBox(height: 10.h),
|
||||
LoginInput(
|
||||
focusNode: logic.state.pwdFocusNode,
|
||||
controller: state.pwdController,
|
||||
onchangeAction: (v) {
|
||||
logic.checkNext(state.pwdController);
|
||||
},
|
||||
isPwd: true,
|
||||
// isSuffixIcon: 2,
|
||||
leftWidget: Padding(
|
||||
padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
|
||||
child: Image.asset(
|
||||
'images/icon_login_password.png',
|
||||
width: 36.w,
|
||||
height: 36.w,
|
||||
),
|
||||
),
|
||||
hintText: '请输入密码'.tr,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
LengthLimitingTextInputFormatter(20),
|
||||
]),
|
||||
// SizedBox(height: 15.h),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Obx(() => GestureDetector(
|
||||
onTap: () {
|
||||
state.agree.value = !state.agree.value;
|
||||
logic.changeAgreeState();
|
||||
},
|
||||
child: Container(
|
||||
// color: Colors.red,
|
||||
padding: EdgeInsets.only(left: 5.w, top: 20.w, right: 10.w, bottom: 20.h),
|
||||
child: Image.asset(
|
||||
state.agree.value ? 'images/icon_round_select.png' : 'images/icon_round_unSelect.png',
|
||||
width: 35.w,
|
||||
height: 35.w,
|
||||
),
|
||||
))),
|
||||
// SizedBox(
|
||||
// width: 5.w,
|
||||
// ),
|
||||
Flexible(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: '我已阅读并同意'.tr,
|
||||
style: TextStyle(color: const Color(0xff333333), fontSize: 20.sp),
|
||||
children: <InlineSpan>[
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: GestureDetector(
|
||||
child:
|
||||
Text('《${'用户协议'.tr}》', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
|
||||
onTap: () {
|
||||
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
|
||||
'url': XSConstantMacro.userAgreementURL,
|
||||
'title': '用户协议'.tr
|
||||
});
|
||||
},
|
||||
)),
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: GestureDetector(
|
||||
child:
|
||||
Text('《${'隐私政策'.tr}》', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
|
||||
onTap: () {
|
||||
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
|
||||
'url': XSConstantMacro.privacyPolicyURL,
|
||||
'title': '隐私政策'.tr
|
||||
});
|
||||
},
|
||||
)),
|
||||
],
|
||||
)),
|
||||
)
|
||||
],
|
||||
}),
|
||||
SizedBox(height: 50.w),
|
||||
_agreentWidget(),
|
||||
]))
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _buildForeignUser() {
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w),
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(10.w),
|
||||
child: Center(child: Image.asset('images/icon_main_sky_1024.png', width: 110.w, height: 110.w))),
|
||||
SizedBox(height: 50.w),
|
||||
Obx(() => CommonItem(
|
||||
leftTitel: '你所在的国家/地区'.tr,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isPadding: false,
|
||||
isHaveRightWidget: true,
|
||||
isHaveDirection: true,
|
||||
rightWidget: Text(
|
||||
'${state.countryName} +${state.countryCode.value}',
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(fontSize: 22.sp, color: AppColors.darkGrayTextColor),
|
||||
),
|
||||
action: () async {
|
||||
final result = await Get.toNamed(Routers.selectCountryRegionPage);
|
||||
if (result != null) {
|
||||
result as Map<String, dynamic>;
|
||||
state.countryCode.value = result['code'];
|
||||
state.countryKey.value = result['countryName'];
|
||||
logic.checkIpAction();
|
||||
}
|
||||
},
|
||||
)),
|
||||
LoginInput(
|
||||
focusNode: logic.state.emailOrPhoneFocusNode,
|
||||
controller: state.emailOrPhoneController,
|
||||
onchangeAction: (v) {
|
||||
logic.checkNext(state.emailOrPhoneController);
|
||||
},
|
||||
leftWidget: Padding(
|
||||
padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
|
||||
child: Image.asset(
|
||||
'images/icon_login_account.png',
|
||||
width: 36.w,
|
||||
height: 36.w,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 50.w),
|
||||
Obx(() => SubmitBtn(
|
||||
btnName: '登录'.tr,
|
||||
fontSize: 28.sp,
|
||||
borderRadius: 20.w,
|
||||
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
|
||||
isDisabled: state.canNext.value,
|
||||
onClick: state.canNext.value
|
||||
? () {
|
||||
if (state.agree.value == false) {
|
||||
logic.showToast('请先同意用户协议及隐私政策'.tr);
|
||||
return;
|
||||
} else {
|
||||
logic.login();
|
||||
}
|
||||
}
|
||||
: null)),
|
||||
// SizedBox(height: 20.w),
|
||||
// Obx(() => Visibility(
|
||||
// visible: state.isCheckVerifyEnable.value,
|
||||
// child: SubmitBtn(
|
||||
// btnName: '一键登录',
|
||||
// fontSize: 28.sp,
|
||||
// borderRadius: 20.w,
|
||||
// padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
|
||||
// // isDisabled: state.canNext.value,
|
||||
// onClick: () {
|
||||
// if (state.agree.value == false) {
|
||||
// logic.showToast('请先同意用户协议及隐私政策'.tr);
|
||||
// return;
|
||||
// } else {
|
||||
// logic.oneClickLoginAction();
|
||||
// }
|
||||
// }),
|
||||
// )),
|
||||
SizedBox(height: 50.w),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
child: SizedBox(
|
||||
// width: 150.w,
|
||||
height: 50.h,
|
||||
// color: Colors.red,
|
||||
child: Center(
|
||||
child: Text('${'忘记密码'.tr}?', style: TextStyle(fontSize: 22.sp, color: AppColors.mainColor)),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, Routers.starLockForgetPasswordPage);
|
||||
},
|
||||
hintText: '请输入邮箱'.tr,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
LengthLimitingTextInputFormatter(30),
|
||||
FilteringTextInputFormatter.singleLineFormatter
|
||||
]),
|
||||
SizedBox(height: 10.h),
|
||||
LoginInput(
|
||||
focusNode: logic.state.pwdFocusNode,
|
||||
controller: state.pwdController,
|
||||
onchangeAction: (v) {
|
||||
logic.checkNext(state.pwdController);
|
||||
},
|
||||
isPwd: true,
|
||||
leftWidget: Padding(
|
||||
padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
|
||||
child: Image.asset(
|
||||
'images/icon_login_password.png',
|
||||
width: 36.w,
|
||||
height: 36.w,
|
||||
),
|
||||
),
|
||||
hintText: '请输入密码'.tr,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
LengthLimitingTextInputFormatter(20),
|
||||
]),
|
||||
SizedBox(height: 50.w),
|
||||
Obx(() => SubmitBtn(
|
||||
btnName: '登录'.tr,
|
||||
fontSize: 28.sp,
|
||||
borderRadius: 20.w,
|
||||
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
|
||||
isDisabled: state.canNext.value,
|
||||
onClick: state.canNext.value
|
||||
? () {
|
||||
if (state.agree.value == false) {
|
||||
logic.showToast('请先同意用户协议及隐私政策'.tr);
|
||||
return;
|
||||
} else {
|
||||
logic.login();
|
||||
}
|
||||
} : null)),
|
||||
SizedBox(height: 20.w),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
child: SizedBox(
|
||||
// width: 150.w,
|
||||
height: 50.h,
|
||||
// color: Colors.red,
|
||||
child: Center(
|
||||
child: Text('${'忘记密码'.tr}?', style: TextStyle(fontSize: 22.sp, color: AppColors.mainColor)),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, Routers.starLockForgetPasswordPage);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _agreentWidget() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Obx(() => GestureDetector(
|
||||
onTap: () {
|
||||
state.agree.value = !state.agree.value;
|
||||
logic.changeAgreeState();
|
||||
},
|
||||
child: Container(
|
||||
// color: Colors.red,
|
||||
padding: EdgeInsets.only(left: 5.w, top: 20.w, right: 10.w, bottom: 20.h),
|
||||
child: Image.asset(
|
||||
state.agree.value ? 'images/icon_round_select.png' : 'images/icon_round_unSelect.png',
|
||||
width: 35.w,
|
||||
height: 35.w,
|
||||
),
|
||||
))),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: '我已阅读并同意'.tr,
|
||||
style: TextStyle(color: const Color(0xff333333), fontSize: 20.sp),
|
||||
children: <InlineSpan>[
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: GestureDetector(
|
||||
child:
|
||||
Text('《${'用户协议'.tr}》', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
|
||||
onTap: () {
|
||||
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
|
||||
'url': XSConstantMacro.userAgreementURL,
|
||||
'title': '用户协议'.tr
|
||||
});
|
||||
},
|
||||
)),
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: GestureDetector(
|
||||
child:
|
||||
Text('《${'隐私政策'.tr}》', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
|
||||
onTap: () {
|
||||
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
|
||||
'url': XSConstantMacro.privacyPolicyURL,
|
||||
'title': '隐私政策'.tr
|
||||
});
|
||||
},
|
||||
)),
|
||||
],
|
||||
)),
|
||||
]);
|
||||
}
|
||||
|
||||
Widget loginInput(
|
||||
{TextEditingController? controller,
|
||||
List<TextInputFormatter>? inputFormatters,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../app_settings/app_settings.dart';
|
||||
import '../../tools/jverify_one_click_login.dart';
|
||||
import '../../translations/current_locale_tool.dart';
|
||||
|
||||
class StarLockLoginState {
|
||||
@ -14,6 +15,11 @@ class StarLockLoginState {
|
||||
RxString countryCode = '86'.obs;
|
||||
RxString countryKey = '中国'.tr.obs;
|
||||
|
||||
// 是否为中国用户
|
||||
final RxBool isChinaUser = false.obs;
|
||||
// 是否显示一键登录
|
||||
final RxBool showOneClickLogin = false.obs;
|
||||
|
||||
/// 获取翻译后的国家名称
|
||||
String get countryName => countryKey.value.tr;
|
||||
|
||||
|
||||
@ -689,18 +689,35 @@ class LockDetailLogic extends BaseGetXController {
|
||||
|
||||
// 远程开锁
|
||||
Future<void> remoteOpenLock() async {
|
||||
final catEyeConfig = state.keyInfos.value.lockSetting?.catEyeConfig ?? [];
|
||||
// 支持猫眼功能时,才需要判断是否是省电模式
|
||||
if (state.keyInfos.value.lockFeature?.isSupportCatEye == 1 && catEyeConfig[0].catEyeMode == 0) {
|
||||
showToast('猫眼设置为省电模式时无法进行远程开锁,请在猫眼设置中切换为其他模式'.tr);
|
||||
return;
|
||||
final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
|
||||
|
||||
var lockId = currentKeyInfo.lockId ?? 0;
|
||||
var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0;
|
||||
|
||||
final lockPeerId = StartChartManage().lockPeerId;
|
||||
final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
|
||||
if (lockListInfoGroupEntity != null) {
|
||||
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
||||
final lockList = element.lockList;
|
||||
if (lockList != null && lockList.length != 0) {
|
||||
for (var lockInfo in lockList) {
|
||||
final peerId = lockInfo.network?.peerId;
|
||||
if (peerId != null && peerId != '') {
|
||||
if (peerId == lockPeerId) {
|
||||
lockId = lockInfo.lockId ?? 0;
|
||||
remoteUnlock = lockInfo.lockSetting?.remoteUnlock ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
final LoginEntity entity = await ApiRepository.to.remoteOpenLock(
|
||||
lockId: state.keyInfos.value.lockId.toString(),
|
||||
timeOut: 60,
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
showToast('已开锁'.tr);
|
||||
if (remoteUnlock == 1) {
|
||||
final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
showToast('已开锁'.tr);
|
||||
StartChartManage().lockListPeerId = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -849,8 +866,6 @@ class LockDetailLogic extends BaseGetXController {
|
||||
showToast('设备未配网'.tr);
|
||||
return;
|
||||
}
|
||||
// 启动监控时禁用铃声
|
||||
AudioPlayerManager().disableRingtone();
|
||||
// 重置丢包率监控
|
||||
// PacketLossStatistics().reset();
|
||||
// 发送监控id
|
||||
|
||||
@ -41,20 +41,8 @@ class SelectLockTypeLogic extends BaseGetXController {
|
||||
if (!Platform.isIOS) {
|
||||
final bool locationRequest = await PermissionDialog.request(Permission.location);
|
||||
final bool bluetoothRequest = await PermissionDialog.requestBluetooth();
|
||||
// 添加存储权限请求(相册权限)
|
||||
final bool storageRequest = await PermissionDialog.request(Permission.storage);
|
||||
|
||||
bool isHarmonyOS = await checkIfHarmonyOS();
|
||||
// 鸿蒙系统
|
||||
if(isHarmonyOS){
|
||||
print('鸿蒙手机提示----');
|
||||
if (!bluetoothRequest || !locationRequest || !storageRequest) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!bluetoothRequest || !locationRequest) {
|
||||
return;
|
||||
}
|
||||
if (!bluetoothRequest || !locationRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -193,34 +193,10 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 30.sp)),
|
||||
// 点击多选可以进行删除
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// // 没有多选删除的 api接口,无法使用
|
||||
// // if (_showCheckboxes.value) {
|
||||
// // deleteSelectedMessages();
|
||||
// // } else {
|
||||
// // setState(() {
|
||||
// // _showCheckboxes.value =
|
||||
// // !_showCheckboxes.value;
|
||||
// // });
|
||||
// // }
|
||||
// },
|
||||
// child: _showCheckboxes.value
|
||||
// ? Text('删除',
|
||||
// style: TextStyle(
|
||||
// fontSize: 24.sp,
|
||||
// color: Colors.red))
|
||||
// : Image.asset(
|
||||
// 'images/mine/icon_message_checbox.png',
|
||||
// width: 30.w,
|
||||
// height: 30.h),
|
||||
// )
|
||||
]),
|
||||
)
|
||||
]))),
|
||||
Container(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
top: showNotificationBanner ? 80 : 50),
|
||||
child: ListView.builder(
|
||||
@ -270,7 +246,6 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
})),
|
||||
@ -342,7 +317,7 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
if (!isLastInGroupSimple)
|
||||
Container(
|
||||
width: 0.5,
|
||||
height: 190.h,
|
||||
height: 120.h,
|
||||
color: AppColors.placeholderTextColor,
|
||||
)
|
||||
],
|
||||
@ -370,7 +345,7 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
],
|
||||
), child: Container(
|
||||
width: 1.sw,
|
||||
margin: EdgeInsets.all(20.h),
|
||||
margin: EdgeInsets.all(10.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10.w),
|
||||
@ -381,42 +356,8 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
// SizedBox(height: 4.h),
|
||||
// Row(
|
||||
// children: <Widget>[
|
||||
// Flexible(
|
||||
// child: Text(
|
||||
// // 调用请求标题
|
||||
// '远程开门请求',
|
||||
// maxLines: 1,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// style: TextStyle(
|
||||
// fontSize: 22.sp,
|
||||
// color: messageItemEntity.readAt! == 0
|
||||
// ? AppColors.blackColor
|
||||
// : AppColors.placeholderTextColor),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// SizedBox(height: 4.h),
|
||||
Wrap(
|
||||
children: <Widget>[
|
||||
// if (messageItemEntity.readAt! == 0)
|
||||
// Container(
|
||||
// width: 10.w,
|
||||
// height: 10.w,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.red,
|
||||
// borderRadius: BorderRadius.circular(5.w),
|
||||
// ),
|
||||
// )
|
||||
// else
|
||||
// Container(),
|
||||
// if (messageItemEntity.readAt! == 0)
|
||||
// SizedBox(width: 5.w)
|
||||
// else
|
||||
// Container(),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 4.h),
|
||||
child: Text(
|
||||
@ -437,7 +378,7 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
? AppColors.blackColor
|
||||
: AppColors.placeholderTextColor,
|
||||
),
|
||||
Container(transform: Matrix4.translationValues(0, -18, 0),
|
||||
Container(transform: Matrix4.translationValues(0, -22, 0),
|
||||
child: Text(' ${messageItemEntity.data!}',
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@ -453,24 +394,6 @@ class _MessageListPageState extends State<MessageListPage>
|
||||
),alignment: Alignment.centerRight,)
|
||||
],
|
||||
),
|
||||
// SizedBox(height: 5.h),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: <Widget>[
|
||||
// // Image.asset('images/mine/icon_mine_gatewaySignal_strong.png', width: 40.w, height: 40.w,),
|
||||
// // SizedBox(width: 10.w,),
|
||||
// Text(
|
||||
// DateTool().dateToHnString(messageItemEntity
|
||||
// .createdAt!
|
||||
// .toString()),
|
||||
// style: TextStyle(
|
||||
// fontSize: 18.sp,
|
||||
// color: messageItemEntity.readAt! == 0
|
||||
// ? AppColors.blackColor
|
||||
// : AppColors.placeholderTextColor)),
|
||||
// ],
|
||||
// ),
|
||||
// SizedBox(width: 20.h),
|
||||
]))))),
|
||||
// 显示选中状态的复选框
|
||||
if (_showCheckboxes.value)
|
||||
|
||||
@ -41,6 +41,33 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
|
||||
final LockDetailState lockDetailState = Get.put(LockDetailLogic()).state;
|
||||
|
||||
// 添加成员变量缓存帧索引
|
||||
final Map<TalkDataH264Frame_FrameTypeE, List<MapEntry<int, int>>> _frameIndexCache = {};
|
||||
bool _frameIndexDirty = true;
|
||||
// 更新帧缓冲区时标记索引为脏数据
|
||||
void _invalidateFrameIndex() {
|
||||
_frameIndexDirty = true;
|
||||
}
|
||||
// 构建帧索引
|
||||
List<MapEntry<int, int>> _buildFrameIndex(TalkDataH264Frame_FrameTypeE frameType) {
|
||||
if (!_frameIndexDirty && _frameIndexCache.containsKey(frameType)) {
|
||||
return _frameIndexCache[frameType]!;
|
||||
}
|
||||
|
||||
final List<MapEntry<int, int>> index = [];
|
||||
for (int i = 0; i < state.h264FrameBuffer.length; i++) {
|
||||
final frame = state.h264FrameBuffer[i];
|
||||
if (frame['frameType'] == frameType) {
|
||||
index.add(MapEntry(frame['frameSeq'] as int, i));
|
||||
}
|
||||
}
|
||||
index.sort((a, b) => a.key.compareTo(b.key));
|
||||
|
||||
_frameIndexCache[frameType] = index;
|
||||
_frameIndexDirty = false;
|
||||
return index;
|
||||
}
|
||||
|
||||
// 添加网络质量评估变量
|
||||
int _networkQualityScore = 5; // 1-5分,5为最佳
|
||||
int _frameDropCount = 0;
|
||||
@ -296,7 +323,13 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
VideoDecodePlugin.setOnFrameRenderedListener((textureId) {
|
||||
AppLog.log('已经开始渲染=======');
|
||||
// 只有真正渲染出首帧时才关闭loading
|
||||
Future.microtask(() => state.isLoading.value = false);
|
||||
Future.microtask(() {
|
||||
state.isLoading.value = false;
|
||||
// 添加停止动画的代码
|
||||
if (state.animationController.isAnimating) {
|
||||
state.animationController.stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
AppLog.log('视频解码器初始化失败或超时, 耗时: ${duration}ms');
|
||||
@ -432,6 +465,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
|
||||
// 将帧添加到缓冲区
|
||||
state.h264FrameBuffer.add(frameMap);
|
||||
_invalidateFrameIndex();
|
||||
}
|
||||
|
||||
/// 启动帧处理定时器
|
||||
@ -494,11 +528,43 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
} else {
|
||||
// 新帧是P帧或B帧,移除最旧的帧
|
||||
state.h264FrameBuffer.removeAt(0);
|
||||
_invalidateFrameIndex();
|
||||
}
|
||||
}
|
||||
|
||||
int _findEarliestIFrame() {
|
||||
final iFrameIndexes = _buildFrameIndex(TalkDataH264Frame_FrameTypeE.I);
|
||||
return iFrameIndexes.isNotEmpty ? iFrameIndexes.first.value : -1;
|
||||
}
|
||||
|
||||
int _findRelatedPFrame(int refIFrameSeq) {
|
||||
final pFrameIndexes = _buildFrameIndex(TalkDataH264Frame_FrameTypeE.P);
|
||||
for (final entry in pFrameIndexes) {
|
||||
final frame = state.h264FrameBuffer[entry.value];
|
||||
if (frame['frameSeqI'] == refIFrameSeq) {
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int _findBestFrameIndex() {
|
||||
// 优先处理与最近解码的I帧相关的P帧
|
||||
if (lastDecodedIFrameSeq != null) {
|
||||
final pFrameIndex = _findRelatedPFrame(lastDecodedIFrameSeq!);
|
||||
if (pFrameIndex >= 0) return pFrameIndex;
|
||||
}
|
||||
|
||||
// 查找最早的I帧
|
||||
final iFrameIndex = _findEarliestIFrame();
|
||||
if (iFrameIndex >= 0) return iFrameIndex;
|
||||
|
||||
// 如果没有I帧,处理最早的帧
|
||||
return state.h264FrameBuffer.isNotEmpty ? 0 : -1;
|
||||
}
|
||||
|
||||
/// 从缓冲区处理下一帧
|
||||
void _processNextFrameFromBuffer() async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
_monitorFrameProcessingPerformance();
|
||||
final startTime = DateTime.now().microsecondsSinceEpoch;
|
||||
|
||||
@ -543,63 +609,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
}
|
||||
}
|
||||
|
||||
// 查找最适合处理的帧 -- 优先处理I帧以加速首帧显示
|
||||
int frameIndex = -1;
|
||||
// 首先查找最早的I帧
|
||||
final iFrames = state.h264FrameBuffer
|
||||
.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I)
|
||||
.toList()
|
||||
..sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
||||
|
||||
if (iFrames.isNotEmpty) {
|
||||
final minIFrame = iFrames.first;
|
||||
frameIndex = state.h264FrameBuffer.indexWhere(
|
||||
(f) =>
|
||||
f['frameType'] == TalkDataH264Frame_FrameTypeE.I &&
|
||||
f['frameSeq'] == minIFrame['frameSeq'],
|
||||
);
|
||||
} else {
|
||||
// 如果没有I帧,处理最早的帧
|
||||
frameIndex = 0;
|
||||
}
|
||||
|
||||
// 优先处理与最近解码的I帧相关的P帧
|
||||
if (lastDecodedIFrameSeq != null) {
|
||||
// 查找与上一个I帧关联的P帧(按顺序)
|
||||
final validPFrames = state.h264FrameBuffer
|
||||
.where((f) =>
|
||||
f['frameType'] == TalkDataH264Frame_FrameTypeE.P &&
|
||||
f['frameSeqI'] == lastDecodedIFrameSeq)
|
||||
.toList()
|
||||
..sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
||||
|
||||
if (validPFrames.isNotEmpty) {
|
||||
final minPFrame = validPFrames.first;
|
||||
frameIndex = state.h264FrameBuffer.indexWhere(
|
||||
(f) =>
|
||||
f['frameType'] == TalkDataH264Frame_FrameTypeE.P &&
|
||||
f['frameSeq'] == minPFrame['frameSeq'] &&
|
||||
f['frameSeqI'] == lastDecodedIFrameSeq,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到相关的P帧,查找最早的I帧
|
||||
if (frameIndex == -1) {
|
||||
final iFrames = state.h264FrameBuffer
|
||||
.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I)
|
||||
.toList()
|
||||
..sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
||||
|
||||
if (iFrames.isNotEmpty) {
|
||||
final minIFrame = iFrames.first;
|
||||
frameIndex = state.h264FrameBuffer.indexWhere(
|
||||
(f) =>
|
||||
f['frameType'] == TalkDataH264Frame_FrameTypeE.I &&
|
||||
f['frameSeq'] == minIFrame['frameSeq'],
|
||||
);
|
||||
}
|
||||
}
|
||||
//减少重复计算和排序操作
|
||||
final frameIndex = _findBestFrameIndex();
|
||||
|
||||
// 处理选中的帧
|
||||
if (frameIndex >= 0) {
|
||||
@ -657,6 +668,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
AppLog.log('帧处理耗时过长: ${durationMs.toStringAsFixed(2)} ms, 缓冲区长度: ${state.h264FrameBuffer.length}');
|
||||
}
|
||||
}
|
||||
stopwatch.stop();
|
||||
print('执行耗时: ${stopwatch.elapsedMilliseconds} 毫秒');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,21 +10,21 @@ import '../app_settings/app_settings.dart';
|
||||
import '../common/XSConstantMacro/XSConstantMacro.dart';
|
||||
import '../flavors.dart';
|
||||
|
||||
|
||||
class JverifyOneClickLoginManage {
|
||||
factory JverifyOneClickLoginManage() => shareManager()!;
|
||||
factory JverifyOneClickLoginManage() => _getInstance()!;
|
||||
|
||||
JverifyOneClickLoginManage._init() {
|
||||
_initSDK();
|
||||
JverifyOneClickLoginManage._init() {}
|
||||
|
||||
static JverifyOneClickLoginManage get instance => _getInstance();
|
||||
static JverifyOneClickLoginManage? _instance;
|
||||
|
||||
static JverifyOneClickLoginManage _getInstance() {
|
||||
_instance ??= JverifyOneClickLoginManage._init();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
static JverifyOneClickLoginManage? _manager;
|
||||
|
||||
static JverifyOneClickLoginManage? shareManager() {
|
||||
_manager ??= JverifyOneClickLoginManage._init();
|
||||
return _manager;
|
||||
}
|
||||
|
||||
JverifyOneClickLoginManage? get manager => shareManager();
|
||||
JverifyOneClickLoginManage? get manager => _getInstance();
|
||||
Jverify jverify = Jverify();
|
||||
|
||||
/// 统一 key
|
||||
@ -39,106 +39,102 @@ class JverifyOneClickLoginManage {
|
||||
/// 运营商信息
|
||||
String f_opr_key = 'operator';
|
||||
|
||||
Future<void> _initSDK() async {
|
||||
Future<void> initSDK({Function? onSuccess, Function? onFailure}) async {
|
||||
try {
|
||||
await initPlatformState();
|
||||
// 初始化 SDK 之前添加监听
|
||||
jverify.addSDKSetupCallBackListener((JVSDKSetupEvent event) {
|
||||
print('receive sdk setup call back event :${event.toMap()}');
|
||||
if (event.code == 8000) {
|
||||
onSuccess?.call();
|
||||
} else {
|
||||
onFailure?.call();
|
||||
}
|
||||
});
|
||||
|
||||
isInitSuccess();
|
||||
jverify.setDebugMode(true); // 打开调试模式
|
||||
jverify.setCollectionAuth(true);
|
||||
String appKey;
|
||||
if (F.isSKY) {
|
||||
appKey = '7ff37d174c1a568a89e98dad';
|
||||
AppLog.log('appKey:7ff37d174c1a568a89e98dad');
|
||||
} else {
|
||||
appKey = '251fc8074820d122b6de58d2';
|
||||
AppLog.log('appKey:251fc8074820d122b6de58d2');
|
||||
}
|
||||
jverify.setup(
|
||||
appKey: appKey, //"你自己应用的 AppKey",
|
||||
channel: 'devloper');
|
||||
|
||||
getToken();
|
||||
/// 授权页面点击时间监听
|
||||
jverify.addAuthPageEventListener((JVAuthPageEvent event) {
|
||||
print('receive auth page event :${event.toMap()}');
|
||||
});
|
||||
|
||||
preLogin();
|
||||
// isInitSuccess();
|
||||
|
||||
// getToken();
|
||||
|
||||
// preLogin();
|
||||
} catch (e) {
|
||||
AppLog.log('SDK 初始化错误: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> initPlatformState() async {
|
||||
// 初始化 SDK 之前添加监听
|
||||
jverify.addSDKSetupCallBackListener((JVSDKSetupEvent event) {
|
||||
print('receive sdk setup call back event :${event.toMap()}');
|
||||
});
|
||||
|
||||
jverify.setDebugMode(true); // 打开调试模式
|
||||
jverify.setCollectionAuth(true);
|
||||
String appKey;
|
||||
if (F.isSKY) {
|
||||
appKey = '7ff37d174c1a568a89e98dad';
|
||||
AppLog.log('appKey:7ff37d174c1a568a89e98dad');
|
||||
} else {
|
||||
appKey = '251fc8074820d122b6de58d2';
|
||||
AppLog.log('appKey:251fc8074820d122b6de58d2');
|
||||
}
|
||||
jverify.setup(
|
||||
appKey: appKey, //"你自己应用的 AppKey",
|
||||
channel: 'devloper');
|
||||
|
||||
/// 授权页面点击时间监听
|
||||
jverify.addAuthPageEventListener((JVAuthPageEvent event) {
|
||||
print('receive auth page event :${event.toMap()}');
|
||||
});
|
||||
}
|
||||
|
||||
/// sdk 初始化是否完成
|
||||
void isInitSuccess() {
|
||||
jverify.isInitSuccess().then((map) {
|
||||
final bool result = map[f_result_key];
|
||||
AppLog.log('sdk 初始化结果:$map');
|
||||
if (result) {
|
||||
AppLog.log('sdk 初始化成功');
|
||||
} else {
|
||||
AppLog.log('sdk 初始化失败');
|
||||
}
|
||||
});
|
||||
Future<bool> isInitSuccess() async {
|
||||
final Map<dynamic, dynamic> map = await jverify.isInitSuccess();
|
||||
final bool result = map[f_result_key];
|
||||
AppLog.log('sdk 初始化结果:$map');
|
||||
if (result) {
|
||||
AppLog.log('sdk 初始化成功');
|
||||
} else {
|
||||
AppLog.log('sdk 初始化失败');
|
||||
}
|
||||
return Future.value(result);
|
||||
}
|
||||
|
||||
/// 判断当前网络环境是否可以发起认证
|
||||
Future<bool> checkVerifyEnable() async {
|
||||
final isInitSuccess = await this.isInitSuccess();
|
||||
if (!isInitSuccess) {
|
||||
return false;
|
||||
}
|
||||
final Map map = await jverify.checkVerifyEnable();
|
||||
AppLog.log('一家登录 sdk 初始化结果:$map');
|
||||
print('一家登录 sdk 初始化结果:$map');
|
||||
final bool result = map[f_result_key];
|
||||
return result;
|
||||
// state.jverify.checkVerifyEnable().then((map) {
|
||||
// final bool result = map[f_result_key];
|
||||
// if (result) {
|
||||
// AppLog.log('当前网络环境【支持认证】!');
|
||||
// } else {
|
||||
// AppLog.log('当前网络环境【不支持认证】!');
|
||||
// }
|
||||
// return result;
|
||||
// });
|
||||
}
|
||||
|
||||
void getToken() {
|
||||
jverify.checkVerifyEnable().then((map) {
|
||||
final bool result = map[f_result_key];
|
||||
if (result) {
|
||||
jverify.getToken().then((map) {
|
||||
final int code = map[f_code_key];
|
||||
final String token = map[f_msg_key];
|
||||
final String operator = map[f_opr_key];
|
||||
AppLog.log('getToken code:$code token:$token operator:$operator');
|
||||
});
|
||||
} else {
|
||||
AppLog.log('[2016],msg = 当前网络环境不支持认证');
|
||||
}
|
||||
});
|
||||
}
|
||||
// void getToken() {
|
||||
// jverify.checkVerifyEnable().then((map) {
|
||||
// final bool result = map[f_result_key];
|
||||
// if (result) {
|
||||
// jverify.getToken().then((map) {
|
||||
// final int code = map[f_code_key];
|
||||
// final String token = map[f_msg_key];
|
||||
// final String operator = map[f_opr_key];
|
||||
// AppLog.log('getToken code:$code token:$token operator:$operator');
|
||||
// });
|
||||
// } else {
|
||||
// AppLog.log('[2016],msg = 当前网络环境不支持认证');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
/// 登录预取号
|
||||
void preLogin() {
|
||||
jverify.checkVerifyEnable().then((map) {
|
||||
final bool result = map[f_result_key];
|
||||
if (result) {
|
||||
jverify.preLogin().then((map) {
|
||||
AppLog.log('预取号接口回调:${map.toString()}');
|
||||
final int code = map[f_code_key];
|
||||
final String message = map[f_msg_key];
|
||||
});
|
||||
} else {
|
||||
AppLog.log('[2016],msg = 当前网络环境不支持认证');
|
||||
}
|
||||
});
|
||||
Future<bool> preLogin() async {
|
||||
final networkSupportVerify = await this.checkVerifyEnable();
|
||||
if (!networkSupportVerify) {
|
||||
return false;
|
||||
}
|
||||
final Map map = await jverify.preLogin();
|
||||
final int code = map[f_code_key];
|
||||
final String message = map[f_msg_key];
|
||||
if (code > 0) {
|
||||
return true;
|
||||
}
|
||||
AppLog.log('[2016],msg = 当前网络环境不支持认证');
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SDK 请求授权一键登录
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user