From 04d17f6483a98e2527deecc8d8b4fc9cf96c904c Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 21 Mar 2024 09:44:03 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=A8=8B=E5=BA=8F=E5=8F=AA=E4=BC=9A=E5=9C=A8?= =?UTF-8?q?=E9=A6=96=E6=AC=A1=E5=AE=89=E8=A3=85=E6=97=B6=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/versionUndate/versionUndateTool.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/star_lock/lib/versionUndate/versionUndateTool.dart b/star_lock/lib/versionUndate/versionUndateTool.dart index 9eafd463..5db662de 100644 --- a/star_lock/lib/versionUndate/versionUndateTool.dart +++ b/star_lock/lib/versionUndate/versionUndateTool.dart @@ -101,8 +101,8 @@ class VersionUndateTool { child: Text("下次再说"), onPressed: () { Navigator.pop(context); - Storage.setString( - isShowUpdateVersion, isShowUpdateVersion); + // Storage.setString( + // isShowUpdateVersion, isShowUpdateVersion); }, ), CupertinoDialogAction( From d9e93fbdeafd5d1108201b739bb66be50eeeb43f Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 21 Mar 2024 11:36:48 +0800 Subject: [PATCH 2/9] =?UTF-8?q?1=EF=BC=8C=E9=94=81=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=96=B0=E5=A2=9E=E6=9D=83=E9=99=90=E5=A4=84?= =?UTF-8?q?=E7=90=86=202=EF=BC=8C=E5=A4=B4=E5=83=8F=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=A4=84=E7=90=86=EF=BC=88=E5=BE=85=E5=AE=8C=E5=96=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lockDetail/lockDetail_logic.dart | 55 ++- .../lockDetail/lockDetail_page.dart | 370 ++++++++++-------- .../lockDetail/lockDetail_state.dart | 2 + .../minePersonInfo_page.dart | 65 +-- 4 files changed, 293 insertions(+), 199 deletions(-) diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index 6f46c4cb..c6c3274f 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -8,6 +8,7 @@ import 'package:intl/intl.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/keyOperationRecord/keyOperationRecord_entity.dart'; +import 'package:star_lock/tools/appFirstEnterHandle.dart'; import '../../../blue/blue_manage.dart'; import '../../../blue/io_protocol/io_addUser.dart'; @@ -50,7 +51,8 @@ class LockDetailLogic extends BaseGetXController { // } // 开完锁之后上传记录 - if (reply is SenderReferEventRecordTimeReply && state.ifCurrentScreen.value == true) { + if (reply is SenderReferEventRecordTimeReply && + state.ifCurrentScreen.value == true) { _replyReferEventRecordTime(reply); } @@ -73,7 +75,7 @@ class LockDetailLogic extends BaseGetXController { // _showFullScreenOverlay(Get.context!); state.iSClosedUnlockSuccessfulPopup.value = true; - if (state.closedUnlockSuccessfulTimer != null ) { + if (state.closedUnlockSuccessfulTimer != null) { state.closedUnlockSuccessfulTimer!.cancel(); state.closedUnlockSuccessfulTimer = null; } @@ -379,7 +381,8 @@ class LockDetailLogic extends BaseGetXController { eventBus.fire(RefreshLockDetailInfoDataEvent()); }); - BlueManage().bludSendData(state.keyInfos.value.bluetooth!.bluetoothDeviceName!, + BlueManage() + .bludSendData(state.keyInfos.value.bluetooth!.bluetoothDeviceName!, (BluetoothConnectionState deviceConnectionState) async { if (deviceConnectionState == BluetoothConnectionState.connected) { // 私钥 @@ -411,7 +414,8 @@ class LockDetailLogic extends BaseGetXController { publicKey: publicKeyDataList, privateKey: getPrivateKeyList, token: getTokenList); - } else if (deviceConnectionState == BluetoothConnectionState.disconnected) { + } else if (deviceConnectionState == + BluetoothConnectionState.disconnected) { cancelBlueConnetctToastTimer(); if (state.ifCurrentScreen.value == true) { showBlueConnetctToast(); @@ -466,7 +470,8 @@ class LockDetailLogic extends BaseGetXController { signKey: signKeyDataList, privateKey: getPrivateKeyList, ); - } else if (deviceConnectionState == BluetoothConnectionState.disconnected) { + } else if (deviceConnectionState == + BluetoothConnectionState.disconnected) { cancelBlueConnetctToastTimer(); if (state.ifCurrentScreen.value == true) { showBlueConnetctToast(); @@ -698,17 +703,21 @@ class LockDetailLogic extends BaseGetXController { _lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent; void _initLockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceAction() { // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus - _lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent = eventBus.on().listen((event) { + _lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent = eventBus + .on() + .listen((event) { if (event.type == 0) { // 0考勤 state.isAttendance.value = int.parse(event.setResult); - state.keyInfos.value.lockSetting!.attendance = int.parse(event.setResult); + state.keyInfos.value.lockSetting!.attendance = + int.parse(event.setResult); } else if (event.type == 1) { // 1 开锁时是否需联网 state.isOpenLockNeedOnline.value = int.parse(event.setResult); state.keyInfos.value.lockSetting!.appUnlockOnline = int.parse(event.setResult); - print("state.isOpenLockNeedOnline.value:${state.isOpenLockNeedOnline.value}"); + print( + "state.isOpenLockNeedOnline.value:${state.isOpenLockNeedOnline.value}"); } else if (event.type == 2) { // 2 常开模式 state.isOpenPassageMode.value = int.parse(event.setResult); @@ -726,19 +735,20 @@ class LockDetailLogic extends BaseGetXController { }); } - String getKeyStatusTextAndShow(){ + String getKeyStatusTextAndShow() { String text = ""; - if (state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusWaitIneffective || + if (state.keyInfos.value.keyStatus == + XSConstantMacro.keyStatusWaitIneffective || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusFrozen || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusExpired || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusDeleted || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusReset) { - text = "你的钥匙${XSConstantMacro.getKeyStatusStr(state.keyInfos.value.keyStatus!)}"; + text = + "你的钥匙${XSConstantMacro.getKeyStatusStr(state.keyInfos.value.keyStatus!)}"; } else { text = state.isOpenPassageMode.value == 1 ? "常开模式启动!长按闭锁" - : TranslationLoader - .lanKeys!.clickUnlockAndHoldDownClose!.tr; + : TranslationLoader.lanKeys!.clickUnlockAndHoldDownClose!.tr; } return text; } @@ -826,6 +836,20 @@ class LockDetailLogic extends BaseGetXController { return formattedTime; } + Future positionPermissionAlert() async { + //安卓平台下首次进入应用需向用户告知获取权限用途弹窗 + if (Platform.isAndroid) { + AppFirstEnterHandle() + .getAppFirstEnter(state.widgetContext, isAgreePosition); + var getFlag = await Storage.getString(isAgreePosition); + if (getFlag == isAgreePosition) { + openBlueSet(); + } + } else { + openBlueSet(); + } + } + openBlueSet() { if (!Platform.isIOS) { getMicrophonePermission().then((value) { @@ -862,7 +886,9 @@ class LockDetailLogic extends BaseGetXController { // TODO: implement onReady super.onReady(); - openBlueSet(); + // openBlueSet(); + + positionPermissionAlert(); _initReplySubscription(); _initLockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceAction(); @@ -886,5 +912,4 @@ class LockDetailLogic extends BaseGetXController { _lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent!.cancel(); // _scanListDiscoveredDeviceSubscription.cancel(); } - } diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart index 3b976415..3c536179 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart @@ -35,7 +35,8 @@ class LockDetailPage extends StatefulWidget { State createState() => _LockDetailPageState(); } -class _LockDetailPageState extends State with TickerProviderStateMixin, RouteAware { +class _LockDetailPageState extends State + with TickerProviderStateMixin, RouteAware { // with RouteAware final logic = Get.put(LockDetailLogic()); final state = Get.find().state; @@ -61,6 +62,7 @@ class _LockDetailPageState extends State with TickerProviderStat void didChangeDependencies() { super.didChangeDependencies(); Get.log("LockDetailPage didChangeDependencies2222"); + /// 路由订阅 AppRouteObserver().routeObserver.subscribe(this, ModalRoute.of(context)!); } @@ -68,12 +70,13 @@ class _LockDetailPageState extends State with TickerProviderStat StreamSubscription? _lockRefreshLockDetailInfoDataEvent; void _initRefreshLockDetailInfoDataEventAction() { // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus - _lockRefreshLockDetailInfoDataEvent = eventBus.on().listen((event) { + _lockRefreshLockDetailInfoDataEvent = + eventBus.on().listen((event) { setState(() {}); }); } - void loadData(){ + void loadData() { // print("widget.lockListInfoItemEntity.lockUserNo:${widget.lockListInfoItemEntity.lockUserNo}"); // print("state.lockUserNo:${state.lockUserNo}"); @@ -81,17 +84,18 @@ class _LockDetailPageState extends State with TickerProviderStat state.lockUserNo = state.keyInfos.value.lockUserNo!; if (state.lockUserNo == 0) { state.bottomBtnisEable.value = false; - }else{ + } else { state.bottomBtnisEable.value = true; } // print("state.keyInfos.value.keyStatus:${state.keyInfos.value.keyStatus}"); - if (state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusWaitIneffective || + if (state.keyInfos.value.keyStatus == + XSConstantMacro.keyStatusWaitIneffective || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusFrozen || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusExpired || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusDeleted || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusReset) { state.openDoorBtnisUneable.value = false; - }else{ + } else { state.openDoorBtnisUneable.value = true; } @@ -100,28 +104,28 @@ class _LockDetailPageState extends State with TickerProviderStat state.senderUserId = state.keyInfos.value.senderUserId!; state.isAttendance.value = state.keyInfos.value.lockSetting!.attendance!; state.isOpenLockNeedOnline.value = - state.keyInfos.value.lockSetting!.appUnlockOnline!; + state.keyInfos.value.lockSetting!.appUnlockOnline!; state.electricQuantity.value = state.keyInfos.value.electricQuantity!; state.isOpenPassageMode.value = state.keyInfos.value.passageMode!; state.lockAlias.value = state.keyInfos.value.lockAlias!; BlueManage().connectDeviceName = - state.keyInfos.value.bluetooth!.bluetoothDeviceName!; + state.keyInfos.value.bluetooth!.bluetoothDeviceName!; List publicKeyData = - state.keyInfos.value.bluetooth!.publicKey!.cast(); + state.keyInfos.value.bluetooth!.publicKey!.cast(); var saveStrList = changeIntListToStringList(publicKeyData); Storage.setStringList(saveBluePublicKey, saveStrList); // 私钥 List privateKeyData = - state.keyInfos.value.bluetooth!.privateKey!.cast(); + state.keyInfos.value.bluetooth!.privateKey!.cast(); var savePrivateKeyList = changeIntListToStringList(privateKeyData); Storage.setStringList(saveBluePrivateKey, savePrivateKeyList); // signKey List signKeyData = - state.keyInfos.value.bluetooth!.signKey!.cast(); + state.keyInfos.value.bluetooth!.signKey!.cast(); var saveSignKeyList = changeIntListToStringList(signKeyData); Storage.setStringList(saveBlueSignKey, saveSignKeyList); @@ -131,16 +135,29 @@ class _LockDetailPageState extends State with TickerProviderStat @override Widget build(BuildContext context) { + state.widgetContext = context; loadData(); return ListView( children: [ Visibility( - visible: ( - (state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime || state.keyInfos.value.keyType == XSConstantMacro.keyTypeLoop) && // 限时、循环 - (DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) < 30 && DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!) > 0) &&// 0到30天 - (state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusNormalUse || state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusWaitReceive)// 正常使用、待接收 - ) ? true : false, + visible: + ((state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime || + state.keyInfos.value.keyType == + XSConstantMacro.keyTypeLoop) && // 限时、循环 + (DateTool().compareTimeGetDaysFromNow( + state.keyInfos.value.endDate!) < + 30 && + DateTool().compareTimeGetDaysFromNow( + state.keyInfos.value.endDate!) > + 0) && // 0到30天 + (state.keyInfos.value.keyStatus == + XSConstantMacro.keyStatusNormalUse || + state.keyInfos.value.keyStatus == + XSConstantMacro.keyStatusWaitReceive) // 正常使用、待接收 + ) + ? true + : false, child: Container( // height: 30.h, color: const Color(0xFFFBEFD4), @@ -148,7 +165,8 @@ class _LockDetailPageState extends State with TickerProviderStat child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("钥匙将在${DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!)}天后失效", + Text( + "钥匙将在${DateTool().compareTimeGetDaysFromNow(state.keyInfos.value.endDate!)}天后失效", style: TextStyle( color: const Color(0xffCBA74B), fontSize: 24.sp)) ], @@ -185,21 +203,21 @@ class _LockDetailPageState extends State with TickerProviderStat ), ), Visibility( - visible: state.iSClosedUnlockSuccessfulPopup.value, - // visible: true, - child: GestureDetector( - onTap: () { - setState(() { - state.iSClosedUnlockSuccessfulPopup.value = false; - }); - }, - child: Container( - width: 1.sw, - height: 1.sh - ScreenUtil().statusBarHeight * 2, - color: Colors.black.withOpacity(0.3), - child: _unlockSuccessWidget()), - ), - ) + visible: state.iSClosedUnlockSuccessfulPopup.value, + // visible: true, + child: GestureDetector( + onTap: () { + setState(() { + state.iSClosedUnlockSuccessfulPopup.value = false; + }); + }, + child: Container( + width: 1.sw, + height: 1.sh - ScreenUtil().statusBarHeight * 2, + color: Colors.black.withOpacity(0.3), + child: _unlockSuccessWidget()), + ), + ) ]), ], ); @@ -215,73 +233,70 @@ class _LockDetailPageState extends State with TickerProviderStat SizedBox( width: 1.sw - 120.w * 2, child: Center( - child: Text( - state.lockAlias.value, - style: TextStyle( - fontSize: 22.sp, - fontWeight: FontWeight.w400, - color: state.isOpenPassageMode.value == 1 - ? AppColors.openPassageModeColor - : AppColors.darkGrayTextColor), - ))), + child: Text( + state.lockAlias.value, + style: TextStyle( + fontSize: 22.sp, + fontWeight: FontWeight.w400, + color: state.isOpenPassageMode.value == 1 + ? AppColors.openPassageModeColor + : AppColors.darkGrayTextColor), + ))), Positioned( child: Column( - children: [ - GestureDetector( - onTap: () { - // logic.getStarLockStatus(); - showDeletAlertDialog( - context, - DateTool().dateToYMDHNSString(state - .keyInfos.value.electricQuantityDate! - .toString())); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Image.asset( - showElectricIcon( - state.electricQuantity.value), - width: 30.w, - height: 24.w), - SizedBox(width: 2.w), - Text("${state.electricQuantity.value}%", - style: TextStyle( - fontSize: 18.sp, - color: AppColors.darkGrayTextColor)), - SizedBox(width: 2.w), - Icon( - Icons.info, // 使用内置的 warning 图标,它是一个叹号 - color: AppColors.mainColor, // 设置图标颜色为红色 - size: 25.w, // 设置图标大小为 30 - ), - SizedBox(width: 20.w), - ], - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Image.asset( - showElectricIcon(state.electricQuantity.value), - width: 30.w, - height: 24.w), - SizedBox(width: 2.w), - Text("--%", - style: TextStyle( - fontSize: 18.sp, - color: AppColors.darkGrayTextColor)), - SizedBox(width: 2.w), - Icon( - Icons.info, // 使用内置的 warning 图标,它是一个叹号 - color: AppColors.mainColor, // 设置图标颜色为红色 - size: 25.w, // 设置图标大小为 30 - ), - SizedBox(width: 20.w), - ], - ), - ], - )) + children: [ + GestureDetector( + onTap: () { + // logic.getStarLockStatus(); + showDeletAlertDialog( + context, + DateTool().dateToYMDHNSString(state + .keyInfos.value.electricQuantityDate! + .toString())); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Image.asset( + showElectricIcon(state.electricQuantity.value), + width: 30.w, + height: 24.w), + SizedBox(width: 2.w), + Text("${state.electricQuantity.value}%", + style: TextStyle( + fontSize: 18.sp, + color: AppColors.darkGrayTextColor)), + SizedBox(width: 2.w), + Icon( + Icons.info, // 使用内置的 warning 图标,它是一个叹号 + color: AppColors.mainColor, // 设置图标颜色为红色 + size: 25.w, // 设置图标大小为 30 + ), + SizedBox(width: 20.w), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Image.asset(showElectricIcon(state.electricQuantity.value), + width: 30.w, height: 24.w), + SizedBox(width: 2.w), + Text("--%", + style: TextStyle( + fontSize: 18.sp, + color: AppColors.darkGrayTextColor)), + SizedBox(width: 2.w), + Icon( + Icons.info, // 使用内置的 warning 图标,它是一个叹号 + color: AppColors.mainColor, // 设置图标颜色为红色 + size: 25.w, // 设置图标大小为 30 + ), + SizedBox(width: 20.w), + ], + ), + ], + )) ], ), SizedBox(height: 30.h), @@ -293,36 +308,43 @@ class _LockDetailPageState extends State with TickerProviderStat children: [ Center( child: GestureDetector( - onTap: state.openDoorBtnisUneable.value == true ? () { - // Get.log("点击开锁"); - setState(() { - startOpenLock(); - }); - } : null, - onLongPressStart: state.openDoorBtnisUneable.value == true ? (details) { - Get.log("长按闭锁"); - setState(() { - startUnLock(); - }); - // startUnLock(); - }:null, + onTap: state.openDoorBtnisUneable.value == true + ? () { + // Get.log("点击开锁"); + setState(() { + startOpenLock(); + }); + } + : null, + onLongPressStart: state.openDoorBtnisUneable.value == true + ? (details) { + Get.log("长按闭锁"); + setState(() { + startUnLock(); + }); + // startUnLock(); + } + : null, child: Stack( - children: [ - Image.asset( - state.openDoorBtnisUneable.value == false ? 'images/main/icon_main_openLockBtn_grey.png' : (state.isOpenPassageMode.value == 1 + children: [ + Image.asset( + state.openDoorBtnisUneable.value == false + ? 'images/main/icon_main_openLockBtn_grey.png' + : (state.isOpenPassageMode.value == 1 ? 'images/main/icon_main_normallyOpenMode_center.png' : 'images/main/icon_main_openLockBtn_center.png'), - width: 330.w, - height: 330.w, - ), - state.openDoorBtnisUneable.value == false ? Positioned( - child: Image.asset( - 'images/main/icon_main_openLockBtn_grey.png', - width: 330.w, - height: 330.w, - ), - ) : - state.openLockBtnState.value == 1 + width: 330.w, + height: 330.w, + ), + state.openDoorBtnisUneable.value == false + ? Positioned( + child: Image.asset( + 'images/main/icon_main_openLockBtn_grey.png', + width: 330.w, + height: 330.w, + ), + ) + : state.openLockBtnState.value == 1 ? buildRotationTransition() : Positioned( child: Image.asset( @@ -332,8 +354,8 @@ class _LockDetailPageState extends State with TickerProviderStat width: 330.w, height: 330.w, )), - ], - ), + ], + ), )), ], ), @@ -361,10 +383,10 @@ class _LockDetailPageState extends State with TickerProviderStat children: [ Text( logic.getKeyStatusTextAndShow(), - style: TextStyle( - fontSize: 22.sp, - color: AppColors.btnDisableColor, - fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 22.sp, + color: AppColors.btnDisableColor, + fontWeight: FontWeight.w500), ), ], ), @@ -543,7 +565,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_clockingIn.png', TranslationLoader.lanKeys!.checkingIn!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.checkingInListPage, arguments: state.keyInfos.value); })); @@ -552,14 +575,18 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_operatingRecord.png', TranslationLoader.lanKeys!.operatingRecord!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.lockOperatingRecordPage, arguments: {"keyInfo": state.keyInfos.value}); })); // 设置 - showWidgetArr.add(bottomItem('images/main/icon_main_set.png', - TranslationLoader.lanKeys!.set!.tr, state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + showWidgetArr.add(bottomItem( + 'images/main/icon_main_set.png', + TranslationLoader.lanKeys!.set!.tr, + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.lockSetPage, arguments: { "lockId": state.keyInfos.value.lockId, "isOnlyOneData": state.isOnlyOneData @@ -577,7 +604,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_clockingIn.png', TranslationLoader.lanKeys!.checkingIn!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.checkingInListPage, arguments: state.keyInfos.value); })); @@ -587,7 +615,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_electronicKey.png', TranslationLoader.lanKeys!.electronicKey!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.electronicKeyListPage, arguments: {"keyInfo": state.keyInfos.value}); })); @@ -596,7 +625,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_password.png', TranslationLoader.lanKeys!.password!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.passwordKeyListPage, arguments: {"keyInfo": state.keyInfos.value}); })); @@ -606,7 +636,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_icCard.png', TranslationLoader.lanKeys!.card!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { // logic.showToast("普通用户第一次需要在锁旁边操作哦。", something: () { // logic.showEasyLoading(); // }); @@ -621,7 +652,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_fingerprint.png', TranslationLoader.lanKeys!.fingerprint!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.fingerprintListPage, arguments: { "lockId": state.keyInfos.value.lockId, }); @@ -633,7 +665,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_remoteControl.png', TranslationLoader.lanKeys!.remoteControl!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.remoteControlListPage); })); } @@ -644,7 +677,8 @@ class _LockDetailPageState extends State with TickerProviderStat bottomItem( 'images/main/icon_face.png', TranslationLoader.lanKeys!.humanFace!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.faceList, arguments: { "lockId": state.keyInfos.value.lockId, }); // Toast.show(msg: "功能暂未开放"); @@ -658,7 +692,8 @@ class _LockDetailPageState extends State with TickerProviderStat bottomItem( 'images/main/icon_catEyes.png', TranslationLoader.lanKeys!.monitoring!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.realTimePicturePage, arguments: { "lockName": state.keyInfos.value.lockName, "isMonitoring": true @@ -672,7 +707,8 @@ class _LockDetailPageState extends State with TickerProviderStat showWidgetArr.add(bottomItem( 'images/main/icon_main_authorizedAdmin.png', TranslationLoader.lanKeys!.authorizedAdmin!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.authorizedAdminListPage, arguments: {"keyInfo": state.keyInfos.value}); })); @@ -687,7 +723,8 @@ class _LockDetailPageState extends State with TickerProviderStat bottomItem( 'images/main/icon_main_operatingRecord.png', TranslationLoader.lanKeys!.operatingRecord!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { // Get.toNamed(Routers.lockOperatingRecordPage, // arguments: {"keyInfo": state.keyInfos.value}); Get.toNamed(Routers.doorLockLogPage, @@ -697,7 +734,8 @@ class _LockDetailPageState extends State with TickerProviderStat bottomItem( 'images/main/icon_lockDetail_videoLog.png', TranslationLoader.lanKeys!.videoLog!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { //视频日志 Get.toNamed(Routers.videoLogPage); }), @@ -705,11 +743,16 @@ class _LockDetailPageState extends State with TickerProviderStat bottomItem( 'images/main/icon_lockDetail_messageReminding.png', TranslationLoader.lanKeys!.messageReminding!.tr, - state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { Get.toNamed(Routers.msgNotificationPage); }), // 设置 - bottomItem('images/main/icon_main_set.png', TranslationLoader.lanKeys!.set!.tr, state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { + bottomItem( + 'images/main/icon_main_set.png', + TranslationLoader.lanKeys!.set!.tr, + state.openDoorBtnisUneable.value, + state.bottomBtnisEable.value, () { // logic.clickItemBtnAction(10); Get.toNamed(Routers.lockSetPage, arguments: { "lockId": state.keyInfos.value.lockId, @@ -722,13 +765,18 @@ class _LockDetailPageState extends State with TickerProviderStat } // - Widget bottomItem(String iconUrl, String name, bool openDoorBtnisUneable, bool bottomBtnisEable, Function() onClick) { + Widget bottomItem(String iconUrl, String name, bool openDoorBtnisUneable, + bool bottomBtnisEable, Function() onClick) { var width = 42.w; var height = 42.h; return GestureDetector( - onTap:openDoorBtnisUneable ? (bottomBtnisEable ? onClick : () { - logic.showToast("请在锁旁边完成第一次开锁"); - }) : null, + onTap: openDoorBtnisUneable + ? (bottomBtnisEable + ? onClick + : () { + logic.showToast("请在锁旁边完成第一次开锁"); + }) + : null, child: Container( // height: 300.h, color: Colors.white, @@ -741,9 +789,11 @@ class _LockDetailPageState extends State with TickerProviderStat child: Image.asset(iconUrl, width: width, height: height, - color: openDoorBtnisUneable ? (bottomBtnisEable - ? AppColors.mainColor - : AppColors.lockDetailBottomBtnUneable) : AppColors.lockDetailBottomBtnUneable, + color: openDoorBtnisUneable + ? (bottomBtnisEable + ? AppColors.mainColor + : AppColors.lockDetailBottomBtnUneable) + : AppColors.lockDetailBottomBtnUneable, fit: BoxFit.fitWidth), ), SizedBox(height: 10.w), @@ -751,9 +801,11 @@ class _LockDetailPageState extends State with TickerProviderStat child: Text(name, style: TextStyle( fontSize: 20.sp, - color:openDoorBtnisUneable ? (bottomBtnisEable - ? AppColors.blackColor - : AppColors.lockDetailBottomBtnUneable) : AppColors.lockDetailBottomBtnUneable), + color: openDoorBtnisUneable + ? (bottomBtnisEable + ? AppColors.blackColor + : AppColors.lockDetailBottomBtnUneable) + : AppColors.lockDetailBottomBtnUneable), textAlign: TextAlign.center)) ], )), @@ -762,7 +814,8 @@ class _LockDetailPageState extends State with TickerProviderStat listeningAnimations() async { await Future.delayed(Duration.zero, () { - state.animationController = AnimationController(duration: const Duration(seconds: 1), vsync: this); + state.animationController = AnimationController( + duration: const Duration(seconds: 1), vsync: this); state.animationController!.repeat(); //动画开始、结束、向前移动或向后移动时会调用StatusListener state.animationController!.addStatusListener((status) { @@ -994,5 +1047,4 @@ class _LockDetailPageState extends State with TickerProviderStat // state.animationController!.stop(); // } } - } diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_state.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_state.dart index 9acdd804..11a758db 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_state.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_state.dart @@ -47,6 +47,8 @@ class LockDetailState { final PageController pageController = PageController(); var currentPage = 0.obs; + late BuildContext widgetContext; + // LockDetailState() { // Map map = Get.arguments; // lockCount = map["lockCount"]; diff --git a/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart b/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart index e08b40d6..92cd04a6 100644 --- a/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart +++ b/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; @@ -23,16 +22,34 @@ class MinePersonInfoPage extends StatefulWidget { State createState() => _MinePersonInfoPageState(); } -class _MinePersonInfoPageState extends State { +class _MinePersonInfoPageState extends State + with WidgetsBindingObserver { final logic = Get.put(MinePersonInfoLogic()); final state = Get.find().state; @override initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); // 添加观察者 logic.getUserInfoRequest(); } + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); // 移除观察者 + super.dispose(); + } + + // 当应用生命周期状态变化时调用 + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + if (state == AppLifecycleState.resumed) { + // 当应用从后台返回前台时检查相机权限 + checkCameraPermission(); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -177,48 +194,28 @@ class _MinePersonInfoPageState extends State { } Future requestCameraPermission() async { - // 检查是否已经授予相机权限 - PermissionStatus status = await Permission.camera.status; - + var status = await Permission.camera.status; if (status.isGranted) { - // 如果权限已经被授予,执行您的相机操作 - // 这里可以调用打开相机的方法或者跳转到相机页面等 selectCamera(); } else { - // 如果权限尚未被授予,请求相机权限 - // 此处会显示系统权限请求对话框 status = await Permission.camera.request(); - if (status.isGranted) { - // 如果用户授予了相机权限,执行您的相机操作 selectCamera(); } else { - // 如果用户拒绝了相机权限,您可以提供适当的提示 - // 或者引导用户手动授予权限 showPermissionDeniedDialog(); } } } Future requestPhotoPermission() async { - // 检查是否已经授予相机权限 - PermissionStatus status = await Permission.photos.status; - + var status = await Permission.photos.status; if (status.isGranted) { - // 如果权限已经被授予,执行您的相机操作 - // 这里可以调用打开相机的方法或者跳转到相机页面等 selectImage(); } else { - // 如果权限尚未被授予,请求相机权限 - // 此处会显示系统权限请求对话框 status = await Permission.photos.request(); - if (status.isGranted) { - // 如果用户授予了相机权限,执行您的相机操作 selectImage(); } else { - // 如果用户拒绝了相机权限,您可以提供适当的提示 - // 或者引导用户手动授予权限 showPermissionDeniedDialog(); } } @@ -236,8 +233,8 @@ class _MinePersonInfoPageState extends State { TextButton( child: const Text('去设置'), onPressed: () { - openAppSettings(); // 打开系统设置页面 Navigator.of(context).pop(); // 关闭对话框 + openAppSettings(); // 打开系统设置页面 }, ), ], @@ -300,6 +297,24 @@ class _MinePersonInfoPageState extends State { } } + Future checkCameraPermission() async { + var status = await Permission.camera.status; + if (status.isGranted) { + // 如果权限已经被授予,打开相机 + } else if (status.isPermanentlyDenied || status.isDenied) { + // 如果权限被永久拒绝,显示对话框引导用户去设置页面 + } + } + + Future checkPhotosPermission() async { + var status = await Permission.photos.status; + if (status.isGranted) { + // 如果权限已经被授予,打开相机 + } else if (status.isPermanentlyDenied || status.isDenied) { + // 如果权限被永久拒绝,显示对话框引导用户去设置页面 + } + } + // child: state.mineInfoData.value.headUrl != null // ? CachedNetworkImage( // imageUrl: Uri.encodeFull( From 683b1879ae18c5cecd26b29ccebae2358da5d284 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 21 Mar 2024 15:08:01 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=89=BE=E5=88=B0=20App=20Tracking=20Transparency=20=E6=9D=83?= =?UTF-8?q?=E9=99=90=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/ios/Runner/Info.plist | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/star_lock/ios/Runner/Info.plist b/star_lock/ios/Runner/Info.plist index 3251cc22..e5204edc 100644 --- a/star_lock/ios/Runner/Info.plist +++ b/star_lock/ios/Runner/Info.plist @@ -28,8 +28,16 @@ NSAppTransportSecurity - NSAllowsArbitraryLoads - + NSExceptionDomains + + jpush.cn + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + NSBluetoothAlwaysUsageDescription The app uses bluetooth to find, connect and transfer data between different devices @@ -76,8 +84,6 @@ UIViewControllerBasedStatusBarAppearance - NSUserTrackingUsageDescription - 需要访问您的隐私数据,以提供个性化的体验。 io.flutter.embedded_views_preview From 2abab9d231e4faebff0dcac2bd085607eef5f104 Mon Sep 17 00:00:00 2001 From: GeJiaXiang <353358601@qq.com> Date: Thu, 21 Mar 2024 16:55:45 +0800 Subject: [PATCH 4/9] =?UTF-8?q?1.0.20+2024032102=EF=BC=9A=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DApple=20Store=20App=20Tracking=20Transparency=E6=9D=83?= =?UTF-8?q?=E9=99=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/README.md | 9 ++++++--- star_lock/pubspec.yaml | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/star_lock/README.md b/star_lock/README.md index 9f10dabf..4ee83f4c 100644 --- a/star_lock/README.md +++ b/star_lock/README.md @@ -72,8 +72,10 @@ flutter build apk --split-per-abi --release --flavor sky -t lib/main_sky.dart 通用:build/app/outputs/apk/sky/release/app-sky-universal-release.apk 32位:build/app/outputs/apk/sky/release/app-sky-armeabi-v7a-release.apk 64位:build/app/outputs/apk/sky/release/app-sky-arm64-v8a-release.apk + +注意修改“VersionCode”为版本代码 ```bash -cp build/app/outputs/apk/sky/release/app-sky-universal-release.apk /d/Downloads/ +cp build/app/outputs/apk/sky/release/app-sky-universal-release.apk /d/www/SkyReleases/app-sky-universal-release-VersionCode.apk ``` ## 获取编译包的签名 用于APP备案,国内商店上架等 @@ -102,10 +104,11 @@ java -jar android/google/pepk.jar --keystore=android/app/sky.jks --alias=upload ```bash flutter build appbundle --release --flavor sky -t lib/main_sky.dart ``` +编译后的包:`build/app/outputs/bundle/skyRelease/app-sky-release.aab` +注意修改“VersionCode”为版本代码 ```bash -cp build/app/outputs/bundle/skyRelease/app-sky-release.aab /d/Downloads/app-sky-universal-release-1.0.16+2024031302.aab +cp build/app/outputs/bundle/skyRelease/app-sky-release.aab /d/www/SkyReleases/app-sky-release-VersionCode.aab ``` - - 注意,这里的sky.jks和google_pek.zip和encryption_public_key.pem都是sky渠道的,和谷歌账号对应。如果需要使用其他谷歌账号,需要更换这两个文件。 ## 用于华为商店 diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 71a10589..33973666 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -18,8 +18,11 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. # 版本说明: +# 1.0.18+2024032001:修复同意隐私政策前获取SN +# 1.0.18+2024032002:修复注册页布局错乱;修复第二次才可以删除锁的问题;修改申请权限字符串 # 1.0.18+20240321:打包给欧阳测试 -version: 1.0.19+20240321 +# 1.0.20+2024032102:修复Apple Store App Tracking Transparency权限问题 +version: 1.0.20+2024032102 environment: sdk: '>=2.12.0 <3.0.0' From 42ec6adda903154af7feb17257c3651955e8dad8 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Fri, 22 Mar 2024 13:51:30 +0800 Subject: [PATCH 5/9] =?UTF-8?q?1,=E4=BF=AE=E5=A4=8D=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E5=91=BC=E5=8F=AB=E6=8E=A5=E5=90=AC=E6=97=A0=E5=BA=94=E7=AD=94?= =?UTF-8?q?=E6=8C=81=E7=BB=AD=E6=80=A7=E6=97=A0=E6=B3=95=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=96=AD=E5=BC=80=E9=97=AE=E9=A2=98=202,=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E9=94=81=E7=B1=BB=E5=9E=8B=E6=98=BE=E7=A4=BA=E9=94=81=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E7=9B=B8=E5=85=B3=E6=9D=83=E9=99=90=EF=BC=88=E5=85=A8?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=94=81-=E8=A7=86=E9=A2=91=E6=97=A5?= =?UTF-8?q?=E5=BF=97=EF=BC=89=203,=E4=BF=AE=E5=A4=8D=E5=85=A8=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=94=81=E7=82=B9=E5=87=BB=E6=8E=A5=E5=90=AC=E9=9C=80?= =?UTF-8?q?=E7=82=B9=E4=B8=A4=E6=AC=A1=E6=89=8D=E8=83=BD=E6=8E=A5=E5=90=AC?= =?UTF-8?q?=E9=97=AE=E9=A2=98=204,=E8=8E=B7=E5=8F=96=E7=9B=B8=E6=9C=BA?= =?UTF-8?q?=E6=9D=83=E9=99=90=E4=BC=98=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/app.dart | 47 +----- .../lockDetail/lockDetail_page.dart | 20 ++- .../monitoring/lockMonitoring_page.dart | 35 +++-- .../lockMian/lockMain/lockMain_logic.dart | 29 ++-- .../minePersonInfo_page.dart | 135 +++++++++-------- .../minePersonInfo_state.dart | 3 + star_lock/lib/talk/udp/udp_talkClass.dart | 16 ++ star_lock/lib/tools/xs_aliyunPush.dart | 137 ------------------ star_lock/lib/tools/xs_jPhush.dart | 53 +++++++ 9 files changed, 201 insertions(+), 274 deletions(-) delete mode 100644 star_lock/lib/tools/xs_aliyunPush.dart create mode 100644 star_lock/lib/tools/xs_jPhush.dart diff --git a/star_lock/lib/app.dart b/star_lock/lib/app.dart index 505cc1ae..8528b05f 100644 --- a/star_lock/lib/app.dart +++ b/star_lock/lib/app.dart @@ -1,17 +1,13 @@ -// import 'package:aliyun_push/aliyun_push.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:jpush_flutter/jpush_flutter.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:star_lock/flavors.dart'; import 'package:star_lock/tools/app_manager.dart'; import 'package:star_lock/tools/bindings/app_binding.dart'; -import 'package:star_lock/tools/storage.dart'; -// import 'package:star_lock/tools/storage.dart'; -// import 'package:star_lock/tools/xs_aliyunPush.dart'; +import 'package:star_lock/tools/xs_jPhush.dart'; import 'package:star_lock/translations/app_dept.dart'; import 'package:star_lock/translations/trans_lib.dart'; @@ -32,8 +28,6 @@ class MyApp extends StatefulWidget { // final RouteObserver routeObserver = RouteObserver(); class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { - final JPush jpush = JPush(); - @override Widget build(BuildContext context) { return ScreenUtilInit( @@ -106,7 +100,7 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { super.initState(); WidgetsBinding.instance.addObserver(this); - initJPushService(); + XSJPushProvider().initJPushService(); } @override @@ -114,43 +108,6 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { WidgetsBinding.instance.removeObserver(this); super.dispose(); } - - Future initJPushService() async { - final data = await Storage.getString(saveUserLoginData); - if (data != null && data.isNotEmpty) { - jpush.setup( - appKey: "7ff37d174c1a568a89e98dad", - channel: "flutter_channel", - production: false, - debug: true, - ); - - jpush.addEventHandler( - // 接收通知回调方法。 - onReceiveNotification: (Map message) async { - print("flutter onReceiveNotification: $message"); - }, - // 点击通知回调方法。 - onOpenNotification: (Map message) async { - print("flutter onOpenNotification: $message"); - }, - // 接收自定义消息回调方法。 - onReceiveMessage: (Map message) async { - print("flutter onReceiveMessage: $message"); - }, - ); - - jpush.applyPushAuthority( - const NotificationSettingsIOS(sound: true, alert: true, badge: true)); - // jpush.setChannelAndSound( - // channel: "flutter_channel", channelID: "115700", sound: "default"); - - // Platform messages may fail, so we use a try/catch PlatformException. - jpush.getRegistrationID().then((rid) { - print("flutter get registration id : $rid"); - }); - } - } } void openBlueScan() { diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart index 031cffbe..9d623e1d 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart @@ -716,7 +716,8 @@ class _LockDetailPageState extends State // arguments: {"keyInfo": state.keyInfos.value}); // }) - var endWiddget = [ + var endWiddget = []; + endWiddget.add( // 操作记录 bottomItem( 'images/main/icon_main_operatingRecord.png', @@ -728,15 +729,19 @@ class _LockDetailPageState extends State Get.toNamed(Routers.doorLockLogPage, arguments: {"keyInfo": state.keyInfos.value}); }), - // 视频日志 - bottomItem( + ); + + if (state.keyInfos.value.lockFeature!.d3Face == 1) { + //视频日志 + endWiddget.add(bottomItem( 'images/main/icon_lockDetail_videoLog.png', TranslationLoader.lanKeys!.videoLog!.tr, state.openDoorBtnisUneable.value, state.bottomBtnisEable.value, () { - //视频日志 Get.toNamed(Routers.videoLogPage); - }), + })); + } + endWiddget.add( // 消息提醒 bottomItem( 'images/main/icon_lockDetail_messageReminding.png', @@ -745,6 +750,9 @@ class _LockDetailPageState extends State state.bottomBtnisEable.value, () { Get.toNamed(Routers.msgNotificationPage); }), + ); + + endWiddget.add( // 设置 bottomItem( 'images/main/icon_main_set.png', @@ -757,7 +765,7 @@ class _LockDetailPageState extends State "isOnlyOneData": state.isOnlyOneData, }); }), - ]; + ); showWidgetArr.addAll(endWiddget); return showWidgetArr; } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 3992c601..cd3a7164 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -20,6 +20,13 @@ class _LockMonitoringPageState extends State { final logic = Get.put(LockMonitoringLogic()); final state = Get.find().state; + @override + void initState() { + super.initState(); + + requestMicrophonePermission(); + } + @override Widget build(BuildContext context) { return SizedBox( @@ -155,18 +162,9 @@ class _LockMonitoringPageState extends State { Widget bottomBottomBtnWidget() { return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 接听 - Obx(() => bottomBtnItemWidget(getAnswerBtnImg(), getAnswerBtnName(), Colors.white, () async { - //获取麦克风权限 - await logic.getPermissionStatus().then((value) async { - if (!value) { - return; - } - - // state.isSenderAudioData.value = false; - print("发送接听了"); - // 刚进来是接听状态,然后改为长按对讲 - logic.udpAnswerAction(); - }); + Obx(() => bottomBtnItemWidget( + getAnswerBtnImg(), getAnswerBtnName(), Colors.white, () async { + logic.udpAnswerAction(); }, longPress: () { // 开始长按 print("onLongPress"); @@ -292,6 +290,19 @@ class _LockMonitoringPageState extends State { ); } + //获取麦克风权限 + Future requestMicrophonePermission() async { + await logic.getPermissionStatus().then((value) async { + if (!value) { + return; + } + + // state.isSenderAudioData.value = false; + print("发送接听了"); + // 刚进来是接听状态,然后改为长按对讲 + }); + } + @override void dispose() { super.dispose(); diff --git a/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart b/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart index ada7765e..eb21fe05 100644 --- a/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart +++ b/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'package:connectivity_plus/connectivity_plus.dart'; @@ -14,27 +13,27 @@ import 'lockMain_state.dart'; class LockMainLogic extends BaseGetXController { final LockMainState state = LockMainState(); - Future getStarLockInfo() async{ + Future getStarLockInfo() async { LockListInfoEntity entity = await ApiRepository.to.getStarLockListInfo( - pageNo:pageNo, - pageSize:50, + pageNo: pageNo, + pageSize: 50, ); - if(entity.errorCode!.codeIsSuccessful){ - if(entity.data!.groupList!.isEmpty){ + if (entity.errorCode!.codeIsSuccessful) { + if (entity.data!.groupList!.isEmpty) { state.dataLength.value = 0; - }else if(entity.data!.groupList!.length == 1){ + } else if (entity.data!.groupList!.length == 1) { GroupList groupList = entity.data!.groupList![0]; - if(groupList.lockList!.length > 1){ + if (groupList.lockList!.length > 1) { state.dataLength.value = 2; - }else{ + } else { state.dataLength.value = 1; } - }else{ + } else { state.dataLength.value = 2; } state.lockListInfoEntity.value = entity; // return entity.data!; - }else{ + } else { print("首页锁列表请求失败"); state.dataLength.value = 0; } @@ -70,7 +69,8 @@ class LockMainLogic extends BaseGetXController { connectListener() async { Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { print("设置网络切换监听:$result"); - if(state.networkConnectionStatus.value == 0 && result != ConnectivityResult.none){ + if (state.networkConnectionStatus.value == 0 && + result != ConnectivityResult.none) { // 从无网络到有网络 state.networkConnectionStatus.value = 1; getStarLockInfo(); @@ -85,7 +85,7 @@ class LockMainLogic extends BaseGetXController { print("onReady()"); // 开启UDP - // UdpHelp().openUDP(); + UdpHelp().openUDP(); BlueManage(); } @@ -112,5 +112,4 @@ class LockMainLogic extends BaseGetXController { // _teamEvent.cancel(); // state.timer.cancel(); } - -} \ No newline at end of file +} diff --git a/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart b/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart index 92cd04a6..722a94f6 100644 --- a/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart +++ b/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_page.dart @@ -1,3 +1,4 @@ +import 'dart:ffi'; import 'dart:io'; import 'package:flutter/material.dart'; @@ -32,6 +33,8 @@ class _MinePersonInfoPageState extends State super.initState(); WidgetsBinding.instance.addObserver(this); // 添加观察者 logic.getUserInfoRequest(); + _checkCameraPermission(); + _checkPhotoPermission(); } @override @@ -40,15 +43,15 @@ class _MinePersonInfoPageState extends State super.dispose(); } - // 当应用生命周期状态变化时调用 - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); - if (state == AppLifecycleState.resumed) { - // 当应用从后台返回前台时检查相机权限 - checkCameraPermission(); - } - } + // // 当应用生命周期状态变化时调用 + // @override + // void didChangeAppLifecycleState(AppLifecycleState state) { + // super.didChangeAppLifecycleState(state); + // if (state == AppLifecycleState.resumed) { + // // 当应用从后台返回前台时检查相机权限 + // checkCameraPermission(); + // } + // } @override Widget build(BuildContext context) { @@ -193,34 +196,58 @@ class _MinePersonInfoPageState extends State )); } - Future requestCameraPermission() async { - var status = await Permission.camera.status; + // Future requestCameraPermission() async { + // var status = await Permission.camera.status; + // if (status.isGranted) { + // selectCamera(); + // } else { + // status = await Permission.camera.request(); + // if (status.isGranted) { + // selectCamera(); + // } else { + // showPermissionDeniedDialog(); + // } + // } + // } + + Future _requestCameraPermission() async { + var status = await Permission.camera.request(); if (status.isGranted) { - selectCamera(); + setState(() { + state.hasCameraPermission.value = true; // 如果权限被授予,更新状态变量 + }); } else { - status = await Permission.camera.request(); - if (status.isGranted) { - selectCamera(); - } else { - showPermissionDeniedDialog(); - } + // 如果权限被拒绝,你可以选择在这里处理相应逻辑,比如显示一个提示框 + showPermissionDeniedDialog(); } } - Future requestPhotoPermission() async { - var status = await Permission.photos.status; + Future _requestPhotoPermission() async { + var status = await Permission.photos.request(); if (status.isGranted) { - selectImage(); + setState(() { + state.hasPhotoPermission.value = true; // 如果权限被授予,更新状态变量 + }); } else { - status = await Permission.photos.request(); - if (status.isGranted) { - selectImage(); - } else { - showPermissionDeniedDialog(); - } + // 如果权限被拒绝,你可以选择在这里处理相应逻辑,比如显示一个提示框 + showPermissionDeniedDialog(); } } + // Future requestPhotoPermission() async { + // var status = await Permission.photos.status; + // if (status.isGranted) { + // selectImage(); + // } else { + // status = await Permission.photos.request(); + // if (status.isGranted) { + // selectImage(); + // } else { + // showPermissionDeniedDialog(); + // } + // } + // } + // 显示权限被永久拒绝的提示对话框 void showPermissionDeniedDialog() { showDialog( @@ -256,11 +283,13 @@ class _MinePersonInfoPageState extends State int getSelectIndex = value; if (getSelectIndex == 0) { //拍照选项 - // selectCamera(); - requestCameraPermission(); + state.hasCameraPermission.value == true + ? selectCamera() + : _requestCameraPermission(); } else if (getSelectIndex == 1) { - // selectImage(); - requestPhotoPermission(); + state.hasPhotoPermission.value == true + ? selectImage() + : _requestPhotoPermission(); } }, ); @@ -297,41 +326,29 @@ class _MinePersonInfoPageState extends State } } - Future checkCameraPermission() async { + Future _checkCameraPermission() async { var status = await Permission.camera.status; if (status.isGranted) { - // 如果权限已经被授予,打开相机 - } else if (status.isPermanentlyDenied || status.isDenied) { - // 如果权限被永久拒绝,显示对话框引导用户去设置页面 + setState(() { + state.hasCameraPermission.value = true; // 如果权限已经被授予,更新状态变量 + }); + } else { + setState(() { + state.hasCameraPermission.value = false; // 如果权限未被授予,更新状态变量 + }); } } - Future checkPhotosPermission() async { + Future _checkPhotoPermission() async { var status = await Permission.photos.status; if (status.isGranted) { - // 如果权限已经被授予,打开相机 - } else if (status.isPermanentlyDenied || status.isDenied) { - // 如果权限被永久拒绝,显示对话框引导用户去设置页面 + setState(() { + state.hasPhotoPermission.value = true; // 如果权限已经被授予,更新状态变量 + }); + } else { + setState(() { + state.hasPhotoPermission.value = false; // 如果权限未被授予,更新状态变量 + }); } } - - // child: state.mineInfoData.value.headUrl != null - // ? CachedNetworkImage( - // imageUrl: Uri.encodeFull( - // state.mineInfoData.value.headUrl!), - // width: 72.w, - // height: 72.w, - // fit: BoxFit.fill, - // placeholder: (context, url) => Image.asset( - // 'images/controls_user.png', - // width: 72.w, - // height: 72.w, - // fit: BoxFit.fill, - // )) - // : Image.asset( - // 'images/controls_user.png', - // width: 72.w, - // height: 72.w, - // fit: BoxFit.fill, - // ), } diff --git a/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_state.dart b/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_state.dart index 4f4ac5b1..ac5e2f75 100644 --- a/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_state.dart +++ b/star_lock/lib/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_state.dart @@ -12,4 +12,7 @@ class MinePersonInfoState { List? imageList; // 使用ImagePicker前必须先实例化 final ImagePicker imagePicker = ImagePicker(); + + var hasPhotoPermission = false.obs; //是否有相册权限 + var hasCameraPermission = false.obs; //是否有相机权限 } diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart index 8740a9e3..1796670e 100644 --- a/star_lock/lib/talk/udp/udp_talkClass.dart +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'package:audioplayers/audioplayers.dart'; import 'package:fast_gbk/fast_gbk.dart'; import 'package:get/get.dart'; +import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart'; +import 'package:star_lock/talk/call/callTalk.dart'; import '../../appRouters.dart'; import '../../tools/storage.dart'; import 'udp_manage.dart'; @@ -68,6 +70,10 @@ class UDPTalkClass { Get.toNamed(Routers.lockMonitoringPage, arguments: {"lockId": "111"}); } + Timer(const Duration(minutes: 1), () { + stopLocalAudio(); + callNoAnswer(); + }); playLocalAudio(); } else { @@ -127,4 +133,14 @@ class UDPTalkClass { audioPlayer.setReleaseMode(ReleaseMode.loop); await audioPlayer.stop(); } + + //呼叫有响铃无应答处理 + void callNoAnswer() { + LockMonitoringLogic().stopProcessing(); + CallTalk().stopPcmSound(); + // 挂断 + LockMonitoringLogic().udpHangUpAction(); + // 关闭当前界面 + Get.back(); + } } diff --git a/star_lock/lib/tools/xs_aliyunPush.dart b/star_lock/lib/tools/xs_aliyunPush.dart deleted file mode 100644 index 4a922ebb..00000000 --- a/star_lock/lib/tools/xs_aliyunPush.dart +++ /dev/null @@ -1,137 +0,0 @@ -/* -import 'dart:io'; - -import 'package:aliyun_push/aliyun_push.dart'; -import 'package:star_lock/flavors.dart'; -import 'package:star_lock/network/api_repository.dart'; -import 'package:star_lock/tools/baseGetXController.dart'; - -class XSAliyunPushProvider { - late AliyunPush _aliyunPush = AliyunPush(); - - Future init(AliyunPush aliyunPush) async { - _aliyunPush = aliyunPush; - if (Platform.isAndroid) { - _aliyunPush.createAndroidChannel('1', '测试通道A', 3, '测试创建通知通道'); - _aliyunPush.setAndroidLogLevel(kAliyunPushLogLevelError); - } - _addPushCallback(); - } - - Future _onNotification(Map message) async { - // print('onNotification: $message'); - } - - Future _onAndroidNotificationReceivedInApp( - Map message) async { - // print('onAndroidNotificationReceivedInApp: $message'); - } - - Future _onMessage(Map message) async { - // print('onMessage: $message'); - } - - Future _onNotificationOpened(Map message) async { - // print('onNotificationOpened: $message'); - } - - Future _onNotificationRemoved(Map message) async { - // print('onNotificationRemoved: $message'); - } - - Future _onAndroidNotificationClickedWithNoAction( - Map message) async { - // print('onAndroidNotificationClickedWithNoAction: $message'); - } - - Future _onIOSChannelOpened(Map message) async {} - - Future _onIOSRegisterDeviceTokenSuccess( - Map message) async { - // Toast.show(msg: 'APNs注册成功, $message'); - } - - Future _onIOSRegisterDeviceTokenFailed( - Map message) async { - // Toast.show(msg: '注册APNs失败, errorMsg: $message'); - } - - _addPushCallback() { - _aliyunPush.addMessageReceiver( - onNotification: _onNotification, - onNotificationOpened: _onNotificationOpened, - onNotificationRemoved: _onNotificationRemoved, - onMessage: _onMessage, - onAndroidNotificationReceivedInApp: _onAndroidNotificationReceivedInApp, - onAndroidNotificationClickedWithNoAction: - _onAndroidNotificationClickedWithNoAction, - onIOSChannelOpened: _onIOSChannelOpened, - onIOSRegisterDeviceTokenSuccess: _onIOSRegisterDeviceTokenSuccess, - onIOSRegisterDeviceTokenFailed: _onIOSRegisterDeviceTokenFailed); - } - - Future initAliyunPush() async { - String appKey; - String appSecret; - - if (Platform.isIOS) { - if (F.appFlavor == Flavor.sky) { - appKey = "334068745"; - appSecret = "bee9c200835e4951a85dc8709c319560"; - } else { - appKey = "333904046"; - appSecret = "3eead09a7fc7416cb4082319aa6f48c6"; - } - } else { - if (F.appFlavor == Flavor.sky) { - appKey = "334068743"; - appSecret = "64de537f14984159a66ada10e54c6b63"; - } else { - appKey = "333904040"; - appSecret = "c316965fe0a74fc9a481a5c44a535dc2"; - } - } - - _aliyunPush - .initPush(appKey: appKey, appSecret: appSecret) - .then((initResult) { - var code = initResult['code']; - if (code == kAliyunPushSuccessCode) { - // Toast.show(msg: "初始化推送成功"); - } else { - String errorMsg = initResult['errorMsg']; - // print('初始化推送失败,原因为:$errorMsg'); - // Toast.show(msg: '初始化推送失败, errorMsg: $errorMsg.}'); - } - }); - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - } - - Future initAliyunThirdPush() async { - // Platform messages may fail, so we use a try/catch PlatformException. - // We also handle the message potentially returning null. - _aliyunPush.initAndroidThirdPush().then((initResult) { - var code = initResult['code']; - if (code == kAliyunPushSuccessCode) { - // Toast.show(msg: "初始化辅助通道成功"); - } else { - String errorMsg = initResult['errorMsg']; - // Toast.show(msg: '初始化辅助通道成功, errorMsg: $errorMsg'); - // print("初始化辅助通道失败,原因为:$errorMsg"); - } - }); - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - } - - void pushBindDeviceID(String deviceID, int deviceType) async { - var entity = await ApiRepository.to.pushBindAppId(deviceID, deviceType); - if (entity.errorCode!.codeIsSuccessful) {} - } -} -*/ \ No newline at end of file diff --git a/star_lock/lib/tools/xs_jPhush.dart b/star_lock/lib/tools/xs_jPhush.dart new file mode 100644 index 00000000..edd217dc --- /dev/null +++ b/star_lock/lib/tools/xs_jPhush.dart @@ -0,0 +1,53 @@ +import 'dart:io'; + +import 'package:jpush_flutter/jpush_flutter.dart'; +import 'package:star_lock/network/api_repository.dart'; +import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/storage.dart'; + +class XSJPushProvider { + final JPush jpush = JPush(); + + Future initJPushService() async { + final data = await Storage.getString(saveUserLoginData); + if (data != null && data.isNotEmpty) { + jpush.setup( + appKey: "7ff37d174c1a568a89e98dad", + channel: "flutter_channel", + production: false, + debug: true, + ); + + jpush.addEventHandler( + // 接收通知回调方法。 + onReceiveNotification: (Map message) async { + print("flutter onReceiveNotification: $message"); + }, + // 点击通知回调方法。 + onOpenNotification: (Map message) async { + print("flutter onOpenNotification: $message"); + }, + // 接收自定义消息回调方法。 + onReceiveMessage: (Map message) async { + print("flutter onReceiveMessage: $message"); + }, + ); + + jpush.applyPushAuthority( + const NotificationSettingsIOS(sound: true, alert: true, badge: true)); + // jpush.setChannelAndSound( + // channel: "flutter_channel", channelID: "115700", sound: "default"); + + // Platform messages may fail, so we use a try/catch PlatformException. + jpush.getRegistrationID().then((rid) { + print("flutter get registration id : $rid"); + pushBindDeviceID(rid, Platform.isAndroid ? 10 : 20); + }); + } + } + + void pushBindDeviceID(String deviceID, int deviceType) async { + var entity = await ApiRepository.to.pushBindAppId(deviceID, deviceType); + if (entity.errorCode!.codeIsSuccessful) {} + } +} From de32c10be971b41c9860d267cd34e420626fc92c Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Fri, 22 Mar 2024 14:20:55 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/udp/udp_talkClass.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart index 1796670e..8113bf71 100644 --- a/star_lock/lib/talk/udp/udp_talkClass.dart +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -136,7 +136,6 @@ class UDPTalkClass { //呼叫有响铃无应答处理 void callNoAnswer() { - LockMonitoringLogic().stopProcessing(); CallTalk().stopPcmSound(); // 挂断 LockMonitoringLogic().udpHangUpAction(); From 941433498db402fd97a05e7ece5ab103f6c65551 Mon Sep 17 00:00:00 2001 From: GeJiaXiang <353358601@qq.com> Date: Fri, 22 Mar 2024 15:27:19 +0800 Subject: [PATCH 7/9] fix --- star_lock/README.md | 2 ++ star_lock/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/star_lock/README.md b/star_lock/README.md index 4ee83f4c..1ecf099c 100644 --- a/star_lock/README.md +++ b/star_lock/README.md @@ -75,6 +75,8 @@ flutter build apk --split-per-abi --release --flavor sky -t lib/main_sky.dart 注意修改“VersionCode”为版本代码 ```bash +cp build/app/outputs/apk/sky/release/app-sky-armeabi-v7a-release.apk /d/www/SkyReleases/app-sky-32-release-VersionCode.apk +cp build/app/outputs/apk/sky/release/app-sky-arm64-v8a-release.apk /d/www/SkyReleases/app-sky-64-release-VersionCode.apk cp build/app/outputs/apk/sky/release/app-sky-universal-release.apk /d/www/SkyReleases/app-sky-universal-release-VersionCode.apk ``` ## 获取编译包的签名 diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 33973666..6c027ca9 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # 版本说明: # 1.0.18+2024032001:修复同意隐私政策前获取SN # 1.0.18+2024032002:修复注册页布局错乱;修复第二次才可以删除锁的问题;修改申请权限字符串 -# 1.0.18+20240321:打包给欧阳测试 +# 1.0.18+20240321(2024032101):打包给欧阳测试 # 1.0.20+2024032102:修复Apple Store App Tracking Transparency权限问题 version: 1.0.20+2024032102 From 9f365a82c0da0887071bf0159f789a187eb81519 Mon Sep 17 00:00:00 2001 From: GeJiaXiang <353358601@qq.com> Date: Fri, 22 Mar 2024 15:33:17 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E6=89=8B=E5=8A=A8=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=B0=A2=E6=80=BB=E7=8E=AF=E8=8A=82=E5=8F=A3=E5=91=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/flavorizr.yaml | 10 ++++++++++ star_lock/lib/flavors.dart | 12 ++++++++++-- star_lock/lib/main_xie.dart | 8 ++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 star_lock/lib/main_xie.dart diff --git a/star_lock/flavorizr.yaml b/star_lock/flavorizr.yaml index 8515329a..a4e6d12e 100644 --- a/star_lock/flavorizr.yaml +++ b/star_lock/flavorizr.yaml @@ -51,6 +51,16 @@ app: flavorDimensions: "flavor-type" flavors: + xie: + app: + name: "星锁-xie" + icon: "assets/icon/dev.png" + android: + applicationId: "com.starlock.lock.xie" + customConfig: + signingConfig: signingConfigs.pre + ios: + bundleId: "com.starlock.lock.xie" dev: app: name: "星锁-dev" diff --git a/star_lock/lib/flavors.dart b/star_lock/lib/flavors.dart index b92a882c..39d9a0f2 100644 --- a/star_lock/lib/flavors.dart +++ b/star_lock/lib/flavors.dart @@ -1,4 +1,5 @@ enum Flavor { + xie, dev, pre, sky, @@ -20,6 +21,8 @@ class F { static String get title { switch (appFlavor) { + case Flavor.xie: + return '星锁-xie'; case Flavor.dev: return '星锁-dev'; case Flavor.pre: @@ -35,6 +38,8 @@ class F { static String get navTitle { switch (appFlavor) { + case Flavor.xie: + return '星锁-xie'; case Flavor.dev: return '星锁-dev'; case Flavor.pre: @@ -50,10 +55,12 @@ class F { static String get apiPrefix { switch (appFlavor) { + // case Flavor.ge: + // return 'https://ge.lock.star-lock.cn'; + case Flavor.xie: + return 'http://192.168.1.15:8022'; case Flavor.dev: return 'https://dev.lock.star-lock.cn'; - // return "http://192.168.1.15:8022"; //谢总本地 - // "https://ge.lock.star-lock.cn"; //葛工开发环境地址 case Flavor.pre: return 'https://pre.lock.star-lock.cn'; case Flavor.sky: @@ -69,6 +76,7 @@ class F { // StarLockAMapKey static StarLockAMapKey get aMapKey { switch (appFlavor) { + case Flavor.xie: case Flavor.dev: return const StarLockAMapKey( androidKey: 'b56b681ee89f4db43a5aa1879ae8cbfe', diff --git a/star_lock/lib/main_xie.dart b/star_lock/lib/main_xie.dart new file mode 100644 index 00000000..cd62b84c --- /dev/null +++ b/star_lock/lib/main_xie.dart @@ -0,0 +1,8 @@ +import 'flavors.dart'; + +import 'main.dart' as runner; + +Future main() async { + F.appFlavor = Flavor.xie; + await runner.main(); +} From f2f28a212b694f4a3d2db92f7f0b8284f1d280d9 Mon Sep 17 00:00:00 2001 From: GeJiaXiang <353358601@qq.com> Date: Fri, 22 Mar 2024 15:53:51 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B0=A2=E6=80=BB?= =?UTF-8?q?=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/android/app/build.gradle | 20 +++++++++++++++--- .../src/xie/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4098 bytes .../src/xie/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2622 bytes .../src/xie/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5808 bytes .../src/xie/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 9444 bytes .../xie/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 13692 bytes 6 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 star_lock/android/app/src/xie/res/mipmap-hdpi/ic_launcher.png create mode 100644 star_lock/android/app/src/xie/res/mipmap-mdpi/ic_launcher.png create mode 100644 star_lock/android/app/src/xie/res/mipmap-xhdpi/ic_launcher.png create mode 100644 star_lock/android/app/src/xie/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 star_lock/android/app/src/xie/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/star_lock/android/app/build.gradle b/star_lock/android/app/build.gradle index f95e017f..8dc22d6e 100644 --- a/star_lock/android/app/build.gradle +++ b/star_lock/android/app/build.gradle @@ -36,7 +36,13 @@ android { keyAlias = 'starlock' keyPassword '123456' } - // 下面的pre、sky、xhj 都是自定义变量,自身不起任何作用,而是看哪里引用了它们 + // 下面的xie、pre、sky、xhj 都是自定义变量,自身不起任何作用,而是看哪里引用了它们 + xie { + storeFile file("starlock.keystore") + storePassword '123456' + keyAlias = 'starlock' + keyPassword '123456' + } pre { storeFile file("starlock.keystore") storePassword '123456' @@ -57,10 +63,18 @@ android { keyPassword 'xhj8872' } } + // ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) ----- flavorDimensions "flavor-type" productFlavors { + xie { + dimension "flavor-type" + applicationId "com.starlock.lock.xie" + signingConfig signingConfigs.pre + resValue "string", "app_name", "星锁-xie" + manifestPlaceholders.JPUSH_PKGNAME = "com.starlock.lock.xie" + } dev { dimension "flavor-type" applicationId "com.starlock.lock.dev" @@ -93,8 +107,7 @@ android { // ----- END flavorDimensions (autogenerated by flutter_flavorizr) ----- - - compileSdkVersion flutter.compileSdkVersion + compileSdkVersion flutter.compileSdkVersion ndkVersion flutter.ndkVersion lintOptions{ @@ -163,6 +176,7 @@ android { // 真实的解决办法 minifyEnabled false shrinkResources false + productFlavors.xie.signingConfig signingConfigs.pre productFlavors.dev.signingConfig signingConfigs.pre productFlavors.pre.signingConfig signingConfigs.pre productFlavors.sky.signingConfig signingConfigs.sky diff --git a/star_lock/android/app/src/xie/res/mipmap-hdpi/ic_launcher.png b/star_lock/android/app/src/xie/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c4abfb2f3a3ace7e97c2307305a1be8578320384 GIT binary patch literal 4098 zcmV+d5dH6oP) z6#0K7YIJmTZf-7-t|*FAFCA3IA(M&=Td&A=~vjGf8Ty?i^x)1)Fqq_%T z4(+4Xs`9eb-Gh$g>cH4*c(x^GZIt?3*UNWp_nSR0VD2IZS2sJ^#-mnF1^0B0*Ohm*L?7!`E!kqL#Juzc?YhT)<9D_M0(>?BHNG2rMa@8o9aI!i)KcN@a~bf`(@m znC(47t?$s;(p+`ub74_I@aj#T!$#WV-tu6boxICm@lR!|8ygV=w`%J=*fcymiP=zP zY^#i0_2;@IkN3xhZ`|hS!NmK}j2fRkeX)DHl2fT2w(C9Gsl@*f$M7rzBeKPlEcKCm zf9ugt{|Q=>>>u|L*}>7~ATo)#Dmz_V{54`}G_s?UZ8oeJo>ht2+<8=1z@u^*Co{FS z=t4-!Mz81?YoDvtYHt1)f|FV5cA2%Q$Rsj84<_8ghGzj7L61zP;LX}0;Jw(KA{;s_ zWc6m}&^{)uHTP~;A33PxRU=r91`|7YFgqn;-J=Rs6XC>2ux4787$HBXhVTaj2F1;< z$<0|EG>uFqOYYq^wx|^fdq80b1I)g#1(FzVQSkjO{?T-W)|@b?C=}+nNkPk3_h$KE28Do;s6>+wbL#ri?&TqOfl*s>IMRx; ziqze*Uw$@u52oqWKQe6HC+=?#vM?-#0?j~lS2QQglGqo;!%IuSjMFZa@bYr%3-b}R z3iAnykUg1w*8IbJ%mm$BZ2}(6+XvnxVE6bMRI!Ii7um4Po!ZE#=0ujNx!H7;92|V& z7lbAzQ=DkvN!il;;_!ZPagj?{c-V$*Zto1y^>Q@H|c_{ z+^CArx2|ixdmAy0w-A?ihJ;#SoOF`ZC^>f;ldveA3=IO7z8Z;Aw& zX=+7>aZd1m-Ia@?k{j&BEBxoo2U!Ap?qcupv7Eddd$}@F_qQE*Ehvuquu!cs_$bX* zPV--o81zwsPWOz&o-)&O$a|F;`z3cu;P3;r^pC6V!epq>EUwipWxJg#c`D1;u+uw(W zq--*e#fVe)C5H85dXPY?-A240n3&}HR;11E-G>Yvly^b&-HqxKnerMw+|>Bsho_Hc zc#V$@TC$SnV|jJ($!=inl6tzkmqy6YMoKa`obc_t7-9YJM`(KXRB-WpK->aG!~hDF z%9;@C`ThsIFHZ^1=Bhj7#%^e5XMJ%|!*|z%mag)Tn{RJ=ZU-=hOjebjSNCP^h}(}$ znoxtkvWZHiRKEJ`6FHBIDwUCY(seH>G+OYIm8^+VtB$6LOKxID?&u(r1ep_2V8Z)% zI2i|&Tn0(mo|$Cxw$!;9FJ+BkD=#lhVshKHX7StQ%Qq-8J4 zQuoN8J|USPfK;(lrLyp)8Ffg+yxe1&DiEsCUW;zVZP2@e&s?m%dZ{`m!#oLkI)4Uh z+H9blj;^lwbKwC~wzXBA%o5~(L4|fe)EK`(JW+`m0O#0YRci~PNsWhmX^y#2gmCV)hy z&zjAwiBrn<>}Y%O9PXoRlvW%#Lbl6y`%OWrn)d{3eO8mZm_1zH0h?St>b2-*A|`+UAu+xRwPJ* z-Z@=R2UhuLx>78Hd$#;uTDoYqckJ}w6)ENgX$-KohI;O)qtfeFLA(RM2i8P(cki=q z3+sc4UBa;yH!Ec_e&IREzi%~_zoNLhk;Dz)%RpcrS|$SG7l41}U+D&IDgCuHVUAzi z+_2S}b@Z7u6=)_e?>PV5X*dA~yK&u>LJ*4uE?wz2BOZ1MdSEKKyzF$g`0@pHbF;|~ zCqvPQ4O@LboMnugEO286QZ8!vbJMEUKYj0((Z;=R2Z~oFW9wl7@pQ zggJUl!~HvIQN2l%Ou%b+aNlj{aJrW_0;{6es4*VHMhed70g0>SvaZn)q~Y6Q@!b;t z`HAfLi4;Q-(>Wpn?7tRy1KWDjlZW6((58QeOq;E#iY;FLeD`)~aZ&Tn4`ek0;Iga& z!+^o8S8G*8Rc5O6hr8xGm1B6n;MJR0+7gS7Fg6C1EpX8??};B)Wu=L}Ery%aayjor zR{gc2;8p9r$BYMWLYA*}e=oW+ZExF)KS)qMk7ySUxVBCTnLT-$@eqhLZnE^6W>=I| zSK$C7VI-!90Q5+6SW$Q$7#OA+gd&b!UIEKf{0$RX2BssLH>>}r`=qhc%l7U7E+1~{ z5Z1ihw!Z%Qm9UN5=)V4L0|&p8TOjsQBD`gW{%MQ7md*&qIlhWJSWq_p`j*(rGg$Fg3 z0YLNt1N(0Ij1d-YZ5+JFLzBsVl)#!am6Lr~c=aMYBk%|Oyqvn?%OOBB$4w?-ixa@; z*@;P&`*(`+&;0cGA)OuE`s^vvPzPkePF!K5z6%S?P#PeSDaKZ+x3~YYj{{?;;|)S2 zRs?RR?+uNe`+D1}}8eaYDAHdayt^b4(@iyG#KYflu)S!`e*~`|lmpX=h z=PeG1UxYs$iYaUvB⋘DfC`mar4;o5@;?An`{$}?p^vtL>)U*f9pCYD@{?4DQvVp z|LtkQ93a?`Nnhbh_v0aZE!g3WpT(uGoNNIQJkUsQc)# zK}l;|wAFGVWJf-x-PtC2M#pFj54Z$bdsh>J)PM7J1Bgu*ED4yG0KB5^y=%V+SHp1x zK1u#4^@xZ9KOE_F<4e>~Men=+Fe5OGIIBoEGHAeb;KHRoQ)Ylry$)>Okmi7-u=+$+ z?d5{t^6Jd2L|#yZf08G@{d8_Po>j?mn8edP6wI^pWFey$ZtnE|81D=v7@;Oq~!IN3rN_= z2oS|^1qRNSyP=B4(7Xq#h$5X$jg|X$3NL*HA}qH-Luf3Y$o&}&cW-kt4#)*OazG$E zWnjX)u%K)^e3jDLD05IKq zujm-&un~1X-t!t3t*eDd%U+bH?UDcb#GF-H|HwY;x4I9AGQLs6bs;-(!I{+Ssok3p z*}>6QTV0b$B~{0dh_7Bk%*t3)FYmyl)qWGqy#jPTW)Cu=_dE!U1pQWFpTl9}F$A~`v+7cKLjvj8?HnmaRUPnxwP2#nfQ;3F(C zbN=-Qf8Dq&4d?JQUBH3;+C64$$f^y!eJzwXaFQU50-Nng=44GORKsv~Uv)>7mhS_B zA$s@gADpt0`R-7h&vi)}SQzj)^eIHw@h;!M&^wxkK@XX8FC_;914NhL; zJ7p%pyC>RMY^7(+_=#O4iCe0Zp)9y}m)&1ScOgNZS3gFr0iKWi>)@-$r% zgj&CuWAiGJ4L^nlk4EdWZKv-f(-LgY$(RHQzbUfGo7F*x%w*BViOU^YhRTLfr9A26cr8;yw7HLNcCF&xT}Zsdj7V>+PJUf@AB*=;@1y*nrOax z(Gi@hN98x<&1$Ay3PP33<$ONhcE|rI5{X3r1xsr23CscVGynhq07*qoM6N<$f*T0` AbpQYW literal 0 HcmV?d00001 diff --git a/star_lock/android/app/src/xie/res/mipmap-mdpi/ic_launcher.png b/star_lock/android/app/src/xie/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..6ef8ace4ce55b40ea33f5f52683467516767c46c GIT binary patch literal 2622 zcmV-E3c>Y>P)#n0k*+~cjAz=xS4M^Ubo4n-Z5ndKY|CsaTgZIuo@1Ea1_ndRjxs++s zrg6Dk(*FlZrBX_0XlQ(V{J=2;LBL-Kg5FWbTg_8mUQRJH{O)MbNf0erIUzA1^!xWk zC=M%OnY0l8GeoThbCD_L%xRuf3OTHh+cDfwSY|L0=oo08UTJsP+DLBv7RJ~KZwm!h zse~n08uAVWeVYmZVb&sF64jKa@^d1COqYv%B-s*Vp8z&;#J0i-)o@NG$QryBjoFgtNh7edciCTphFy&bN z0GYNV&YyaF8uAVbFQ4;W9q0MwJcvv-5>+V`4X5%OPaZ>*3j9P6#daWWBUr|OOrRm4 zzV^17wC{w)7YA?I?ldF>;|p*7#LwQ-+ag3~0ZMG_?O~--`)o3D@s4ExWG>Y8LlDzF zASOX@Xm77r1YV`(WmTEGhV99rI=ggLSJv%M?|%3@NpDa3kfFZo6Pr&Rm)yUrWm;G& z3X3w3MI@{HZ%4KFnl+a>b$a8O0^z@}vzM>o%$VKN-u5~rx$Sx}3D&v`LbCPn^j){n zbNVc>q0OiAv1OSDgc3z>0&~(3jNrv6G`erpTJTe=RQ$6Ajd=&*?r!~j6xPxeK7U?e=v4` zlYlHA6qpZb0d>_@^Y*8A-oK}L(W0RT59Myy%osIV*4R+?&8CjqH$CUh_g%f-&V|8Q z9N8mmQqEdaUjg86qjR08=bx5~3vaKx!3%HBtSK&S@W2w#zbac?*;E!_) zc?U8j5AK0iwM@#(N)we7bK{aY3nQ#SLo#!?_QPWwAP{gDZcKt>K%kMNV_@*`y@%T$ z{#Lhlw}Mv-II^npvbbpHagzcPw$OboSArG*$w7)k)MR~0p7y_y2>7)DX#gRTyYbjU&z7-&F0til@Xe`VdmX__{ zKUiZUNax*zXh4Zlo3XQ3EJjo+;4Yw6;Vg<^PX9Ci;9k-7t6-Z+YE@(5G4W47_^sRI zK4Xq4KOq1F!?3WlgqM?{ZWU|3!hH!Fl8P}kUOX+Ws-SwYBu^eN#!p7|QC*qA+jg=S zMb_n{cRtc2aggGxzS|1&DtAMY%cwDy0d-cD*LB~8ytkzlfIEFjqN8E zRsS>DAuz}(IK*$&I?vFs`rQ4ZAFpZhhg>E&yszbI5lCjtKh4wu0uJcN_68?ZpEe>i zTLY04^?XnTleB;^!e`qz1$kXhAGt1ybQ&Dgd^}fCQ`PbGA%R<%`9*P9A+zm=8)Y@TvI6tL?x1?7e&yYhi?)8#7?* zcHkxWbR>EHc+i9?AqiW+vjdC$I%Y-Z;|D~3+HaRTo;|9~OjFcUVjSo3lR=d-2n4d0 z3_fH-qxorzK>nd@koCdJ)N&aJT48Y!@FcIf;lQM=cS>>cbX9K;+Cr#hn&W~@>u1gZ zz{pZwZCUIJi~&wSpV$QEn0}3eag^D6vWD!~&04UuI(56ewpwG)#)ismNlh0{1%AE5 zD|9|4={YB?;+su>Y)hi~a)lR8LsUEF7qbV#KoHpQ2vU?bpONWw&gwYt`AY`2R>X;M zP{@dpCoT%F7730V=<8?$obH#;pD&x|85Zsn9c$<80yxZRGnB$4LBY|^n>Xxy{DS_z zkLJZ9n9EQ~Xc8+#p}2*HfvvD-xDu*1nW+JG)?XI7&zLR9KiqWgB+}Q1sQQ{OoCeY1 z6CJ|}UkU`gm#zR23xbp|Kgq>HI@8mTOCgf2v-3yC&pQPMn^I~HkZ#z)(SLoSSJ;Bu zjMR?be+3-1w40Z`r}@&kfTU!`nDM}Y2BJ~4ifS@a$u^XblynF(1g1UH6Z|Y_G(U_I zjqN=w^N{$?P5!|wrGO7O%7*$^@vB@v|AM=26BxxLRZ8WXvnN0g1k0q1snbcgRBB~E zV-+B!NC@JNy)Xi#hUP2h1-S=QT@t`=yH(nD@6LzWxo#sr1>x3QT2g;7t4}CIRYO{b zMX)WiRF@jJLFNdC`8k;_*DeQaPG-+v0^%Q-s^y2v)Zn51Ny%;@!#gX>YtvI?`V$a@ zlH;)9>?JGuP4XTs1iB0GS5eR7AINgaKL?^L=<9#5BUjQ`oW4#;MS6)-x`mHpz zWkyYyt}inmlh~M~s^aHhUVEC}R3;|^ zb(WhNoP@3ovUK~W_c-j12O@ifg>z#!+B!Pne(QV>XLMV6wsUaZ#Z=j>C%lRJERj2|&^hO-w3oE0$QcyxbpjuiJ$6m0E zY+Xl;5{=^>vU^|q;|FyaJ4sN#-rm%Og2_uyys4-zt|QMBJ9x3Jhk_@@r(;3ih+S0T zwO9*?)ZbLL&MtNk<9|bglJ-)-P!yQCZ?TYv2zT(k&|7q_W?-3_$a*q=9YvAL={-VAq)ja-L-vN_e311C`BwPs8y8KMHQ`D_b65>T3kg1Q4qHlx3y~Z zQ(x<-$_RTT%nTrqka5401VXqYxf#AM-|zSRf9fyy+;h))&U2sVInVQ)bFO4xUthxi z0~=)Ucl-A3|7|k5Dc-$%CudMZM1-zSLJ$Q0B@&6oC#pM9l9Q7|*5k46!yQ5g86S@% zeHcXOHr!DG&;uzzFg9&^GN>CuB}&F+lgdy zJBtqtMlnn}Fi5NTNCX0zRAOdprynUs0r$f{f`49lhDRwc4c9o`BuH}~%?)+TxESy6 z*1C=!uLmgxqOG;1^zbjW7qi@E&4JxAMC0%>2#@t46N$o_>VowvD|-g{#>G1f9;y>5 zdZVqmnRVf8)tM7AJ|A2HDMqcPpT^;05Y9#+sZ{x+B|rDw@@VRqiQY?BSb2KkBt<{e zzj#`>Ym=D8Qk9TMCRmmAa0T#65T3S(rl#tb_4jUa9{=I7U@3jx!jECvo2x2{61O)# zeGDs?X?sv7!=#--_@{PAB!ZR5M52nrNi|o`(_>;?CQc@qV7^D z$nirSfNmqj}5o>vMprP6;=XsAG&?2L0Gr~>G&2hHeSXo}0vY&hJHVM+i8YN^B9VDoe zHZ_eSsEt~S1nFd4P4LxiYp5?hu(u-ZSit(N&cjD*t}JeDE=>KkJ~JJX$w&n4+>yh8 zcnB#?m<-Y%QU;)E6z(=Td=+S*_x)^_%c$oXC~ zzbZ>jsm@B5A^ZShkHDVmw>Ss&QI!a)S$Rpj1rP3NcsZ53?^c?=sRum9m6*jQt{pUg`7H#rzedQC=#T9 z+=P&J&0$e%Bfm(Ipddp8Ot;wHfxbGyW9%d>s*vJN(a}-Vj4nemFrx|~#$ZCBpws6(VMy3bMDSPA(gG_1@1W}8{j#Lp zGPWW?fiZ>KO`6&(exr$nrK*s}%(I}nP#hfLm4Oy_ZA8-AsvrHR=wy)L33;TwG_|x+ zzvNVuSET&RzkdhoB>)OceHcBz-{d&(Q&nLzmjmo~&AAM78(XjFrL@_R>hqLUk06S> zyNJbBv5BaQzp52oB*?(54bcSd!b-*Mo{>~2%sZCccqv;V5MXsec5w7qw9IqbEY~>%AV#t2)6Z}1W}5){yhgULq|g6`HhV4zXsff&ia(Ny84g99*JUuG#zy52qz|on z#O#xPLF>2LF#O?^)zuPsT&%vD-o1Gn^Oak86g_4M+1!GlQ0IWvKRAyMX)G!*Y#d$5 zAQ*A66hw(#n=!YySN@Pm;86(Rq-BpluO;8Qd_El6J1FstnCB7_TAq5i=28|ae`RfL ztn}k`*Drd-EOnnAu9QCez5~D?BaEd3#*`ok5k?bD+S?}qyU;NQ07WyUQa$G{_Lvz# z(inMz3EqFjTK8FV%2Sf+@7_eM1H$0q#2xJHGxTr2cm86yp<_TmJ^*87)RED=wByaI zcR-yq#c#zrik&^qX01HDg0}Cgn=qNVW1|#9=~~N5@>Vac89hEAek0NqFa$>3-GOiv z$Q?ODnM48+2@WI1(&jF3?9*S5ww;HKa=dbnbup8baiXoh4z&*V{_U5~p14h)?G?4i z)Ydruv=JDjGGQozMaQf}B9nuXk5UJJfxlTnc`5tq1?m?g><0{PZ;V3mikRmL4AaqM z*7>ujVlNdmSDj8}Upeo$GQl-?is8y(5Q9WQVa25^3BNjU$y#tp0ut197L#?vjplat z=DKhPNZg0jvBL7Q>gcDmGZ!?flHw;AF2Th_Pae?Wh{sgb!gfqfyC zYKV&)dNK$|4g2Y%lH^2LNs-&kuT-V*dNR0gjT1nXgcW6g*I@n<^LgqFQo`CdU_feS z?XBw-CyxrtOHmtXe*fm}f^cf^RIho9Ej>K-qeLGD@ykj+{J2(<`(Akosg}bK(>#f+ zkJm455mcleR{nOLIK|SPhFT5G>u!^#xdu-yOFPa=JuDTWBocuL*IvC)cjKyO)FST% z-;i|A#_IL}hy(vQoYZ_d8xo3C+T9tWf?2GqiV2z;btMR(BJG%%$5l2%@uF+446KaL zyhYAqCzk)3RDTcM6@bLzir;>%zk5RuR{$@AfVru;b-n1|J~D8QiCxn-s@HnzHLsiEP@}55QUa-XJUnu@$XGg#l*s+g0V|MX@L@dLkbOoyaHQZ>6RK|=?f%C5P0tL(r}q8c`87rZAAUq5+Boe<);a=n?oc3(^jg9Ka-kQ(0amoXC* zkfyafT~jD^f8G;xm^S;!XhK;r@9_iWCGYuDLM+N7{D+UKZ(I#X*kVO*KU3j4W`e_z z&q@ycTyy0-7H##ne&;`b>ho>9>qITC049T4xSWctboSX(CTiwJ9boKc&Q!0MShtYr zoka!!OzmZdla#-01`O^Sw;KH5zWATA)D&Lc2lv@?QJ(@+MAPfPU(E@nPMAbrxZHv! zpRIr^&@*9+*W75pCeDMqs1Je|g}Ei6D&wS2>H9bEVcN0hP@A5UKYDqt&4KmS~yOK$z_0RrleD$K??Q5dB1?WpyT0&5C=o=TWtOH~L{LvIn z%j9nbl1l4xt~K1d?Xh67XT*GEO32cS-h1~i+*kiD-nX-*Fdy}4Q2t@nQrl1e<+m!q z+6U!a51c`b6=k{G){Ec1##+(@^OSYJ{+=t>I|ucK-;u(7X=IL31rd+?a_KzaM!}^H zA~=l;w(ZqNy-b4^5Y@7a^6f||$rJ}W_i3G{PaFme9+-XsxB^wFDOg#T#^+C7e?7zF z>xJ}~rLbkSP6mk^`T0i=)Sl1Ou*SfXK|}ZcLLD|5V{s0VlNQ6X9PI=#^K;{uNvheX z{m2yg9h`vgfXt&9sCT8tx0i6so zwY78ZKcwmY9SNraiyAu;k^A^hhk>7x&{i6Vi0RA(Z5ES=g!${fZR_Ap3(eCxs82)g zdvjKWa)g}g7daC{90z}fMTTZziJOJ1n`>A^&C^Gck|L~Ug{(@}&8s#82HAEb@Vcm& z>)447Lq0D#m{@!LGU|3Q`39fsmpD%z`Yd1LK4~iKE^=cIs^`jo`J%O|5;O%-DDLaF z_)Q1_lQgh0r8!s1xBoy=So-RVSvVPlWQPfw07`|z(%%kMpUc3~GSIEeoI+o{o-s8{ zy&OIOGdsJU8@74QjV?}3R86rk01+$Pn!w6T^Nm{rEU2p7Iw;69W(hkpO)6+n+Aq|- zOpR~@Ec?dQsuM@VHPz@X zKm@X*qvOQM9+A=3RA<;t^jXY`&gh$Xi1Y7f#fjTnON&wKv=rpNi;HpiawL7(DjS9$ zK^`1Y7>ncFXGWAA{iXKGMM75#s)DGYzP*<|{b0AOdw)`=2v(%r2B}11f+KW-5b?0O zrq?}xQkuA3SXQRNTcb`4@mR9L79--*M1kYrp$=!Rl&2l9Og$`XLzhhM;|KibPduZS zcttHzy0hj^)Se03oX1Zt+PxXomaCQn$%thllFE}Jn`zF*sz5~SidN}$?W6no@o|bu z7|*)Xd{(XZ?7CL~25npLNF@6F#niFEK%r`{oR^{5e_2~w`QZb#*DiU1niD1~x4bwG z8ftgunxKq{tZ(ffpp0p2Z|ArTA4BTU5nzT`!1gJwtO9!>O+G3ha$RZS4)AJuS*M?8ohCX_Nt}A3tli+6xx2fDgyN(M84q`Qr(Gvv(6)JCFGj)^ zYEP8ch6SAyNWc|v{OpU$jFZ*p&qz?yJrE>!1s?rDi(CMNj%3W6DfkdM6l>LxI zDj%QHY%929(WhUp9sBSvA0wT0l4<91v8vF-)7xkHD%!|#IGa^LpNyiZwGHE&IM2xW z%%8S5+`5ihN5bco|GJ-b_N4#XADu^zMON^RTwp)wQ)co$VKEcpa^%8q=RljcFksGn zorsYlR7@smXPMIYm^wI8=SKTRL}@tWq5=9R?E#y5ZP~+_GNX9kj#docRKn%vt^2M< z%@t6GZD8*~hf=|NZfoS5+SuqffEIxOUPMw^eX;%6@d5Fh%l`&%#)jalr*UH(|K~GGS}!!F_diasoDN zx9Jh6Q~N*@i?Y&dP9BxUw_iVqr9WPA$Q%Wrw)Ea8FS}G;j5RhRFlfkND&%s+{69GWKdH{A<2Yn zAk z``LAeip$1ikeJhuyK1THjM<)%(dJYaP(pEV1g-#o)|`qHM}WMb(LoTk2&&$^q>dOv zR13;VE@rY$9Dx+OIM6jlwe!dfp<;*_SU+ev4y6ak=H@b?h0{=uP2$=bRekWH$)m>h`sQ1znu}ET@>x;hc5w-Mj)kCb|7=E%w(eN@ zlOayfKtw|sq`pRAOa`fTMaw`Kaq#E*Th{~D{b<{}J?Z20`ImNCzXMl*b^14{P$;o? z@ZGSDu9j+O;c=Krd-*r7VcJ-TVCLq=SiQkT?HC>jX{0fZ&gutaGDy_gW!rcQv!EvD zii$ym4p+c+($wnbPiVnYDIMOBsJW>)?O5%lbEKvwEbfpT9BEN8UZJze7F~9FNRb&B z!z2i1I4+pJY?ZZJ=NbdAr0D&w&Cpx9Cgyz~S37E)fBZ&@ zqm%Nk5OG{sKMREAe;boQB;<-+2OD^W1qI28!e@VBQ4h*Zdj|DbvDRV05LIDKQDJ@d z>AK6=B(-64{M2_9o6s*}hoE-a3XlJNM*?-f8IQB}r?>T4Gnaq+ckAI6b`sO1Y8SilN# z+s|rfsDU43L`pFK_D$C9920&c8P(j#kLsGaOb??kTuwnG((HZx`=+E7?%Le+&ui4~ zq>cQ-9X~)YzC)U}l%PU$aNB+q!6@I=lOSeX`$k15kI|~_$T9xQR$6&8uo|@X_3w8i zz4p$H@)L)J7z?~el5sAmb!`N5;AHh028t3+*#>=>F?{{vH&O=-(b^Xnt?Pskm+_M- z&Yr3~c1YR^KjVpnR2K=-nj3+iI5gzDdPE$Qkth_8#mng+j@6}oP}zIVe3x;-CCU5h zZ~v~P3mrc!pxYirLq7N^L9D=Z0yIW3a|?^`m_66h4Skz{R+u}x25sHTnHE--lBE2C z11gY*jxdSB^W{49KJ@$iAVy93lIDPcfg842d->pP3LB1tK6N~PrtZ-nrTcdYSyd=C z@JSF(3DExa7acwrhqka~=H~9RD#3O57_E=%1m|I+?D`EXKX#CneFjDugj>ao^A$WD z43nCX2Gz;7wys}&?LGTzQyX{)Vid@a{jAo)ekMcVLeJtqo{`3!4jsETL?g>Mq`H%gd z5*QbHyi4PxJ3iijN?=6jw7Rj)sr2yQ6!u=|AyJd!5jI u43i;RFJ};wiLxKwi0BSH(hqDl`+or_xRawh`d#$^0000Qo8~#V`#2ABJHH%d8iCY!9+|^JYu+u#e{<%>n)tm& zBW?fJ!%RoL&_)?yABhlE_o!oegc`#B3$vF2)TKN^Sr7Yfb}voT%?L>WVgK>&r2|XT zMokYhs%Dk>xu~p~el*^E25oTJK=h)an_(d30nU?Z)@vN)^yZmP^^{+z3s9L9ue|!965>F$4zzZ(j7)>m!ZvpRFIvrb5qgvD-2Xc6~NoGGSupffKel)DLu?w!IZ@Y zKUpReyjeOY{ow9T)^4-*@;2wbWWa@>7l&d>_V2_hWiS|3YA`*itPdb<#t}w|*$^!+ zGxic$T1xz&p02(7dq<3CJG+=)2Q~1=NxObIZ}*n!Y~{3SY&)#X&!ws+HK=uBGlDRx z)b&cbNs^92k$dJi{&DL!SV^0cvpIFZpC$Fi6`U%0Ru=wP_%oUCRBT7CIdvd|VMW`x zcSnhFg(a7pb9wIRIQ+w(I>&d&aMMbts*t{zF-{u)R4rJT{7m>{Y~qywAd^Qx38Qcg z1+lU+zmV+BKb73Q?K5Gz!zazauacIQWbNOP8F!eidKxoZU!|>! z(Vtm|V&sqiVgNS>6oDK&eB~KAg&P=@bK)>oE+se(%=k+QYI+N352J7e1S6lr8hzU- zaAcHh{M6*=MMXD%)wMYiRt$m_UVNE1anMw$NR+g5gZ$bhg~Estkm2UyICXBrj^Dp~ zY7`|tk7EN`B6X;pFzP)3s%2zm1Zj3A{y&q$30|>2uU9|e!QGOlkH~JXEP?NB+iyto z!35HWTqb*a>_B1MA+)FnhCtb(+1oph7~7!l5C;3hz=|TAFOrFiMwbeNYvzUaVpEb_|q-<(Y3t^VQH{e!89ohfwRD+`u;ro^6+m~Q6r_Y% z&f5@SFv$)vJdE~zOS^U{J!Ts-D-#7+5P?+lAKli*zH@h<(c^8LU28obZ?XyuC0r?} z=8z5*mV==lW+7)LOhGEvmt`0scjc$PO;|qPD(NL1g-|dnJI*OHI5=q8S_i%__>Eu^ zg`Q#ddYB0yCd{JFyr?y)`oaV=rxuF~^Ddpu-TO1MqDlcw70l)GhmY|c7;f~^8ixaw z5e(yWq8ZoHAnjom^cB<-1#7@!v1+|K>(4(@m(Hf?`7jv(g23Fckqx7!(Traxz}qfT zSxMM_&2$kk4FnHhXM9j6UUAu>I&zFbmTbnQ~ouFb4ciD4fmO(0yZ=dcLZUi~VQpnxqB5k_F|-J)qrf3@ z08&xUp!}FO2M+`<>Sv? za{tbw`*+;?4D=c{S|_rGX=m?0dA3K`sGK8vg>i?W_q5sYeSqsl8FYJC9mFNTD8YQ7 zhK`CRdGgSzv=p!r;r)-(wq29eTbXQv1+OZp^!eu1l^4#SC`LA@;w9vsJyCG=qSu&7 z`jItOPA&mc=kodwO^IGu`s4}Da>2{zU{#|M9|)_nAZ22+feH);L-T7juoz|))YyC6 zROipzBShnEL2B}g@!_ku_@yZQW z+M*CX2fKIa>DH-R(y_f@g;9xjgwhKxi#j|N!)}RtnMNsPw7*ziJ*`tt-Uc(~zBgZjpwDf(1MhhMm2~rNVsE<4y zxL8kO_p1^LG`|vSrkGL*LwtRkuia+j-2nWyc#HJt)z`88*V%iv=bk+dC}82$%sH|z z_tH6B^mlGcYSgbYyd$hGV<1snaVEK&mAlrGAYCW!NJSOP$H#L(7%yZ19l$I?a0{+e z;OxcRPF;nu`-|`20UROaMdGCCk=8BR_)nW-*N8x|t25L?52IC8k@hg{wM|r80Z<^2 zNB_aTQ8Sq2D{6pnYW*4h5#73$xo$-j`I?R<@E%zf|LFP1{|)#E)BH1W!ni|nato&>aKW(T_O+*> zPuvEN;D?Q@%g7ov>VYs=CL`-%H0>X8jSUwQU3>I$A27_J@h6t3j5U{QJ!XPy-@$pO zVg*MJDk_22B&!MwGq-OL#U9`di|`H`Vd=;kP1HvZgGfEuVTRVUgm}6Ht=s0-;af`X zTkv;0%gNc+i@^BA;c|T=C*u=aa`a+pVglgACMyqmQ~E?Df^7 z4Z94fk!uig?_Nw>j`trDMWbk{crkBk@ozWqdB~-ENYLU{gy-1#2e#UKOmzKn)}HN^ z8R>u}%hHnL2la66J%HNC8Zuaxu*`&KNzn^!ax$SVLu!6h%F`r6qK+Y-Dz-#-Zx!FZ zp>8GxS1w3KPqZb^!^7*`9seZn+A2D*3(&ZVDNuD}jrWvUK4Bv%sWTZYMVKfhIWu;z z^vVS*6jHF6nredq1p+2ob}|!HCBlR+-QnXODuO(}zo>5Tom z@=qU?6&HhCq714}h<`RL)IDsJ*RTlF6nrvJMp%JJn6c$2>8fZR zj>mUhjlC%uC?KpvTqrzqEM?CQwH-;{$c4hN<{XAFNfl?QluFmkf`|8uZ(h~B6&r!$ zBL=w-9mVU^)mUpBgU$XVdSh{7LdMSVNz!AK^2O$4XgCuYWb_gl!ZU!#vSq)5$V$5 z8)Ip6XwuAK`~JMY?kgi};va#~hM!XS`%V1g+_8)M&S{db@S_I(^rc zyz{3p1&~65_ekN1Sn=<-yeH1!b?FZHIGQk;u;11!XPk|LRo>AcY$*o~23>PVRFGTV zsIsNz9E?FV*3uaE_8pI1EPwMV`Nz3(%?^P<)wKndBM7bF%Jt&k?|F@z%{B1L zY2M1ISxdvEp>jD5!W3oY8S7UUT)yBH5#`dMqYiD>Ui{Bu&*fdelD2bGwe}h;8I+=b zV#15jgPpsDc!rO$_8{Jmmr)}H7IX~Lyx!l6!E&_Ba z6z7~ndo*9C)h8`@ox7?3X4u&HO`7RGU}(=V9bPCg${&HN8blSl)rlUX4Vu@ zyLSF_mRY;GYn}!ph}-u)T)yj?btood*H%DDMp0Rrd-g=(^(!6`j{X26no&%%}*Az3itjW7{mOpxe+qaz!(`JaUKR2#s{P}xTMkZi( zGo{K*gOGv4Kbtz+z+DZb%9R5P9Yrb0k0y?^E-q4sh2h$OQXvotFp)s>#!lTsxvk8~ zCami8+TlhpgjQDN9M~tzOAA`EP5%;(C%@6cmF@$>6Q_=q1Iv(=DQ}Y(OfUH2%YcO| z*<2^m`Vjt_`rFO?V+YWLrxjq4!Z=k3lkW6wmj+X3TRGLT#6Tkt=mS)W3ST}?UG#%h zv2r#wP(2xjHJCCRs6=w$lecCM`v4fK5|tXb(5_)n>l2r9FPzFc5TlS7I`hN5FsSJM z-KT?kdgC)?k3KA-RJyu^RSI(+ET6}GnW(6!1ngKivQey8+(la=$8>$5)ucTPrq`}G z3-Gyp@ec|Bje-fonTPiTPMQf)D>5kLa*QlPPi;m*rmY=+Xap~Gpzw5D_TfE>QVGcW z#Mw>Tye4DsPT$Ch&Rs)vXwxN(?e6K{HB^|Mt}rI}$%_W(o;b=LKb1k`CanX6+?-MC zT6(#xzY{^v6US{tC5Lf_i;aO@6@I(*mDq7NjbO^8#J&gpj=Z7 zYa8$3V+usV@-uPZ_eIM}lQymPrP2KRX-&5TLn1$G&%W9zP_$ zb5p4g)@JCGlN$^%1D>NQB(GdltueevV2D3@ydp5zyU8agiWSB`$~&?b)^zX1AY6_& zhcJaw2_XrYwE@b6BYylKbx*?OBsmExdFN)01eV4>mK6V zxm(Ki4WhV1p!%RxntSS~`1&PY#01|#!*q@^nB2w-S4zT1zg;@J{M9SXLmVekaTZ5) zvAD*}k9R7M?|TxS#%5dbLi^<%+y}j%=OpQ%Mk9UT(<+I`0kKGe()0eh_j>hWSSSL` z9fv6m4ZL9yZ6l}D>YoZ^>7X$f4X4fV=ra)4;qlfARt>1Sq$GRes^aUHT?Y@>U%|8W z@oOFvmw)|Y*1nyUS?_WH$)!YD?%qRIkYDq+gu&wIC55Vif~N7igCT^;G$2yawGY8G z)0f%kOcqKabRgPded^h`oV6<;)QDuKEMH$v_}HdBLyf2p_^E0*G-=lQAu z*`81om1wSnVGt`Y2&A5bs4OdkNxa>3GQ?D+Btr@eFe4e=#hKkLr0MXnbYphhflONu zW7yaRL{0S`Ix6$*e3HfFK)hUmBeze)OR7)-`1)(tEa)i(%uY z82LP)1GxDRfe?E3>FW{IC%=U3<9^W#cgo6np-1Joyb5EO#F~{LSK7(v-J=S1CjG7tIu$ zIMR5BtWs?LK6LffYP8+`5I> zHgElA&vsOpQ}X;7Q!ZDg?!^niFt6`>xD6fU+9;TcM^W$CNn-r9(ps8ezR!xz_VnU( z?;S93n1P&QCc{$ED|plP4C&|5t8dEo4Y{%V08^0QFDCo&-ps>$8!nD^@7~++$s7;Q z7OJGO_!LuKP=Ls**{*Js$FSyPW#W?z0?CIl;uW>^UEPm*KKIiIj*|Th_sn5Op1t&g;_6?$ginPR0t4 z9|rW1!soxjU(P)I<2U#4(cXiHQy#L9QpJHH zR4-Wslp*`$COh{Ykhy7<`1hNDHm&L+apsn_qPW8iS8i}@+MKG&REh+5XGU>SQV{Ij zf(Wb~37}l1B#{!4k0FI@oxz633tqiB=fi<1uSDn1d*#xPCi^D2#1Hyl=uj-;EK8RPb9K8)Bu%yRJjt}FgY-nmtD(1?)z zLRH)jfAVbKuo0%+H}TZbf(_9KO0dev)>fV>l)h;sep7XqpX&qanJ_g1qEsRKyS5Zw zxd1xKU{Lm!HTf6MG?+NUx&7DR_sV&AKWFn#RjJ7^iI1!T(fSpEFtV0ZM;Uju?^O?k zm1Jkwd3x(6Xyv&#Ub3pN&!Dtbiz~q5c9bFesmVz{Ot5O&5?34W5)7X&udaT!bWX*s ztC+#m+%%@PYbA{ilW5LZHP`|eMKF2~OsXLH<96!JYy5GOom#imq0OmT3x`9eh38KR zj_j=x2|-Fz`e`M^|2;I+A!WKQhR+U^X zv(Mm0{lf_Eg`%(a?Z`h9hf@V8gVPYCWJXz3m~h1XIm zJc;S#q~1)K;2O&(OVqz_JrE`<)!y1vnGJ@nVlV17OgXH zTq8VG+s+*ykn`kW+NM?T+cy{n8X1ki5Uc%HEvC%2HD-GP0|pd~W|E{lH*zWEzI>LIP$G@3ZWG1%yQYEq$qOl>BXp3H{fZB^=lFb5xB zvh`+^JUA0l<@rn9yS?PhaRh~cw$@g|$;p4kdbgGY$sdZug#~}!t+;d3Z~A;2lAffB zNhGEWt#vOS3!pxFST3oN5GIL)FE1_4`SpBO%+D-IDGf|yS7xHHxAPu7-nDxuThHB0 zQd(M?l$g4D2_neB)%b)*4?KsA;0+$G@0eC1%ptaPz!1X%*7{m^EvgUG6!~Kk#)oA; zdy+VRnvGb@#6U%M1c99T4B(HQWX&ZAgFqFE$5G*|v=j`*)cf=)q|(g2JMyny^jo-+ z+oHAR$+lJ`ogRY}b+}cFWK6=KX0P9c1Oirs&i86GbD`ts9YAVs&2w+EeuvObRD!6ba zW5*^%F=%c)Lcj)-RDi>%4M??y#JZu)p3etz)FuNAx%3_6IcB1*qlp2H%E+4D{X9bY zCU4u2cN8?TM!y=A42Z^xn#5b%V;E*R+QcssOuQ0?96EgMGI%7<>?l}B^=N^UXS#I{ z$vzk(zIMrI)-Z@pkynRNFPT{AsOf5!*e=-CFHizqG3pYftA(qJ_q=6pZNH?pKB~x? zHR66lQll4DWRMy;2>?ShGMyS2CcIulQlf=MNC|)=lqMMV_D=nW_=b-KNycazxXoK~ zVvdU94k<%4%FBSR!IV3XSg1Y*P`g-9Ic;_>ZeR&?R0|^Cb!j?xISVW^p*djN+4)9J zati66wQ-gB&W+k<7Fqy&bxnCcqm5GPm2H;1cU9kPJFegW-TKWXR0PPD>mD}prhPK!ok6P_!!@?Q6}HQ zOt`lD68|K}9wNqRB&)>9$0ZY1463!Y{TC3y$LbyDAe!OTS&bB(_y(1yOxmVjTt@#1qs2jJ5cQiq$3n+8>6%_-rzlY-cN z%E%fRLdmzdFbs1f0BWrDM#&>;Jq$r$yKcRL=PjpEy+~m>C?jhIgt>+E%lLVt=u|Ai zHoAwIZ-}7sWdX_~Rvc^iv$hQ;|KMoh93&P3gT)G%KG&^x|BAP-YCoH5SY!##a98u{ z8zyshbu^ej`{ReLUx2NV>0T(Y^I2p#GHe{NYxIxoSZ0DM2M`O+A9cCL_KyH1FTvsy zzNHsy{t=+izp5@IG&2?Le>$jr>beuDExN|`k%PkLt!o|Vzc#T^?rd5=N^8x;_Fv$P z+GngcE5m=Gt63tqQ9YZ5{`Is`{!kx<9q(T$`detg|0oE9{@XI7QTSL0Q{!JVLRzlb qDGAHY&VKOVfh9`+Kd1%H)c*kJbxU;^R>n;L0000ZNklGfS`0pXi2D26s2eokQPWt z2qnGkZZ^GbpPB#8ZV1Wlw4H3@dw8D!VW-?Pch8)2?mdkc78VA*#7nRR&(Z|E#EXqa z1{yG6fMw};i5C&~@854^pxD@0vyF;j7!1Q^8_t>mrULx^;?BmrdGlVXFiQfk4yFP0 z!m^RM8R(_>(Sde0v~2Vu&df^*WEE&)Bj`mFMdo9m7jbsXj2BU(nNGP!n#mbR`|7+z>tUT5 z%^VWQdY<-w0M^Dvrez>26uJK!XksIaPwz`3`UQs8zJ@F+icH8r*6@D(&%@#x%~TBZ z(sni?M3?^bd9NP@e^`)>Oeld``6Shu>6l987X7NR=y?$#tF0+Gw72ZYKA-o}X-{t2 zF)}9)nS_CiB7W*?stcFQaqmCOfAUP{py1Zu@Wp~0JpO?lRhR!%N+g&-z>p`*FN#bh zfm%;}N#+9-#mdf~uKwdU=g|{7ezx2wguM{RzICH?!zxrLh5#qP5YNuepv%q4M#g6# zV_82wE^bAdUsNboee6(5#(nQ`Qv>?;H_FYe7FETCIp2IKeQ+N}HPfj1_SLmDEN*2U zABd3|$cW@}y?r(Fhu;vzFllB+!Rp15!}~%OEqDK4G>pXQsbz`rwO9TEa#v^iFdJKT z_cTLri18(mv8Y7VDlPXs{{({@9%nwDJ;`m*h=?U$@(mR1){K&KryhN`$`&OS-aOk@ zJ*i1uX~twA<1XD%NvZw_;17a9<>yZ}q}=qLHaBp{2qTVY5maTSKmGArWoEi9(x|ZX zfyx?MKahzunvo@tF)8!*A>~I5l8J-`->ob?xZ8c$M`1Bjj5Vk^AQZAA?YsLS^X!vp3b_w0_6PnpK!wR{&7~KNlEAvi-l* zUOXTA{TA2oNK;a080v*3SHJzj?S2XZbQVly?ht}2m70dGMzqEUVgv>w>LI*^gvPcVf^muBl|hEb>u5_MzHe_G8$Qw zV8KR4kU%EdCP(D5W~(qZtOTwpO*~kBDk>0@9A!F_yFl3xDz*i|bcdFw2X~$l@BbTgn@bxpsU3F1e zDiWSflEm%eqmYfpi{4tv^9=SuA;!6pfoQJLAQDb$l>{EL2n<31)kpm!LZuv z$tl;9-KWm!IBQ<332XsjT1xh!Sv;wX*EDQv(Ts9SNTBC*P`c8rcNx#&a*eV0Ah<>K zfgSg5{u{DzxqEci)(=pX^*D3iubkAoaDxmnWOs)S&Gy_Ca--dqEy!GHEExzaF*qEK zaY!Qp$J5&g0*DAGhBZ9Ocr<&0Q}@?{XUunv>cZ|mB{^B;Ck|JgKF&ih)=TszQ-cC> zu2sC}grbNIW#D>Ka}R(TcV$pnLEr!%gVh{ehZ#cv!>IPo&CHZrF08^G?`_*$k#xX8 zg>fN5mjoU2YZeG{9^B=}op%?`azwF~{MX`gdpiqkLy$qoFtQ5PCIp9)dmznbPijC& zbVLMl^&)FYh2Y_i2k+ke*L%#Qz)@qET#|kHLg}$1a9WBT2BD;9Q4s`Vkctc0zVrUu zi&ofpdON$hq7_wCm&;{L2s0;|1gF6aWVWDxj*lPpTMVcev~)$#Yi~-0#iGQ6C5eaF zkfm8`R~8pY)9%nRP}P&nlnq}yJ zt|3$v`w_MJ!u;tD4^nK^mfRic zTi%E!gJBG0&U8U8-v*aJ+9*HiSlzN<)vb3?g7uiJUlscUzB_277HkWkB?x+Cjk?u=kM4ePKYPIEnpoOs^>y(pDgJa zGnJZ#^wY=6lj3dj^K1}|jn2~SL~~tT9R>`EnDDV<8xO*>P)7%-n#x(>U*hH+sUl;iDur#I%!6yaZ{+@I($=w!)?Z(L^rqM5)}qWATwv}V{JUC z#{)hwa@dOwS89NdDWFL;Jx|Q6}>D5j{M|t>=MhGdTQsIr{{MgN0vDjTB5)6J~ z4a4y~J?(~n7(Hz+lNkf&sCZl+M#Uw9pil$pFdrB(kVOi$a4IXv55kakd4?Oy^oWR= z41pg?6y;>q#BQv)`5zZ$6Evs=#)TWg!+UQ#;Na@U{3;un?Ad-2v2s+^*Ri3-ETCr~ zixq02iX?9&N$u#=`f)17Lea596(ISNJ$--bHfhM?-s_W}n-`v!oVIT{ZsY6^{Y0q(L*MY^Ii*vGM z=TC_f;ytvgqs8+v;~sDp7qaab6*ObMPtRT~XlM?ls~e}BN=b2eR{Wk*9J6ehI*iVP z2&9ICkM6E6HGs~#@#P}U&1)R6s)tzZ4dVL;FgG$XV)05Z1I-;Wa4-y_T!nF+j9}`S z2sEs1$?~5H1Ok6gOiwdb40ni=qx z@@uM8l+Lw^r%#MBmMK8WKo+mDiaHCZPXJut(wROM3_M6ldg{|3*735Qwn1pTYZTyd zAgpJvwx6$ZrA)FZ7mMnCKWQ5f=G(VF!+jv7TN}8HU`xFTu7PGs>tO+62C{}4tEh}7 z9TQBw16`a$Ny_cQJ=+v%_xK3gD0d9sS9X7YK-iL14jSh_8I*E)>bft=|NcvW;$Z}$ z_+8;k*Dwipvc za!1`FRMfB-3{NRJl>jJ6yQlo~jPmlIPHJ2~HfI0?g^;v6>EnmGkDVM& zS;Q!K*hlW2yXNiQR+D@g(v4Qb+=8iMl`IPa2C}&I(?|xL3InWBarc&2WV_}c)?__- zx^1KS&aGOF9$~%C^7?R`@3<*0zWx-a6=y$HUiqUm@sO%sN;(z>$;%|7*i9A3k9d7F zA$aUWvbl8*i;P;owXQHP`-g92w{IfN5?Xnb0?e||Wgsiz9srI?MSTJcW43xOC;Px4 z)!my!DWMGXmqusV1_neQIAKTUB)Nb5sBFu(s0z0hVY&cCFslktN%7VVHP`-mWpk`8 zdASznpwO;c_6o24U9{s4V&T0X{Lm-ZcXKC3P)AUm7#R=D{Vja_457ma)tVu?RKD9ifprQZ5uR zbyo1inM^9bx)kIpbF)<_#%`)mr9zYtUwP>d&tV^W3>oE2vKMOS;@a->HGv<`D~a2g zcPf$1NM?ccN}!hevjjW=zCVs$^~pBTT?+{|AxK$@$AQq-d%eG5JI{tRHm&8LaOkwT zffGJ{xOi?u3b0f#gBN!iD9X!<_x)ON{&d@)b_mFQr4DXwA{Tz))^`vS+AMs4WDfuNcGf(TU@qF0mErE?d(T=Qo91pej0P6LK@TC&o{NcqAMF;k$J zDH%U)s67^s=w_-iwZ<^DT9kB9l5{X+_4j@Q*t50y@vIt&m5Cn!&U0@(@pk}2uxp5J zuy8}E2-ZzU#DB;0F*p#f$7|u!=ek9AGy3y(TC}Y4|K2OwzoY)nf6bf{hE;h)ASiF` z3dyBE!saceFpR7U)+>RyN)@dNtIy99c(qu?@VGpERlRX5*R z(EI`*rBEL1HfcutnF~xuYIC?pb#>pH@Nj2r#ep3#Tc0!nq|w6%spE!t#7u8HYn~PA zhbCAr13?Yi4kM)B0hm-*y%)5;TmorTm?p2!ZSb%*VB3WKKv}+t0pe)8lnxli6BW zF9Rv)YgoaUt!^ha%+3zBf!l80<=dmRp~^;qYj~vV7hgN}c)j4;m54&lwiXtK=H)zD zFrEKSzaHQJWNaE+1*>2n!h(5Rx~pKknu2bcDU2bnUbt>=PZjyqdK8~Hnjg0dLQt1Z z(QOwlx1}rl>fd*OSMPU)hxQljj%97m09A-4U%WlCpVvndgU3v;62r*y3{;ew@?_hx zKD++na9i*Y4?$>FVG!0J5<0eY$a_RE4UuMz{L{yZH+`e=!b8=`m+wD$`1K6?LWxkY-C9W%FWJ7|KS_o2Pt+i z7v|_rgqq8xt>eTsQYSX%kXBWSHh$eafmKy1F1nr^_~tuIE(eBD*!(5#1Bc~(v9P`{ zpOr?#H%ftFl(%kKar~~R-AC*!nzLaU1_D!X|M330ePF72Kqf_xLZN4 zKiZ;r3SndoOw(cqPX=~$cQ-zXz3n%ps>j^-6(5SQGm(+ z2gR5Khd}x#D66W9w{Dc2OpIK&$@LXB*}AM@CI*s-Mao;((l&hUj^UMcb-n~8g6h9I zsEXQ^p_xRf`Rdz_7eFsYv*A?v#?(-i%nX(sW*Z<1MVK#=rNM%JgZM6bOO zwPm-lMi1=UAN*wew4wgkK@~eD(ile7e_u@d=VIuZ@BR7@HWqDK7>$8yaph$G6w!tjkmLKTKR{|BM**tZfuE@rP@!hF9Nyf`(tZj|4+>d~t=(@WH< zk{d~WuYX997Sd_avg)BDOB3SD&z)q;Mfe+?_w}-Z1H0OOzOqfXp6u?T4rAi~H3^jaR^UX712NlD9Yk?>!(85U4N?p$cmrA&)tbG!HNe zz?W2-bVz5bn+HQ7>wfU-+h1N+_u%vS>IZj`mNEfM0#7fc#lnFy*2a6OL*OqsO4SGEjIQHlzQ=kFm|JB znFP`8BSBxtz3Cr}1A7e|5;A8o(OHBltVO^&rl!fCZw+#f#vx@Aow4oOcLv-8ez$XW z?z!VYRoeaBjbF=ivl{0B1Lhp$GjmmZH z$RnzYFd@G9XdE*i2vO~66jERQ{a${y?}X{TAF%i8vtgjemo6X|&nZ&xIak*ZZVb`_ zNF5%R<1%De=&VH!B&B*$HAS6h96&$;G2q~45^sjAy1MM(9-WEjLQwF+7QGGKqPxC& z=#=Q= zC;Zc;K4T`9?EAI+>VTC9a!aOg7d)=6lwWffQ^cFZm+mNB2|_8P4y7Xp!+5R& z_dz4VXMM`2GZZiaPdldbAGJb3_Kwm*DU;P_JuWv>H@DY&-i~}BA)8oze*Q~c=rgW4t znl^oa3VBV9J*)bGIfvsOY~AR?fz;1l1{7*+fC}`KI}GWlPhimdELiSlj5gsq;M>`e zhNJ*85UlLCQ;@3ql{K*xH{tR5!PDmkPMKA7> zfLls*(Y_>hP39GJ4I%)C*-)0h)JNL-HGq3)0%eItQr)_myJJh(>`x84jtPJYqgic2 zkON)Thdu%a5BKXoNOb08$$?!8Nh$5yNC*@`L`jD#F8$#L@@~FF{zX zm$knsDk_9~W2JddUs?B~{&}P-tmBd|YDbOD-Tq_4^?#UEz9A?J2B^qevqWU0x@?ZEOudI!ExCQ2b#iXqotqEu-gN5qPROhUE^V2bEb^*q>JxxiwiPf9 zNGv;lT3%V+d?s-N+TUL=cX7x6dyn^Q+c#{;NCZJL5)M@zKgbb@TFg8Q)h1u6xp&9q z)gBB7WdbgrPg~T{-h-wfzdmvj59YsP=mDqyMh*diU+lEIHTKy(v_KWPV|oc~E`b%)qiccjc*f$rLE~xVog+jX|s(ux)_kX#NQohW%#D*XN!l0GZ^s_{)m* zYjnnzKQwa5W<;$b3-oRJOmv4R)sDRZBL-itgMJZ(hqd zIagO;;%>a0tjyUl{OBH?H&XQ?@p_{-_$fShqGhX~bzL5Ve|zLV7_3EtW_;0=M9ERHfX``gVn)M6C5r!i|?3_I}&& z;Nqxmqkh_H&{YuYa1P%duX)6s$ltL=oDk38bmE7>dy%BxNgp@FecTl4UL-+-N4a&3 zEJzXG=gCXM5UsLy3|5e zQ$u*ItfVMq?Q$eNjbm^`O|w%uuygm<+J3$1HCAyA?Bjv>c6N~qmxaz+QIW(gEs`d3#X60_(P=EcZ=9|TA92pf?;CguJ5C_{b zDl2Zw;p%jJ!EhgoVO#3du(7wN-ALpU)sVQier3bi)4<%pcWGI9Cm{~pX7Dh@Yj1ab zzrVrPKSOIH5_vW@!PDoszu!N5^-}56Od{)z-W>xTMky8+ZQW3F{hziQw%L)hg;QWi z)TUoWH0=)%X{S5pjq=NUUc7H@3_UCEIPDBT3zMHK=3+xc*3skSXE`?|6xe{-}S(< zG8a!O50@l2M|%A#x8>fET~G+^a0UTih0)0m!p%lrSOoesi|BNU^*PQu91a8z8QFX8 zXAZ{5X)$J6PejZV)u^%g@q4SzolpQaVg*#G6eYx0;k`&kw;3{;v=@oMHFEA6=C}3e z`G(}e`KI^Pwn0{~XWJ`FR@so)rz*8NXWJ&O&UXPrKJT+}%TNFaQQ8V4JX?YmFzUKm zLtTt87xJ1sGjRM=b}=x7FmhfPZWztPtCnPZHb>Ko1Tr+7Knq|P746$mcK&p`A9o0d z+7cQHkC9^}f1YnXa`o90w;|qJD^}~DtW+xZ#f<7)lBW}t4PIaFE1gEo;)*LNw&RU$1z zJ}}5@^jJ@}m0ZYx0u=@rlX6#0Ehnfm!3zpObMvTguGtra>bP*k$8!Tlj(R+z=PaO|8Lkb1o>kY^>6Hb14z0NZ zSQ8sEvd_Zh#$7o!hsn#k1P&buelmXESeqEfw&b>^7fIqlNn)#dkvRGIh0gmt>&r#D z-xm-q;P0|h@Z$vIZUB9&mJdVie%|fmZTxB}nt(Ezd65yhGI%l>svA++l=O`^265`s zk3VwUE5=JgC4`v@Om$kg6z@f{Puq)xofAaci)1<8i)8L10eQD?3V8SFS266P%HNU* zNFaZkfdS#W@*A($Oj39nQ7U1WLmd%hPvkSk+}xl#oz)rE=tYn2!s`&#nbM1HESRsv zoqLyV?pt?PKDb}7b(55Bxd}WtmJV@Z?GYk0W^D5v{~E)>n)k6#ICtx2gCD5YB*5%r%T(8oorMZsbKCJiFk7Eo+Bl{ zpUqjjf?b>?)Yyw8?O899`GzLb_zf9h*RgZq+U0dm9ubqE`AT^lNE{qKGT{t6A{jy{ zr4J~R*ARq8*DI*=NBrhMTL#f@RA5`VSo9-o0n*dXYe=N?jhev;NxO zp^LwCH?R(udsu|ao&@o!q@w$GZ7R#lQ&XJa#;Rw)1ggT&@b~)*hK_!tr>O)_6HvU8 zAI;ve9nsQ(>*b9J@km7;4BK_-D)?|h_)LoC5MT3EQ%K~pc1 z!tYk8433d>h-QUL=Kw_p?(Wz=TnVgvDDoRGdE*Fm<+9pMKWEM%B65 zk~7CDdG)W)`?mS#_%fbW?h?ruYv3NpdKgFxZ7&kHfy44idy&vb9cinUWUu+Nm+$xeIj;HB^*8OWY)VE`+XRwgq8b45Woyc%)O@iGqWBE6?hC z^_f~pC<@8*a?-~SwQMhvjLR2f3Gs@IG;Ik5wOFWgf&ky$#;Bi*Yt#rNL4N&HT#%A)GM}YMzVyjgudKE^rk!U5bQU=lj zth9rt&kme2}fQ7TJP14WVKdDGRYckGZR4@o0! zT)kxe`cg4QHZAQNhER1&JJ3G@&#icNRwsPe#M%~fkX4RZj@!F zKQoLBPUe-1#jWo}f}&{pp*@lvTO3e`Nzp1quQH^QUjSt&hlXq`Q(?_(iCQlMm1aKh zYTub`-Guid*?ZI|y-4nl9pv(MpU_#KI)#KXzZR^XGU9eMoI8n%#kLq#Gppv{={0pw zGuY$7bZR_U6RekkD)wv>LU88|+bI%zpY@buSW3jcR+51g}~jFmNc7OKNhn z@2vjJHYXR;6#t`Sot9tFIzp0ouy z5GKS`|8tS~5)CiH#f2+F!d(ZB7%*W9#hD0#+}XZab~N4w(*$#|D$#GFufpUs)rdi|uod69g^@->R2Ue(bSwU4Mp=pZ-S<6l|ac5GC zkirD2=awTrk9h3ZgN#QrV|*t~4;(j@$0v0Uxxd=I$C)dlg!rN(2RP3z*8vPzhXYlH zhIe1FHk7h>V{J}$_Q}IFCzE)Z+vqd~X80^z7?OuYL@rtB(^a>+nT@X>S+%F_5Y>Ib zGCxYzsSt~De*R8+^=~eUv7RRI&N@X!2h3RD)t$JNiCQY9kLFNYejkXe4T$wJkaK8Q z!+$pj4{;Ezc-JqLm(IU>_&kMwv{^5bjkQ^ifUSyGrQpEuq}fAf&!Zmw#-8o+{lD5G z5SMM_Ka9aDJ{0}!&u+cnqaf1B+lOco)^hE}vQnlwV7&}Pt01I8F%$2)fA^j~`;HdJ z?RmH-*7@CjuP#{TMd`sPOHaN3^Y_k=()lRu@`xBP-pmR{-|XFO{!#&5H4j;J7149H zEa*mAq09`RXpm^V43u^}k-GL6N2LNQBPNyVxIBLF^f};%`m~Y<_tU;#W1pX6k3h6_ z3rWY~K%71wL`dRT3K7mK!sUy6{h7LvUk;b8K}dM;T0#2Q=WpcE8$Lv6rko3 z1cEAzS=eU0`SP&4*f(BJpCGGAx zhp4=Z*+6Y*S}y}d_8(mR`+4%?u%@CqOYTvtROcs;@+ru5P!qBat^UH_O|B-dufq?& zdW5%SM+SsfeGG2-1rZHxp+y*z4xZM_KzuvuhI1H#v6i3E{bu?qacm)R{%E zzihod{bw$)>(Q%C>uSEpYinAPKrl2yvfX7;FlI{;Z zSDu-JWny{ct$3zXqmtH;m5r%mhGa?(X_-fgDK<&zSefRK>x@TPpo4~pz^W{)fG69+ z?*4nbkIQxUo&R@``x!=OfPMVmd*A=>_dkCB-%kl6jX~pW6GfU|fM6Et{W3m)Q1Vhl zVup@*kbly{51ltA!|1E$MoIDI)#-sHR~_N&jtC4knHvFy1}2T_k-pmZu|3hY*sRvS zKHs2;>k&P6JY~cDI>k_*%J42EvcM-e&~wQ`=k6H2Ek@i*UEH?0^4s0P0JQ+(5FdjX zRx_wFIx67R89k?@koU`?eY*;>Hgrajas;V4@w0Bx67q8(4G$ku^mEo(a5zA}ez|l7 zbnWmD^2_wCfJSyICjyQ*Y0#$D`jLvD-4q)?O;GQ{@F0cp-@9=!ZbM0@C*FZ$5X< z-A|fa43Nu7)N}Ft+1gK6%gW1wU57giVld=#G!YBd9)RHQ)F(bZ;iF7{(vq4sYok7MUG0wtBkiEUHQ1vSJ3y-U zZm;>}Nc@NE)Q@h$hV;04UkoeO#3wAwfHRZWmIYb>C>r+q6ERwn|=D7zPjsynNPE(%o=d;}RKDt+AR7|sEWXSR zA316rH+9hR_sM&q;o8-^Uu4GV^$!@vw&G&3TrV-KNv}PfpSUIi|0^-99vhoDIs6VR)VDKFP}=m2%PV0SnwT$!p3*`J2m5G(l*8J|DW z2)ySGI}J1m2>&E`*oW}Q!ou8ryG^V-0He;Fv?Fdu$~181^7YYb6Ee5>#dc?UGw+hp_**FpJxGQUT_NVkMf@%h_wZ2wT*;^q+^QilwEiC*d9G*#bJTO zEJI?a%nYBL;;-$<`XZsRae+Jb8xMbfbJw;8vIVfxaCr%o`*o=(+l6tzjh zCAi0)`RWyV zWo4*-2SB%Iu9xTXe#zcZizyOCMm~T%;{ZLJ>ofpEGz;I1O<4pnhMI&<$>Z=Z)9K$! zKl!N9WaR$(SsyK;g!_<}x|6q+k&qga1q5&xkQ_ziy?ZBQZtd_`c1ykqA3RKb=vYbi zCeyy1q^5`}`Vj>fyb`C-q3b1t_h>cMRb1XVaGV;}Xl5_cy)sFxksKzI#V=m29zL>c z(|XJ0iyj6>RIw$%Oh8Y5Tv_PejRjL-pa0k_Db+Z<996OODw~%0{6ML(7 z?5`{QyJT}lLlN^_SSVuWZ5q%0B{FWAU>?mkB-CuU!R#{tQDO)fJfwd{Hs)ckUMxZq zd-wZ#UwLj$sLRW({4R%viU9EsdbbX4Ga%0EIN3&CWfa_@1Gq!W_sdYkZ{VPik)w6V6X3Ri z4?<((LYKc6ob*y<&W<~$P69jC0epV8GGM(g2+ozKJrF-_)WgcE)|!qUz+`A-+KSjo zGa&wH0dNeA60`7uQNh9)9tt_2Ef&bGf;kI=`=;QG&iF7z^-Z;|JxpDI!)f^qd9KT} zxoQ}>o<+eiFv>e_I+SZXw7=1Hs?~bqSe=`)-x2}l@E)#=lu^-^@`}g551b=qtXE>( z+aH8>=e_U+-#B*lUtbzFeoEE8oyLQE-OSPONhQ34h0s^E;m;3SWW-TJvZivzuJ+wG zG&myt!_Lo%Rwa}VR2q$H*$Tzbk*1An&1I#aZEy%cZ0?HgvIg!*gU1C1j;5&ocD3{W zR`sA5qJDW|)YLgaox4J4qV$OA*FQQZ&#-4lY4&FdthpQrZh>x_pj@Ail@}fZO*ncq zd3dDtW+l=z+(BdJr>ce}g>~x=y`7Q*!!X_K1u-e}EB5ZJ+_T*=FaiMch2X+?+LGlx zQi-*UsxB3%or@rt0*T%9m9{VMCETS0{-AWT<^>EIb~7vE{<+ikpb%J>g>s#?2o&nZ zVk<2~9j2%^ht7E|Zu(rQEh`IyW5sCmm(}`wOX(Gkm*OuXMCkJ(^jC}`o*jaWOpfnA zkpHGhnusC85&Vk-ylxl>9c)YAqxD>|R-iUL0r0oCBTlro=;4lDU?Ez#zqsL!PY!$s zO^AG6M67T}FR+lrfg_2W1Nr|UK(~~HfC#(;Be)1-)FmV!#Ou-8A<_~Mf!CvPN3b3! zMFA0bWz;T^u7C&#>9}Mf^Fof0k4x$TBETPq*A&r2;NfHY5D?<^XiV@5$Rl1Ekt6)< zwVerwKx(E`#IncjTR;TfJrEIT64243N5yT2m-dL! aX#5W!{>5e6r7>Ut0000