Merge branch 'dev'
This commit is contained in:
@@ -78,11 +78,15 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Flexible(
|
||||||
controller.name,
|
child: Text(
|
||||||
style: const TextStyle(
|
controller.name,
|
||||||
fontSize: 18,
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -98,12 +102,11 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () async{
|
onPressed: () async {
|
||||||
var scanResult = await Get.to(() => const MessagePage());
|
var scanResult = await Get.to(() => const MessagePage());
|
||||||
if (scanResult == null) {
|
if (scanResult == null) {
|
||||||
controller.msgNotice();
|
controller.msgNotice();
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
style: IconButton.styleFrom(
|
style: IconButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[100],
|
backgroundColor: Colors.grey[100],
|
||||||
@@ -111,9 +114,7 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
),
|
),
|
||||||
icon: Badge(
|
icon: Badge(
|
||||||
smallSize: 8,
|
smallSize: 8,
|
||||||
backgroundColor: controller.isNotice
|
backgroundColor: controller.isNotice ? Colors.red : Colors.transparent,
|
||||||
? Colors.red
|
|
||||||
: Colors.transparent,
|
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.notifications_outlined,
|
Icons.notifications_outlined,
|
||||||
color: Colors.black87,
|
color: Colors.black87,
|
||||||
@@ -232,12 +233,17 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 11.sp),
|
style: TextStyle(color: Colors.grey, fontSize: 11.sp),
|
||||||
),
|
),
|
||||||
Text(
|
Expanded(
|
||||||
value,
|
child: Text(
|
||||||
style: TextStyle(
|
value,
|
||||||
color: Color(0xFF333333),
|
textAlign: TextAlign.right,
|
||||||
fontSize: 12.sp,
|
overflow: TextOverflow.ellipsis,
|
||||||
fontWeight: FontWeight.bold,
|
maxLines: 1,
|
||||||
|
style: TextStyle(
|
||||||
|
color: const Color(0xFF333333),
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -515,14 +521,15 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: kPrimaryColor,
|
backgroundColor: kPrimaryColor,
|
||||||
minimumSize: const Size(double.infinity, 50),
|
minimumSize: const Size(double.infinity, 50),
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Text("发送广播", style: TextStyle(color: Colors.white)),
|
child: const Text("发送广播", style: TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,8 +29,14 @@ class HomeController extends GetxController with BaseControllerMixin {
|
|||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
initAliyunPush();
|
|
||||||
addPushCallback();
|
// 检查是否同意过隐私政策,只有同意后才初始化推送
|
||||||
|
if (StorageService.to.isPrivacyAgreed) {
|
||||||
|
requestPermission();
|
||||||
|
initAliyunPush();
|
||||||
|
addPushCallback();
|
||||||
|
}
|
||||||
|
|
||||||
FlutterNativeSplash.remove();
|
FlutterNativeSplash.remove();
|
||||||
log('page-init');
|
log('page-init');
|
||||||
|
|
||||||
@@ -152,7 +158,6 @@ class HomeController extends GetxController with BaseControllerMixin {
|
|||||||
|
|
||||||
// 根据登录状态和登录渠道返回不同的首页
|
// 根据登录状态和登录渠道返回不同的首页
|
||||||
Widget getHomePage() {
|
Widget getHomePage() {
|
||||||
requestPermission();
|
|
||||||
if (StorageService.to.isLoggedIn) {
|
if (StorageService.to.isLoggedIn) {
|
||||||
if (StorageService.to.loginChannel == LoginChannel.station) {
|
if (StorageService.to.loginChannel == LoginChannel.station) {
|
||||||
return B_BaseWidgetsPage();
|
return B_BaseWidgetsPage();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:getx_scaffold/getx_scaffold.dart';
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:ln_jq_app/common/login_util.dart';
|
import 'package:ln_jq_app/common/login_util.dart';
|
||||||
import 'package:ln_jq_app/common/model/base_model.dart';
|
import 'package:ln_jq_app/common/model/base_model.dart';
|
||||||
import 'package:ln_jq_app/common/model/vehicle_info.dart';
|
import 'package:ln_jq_app/common/model/vehicle_info.dart';
|
||||||
@@ -17,6 +18,8 @@ import 'package:ln_jq_app/pages/login/controller.dart';
|
|||||||
import 'package:ln_jq_app/pages/url_host/view.dart';
|
import 'package:ln_jq_app/pages/url_host/view.dart';
|
||||||
import 'package:ln_jq_app/storage_service.dart';
|
import 'package:ln_jq_app/storage_service.dart';
|
||||||
|
|
||||||
|
import '../c_page/message/view.dart';
|
||||||
|
|
||||||
class LoginPage extends StatefulWidget {
|
class LoginPage extends StatefulWidget {
|
||||||
const LoginPage({super.key});
|
const LoginPage({super.key});
|
||||||
|
|
||||||
@@ -30,6 +33,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
|
|||||||
bool _obscureText = true;
|
bool _obscureText = true;
|
||||||
bool _rememberPassword = true;
|
bool _rememberPassword = true;
|
||||||
bool _credentialsLoaded = false;
|
bool _credentialsLoaded = false;
|
||||||
|
bool isPushInitialized = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -388,13 +392,28 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
|
|||||||
content: _buildDialogContent(),
|
content: _buildDialogContent(),
|
||||||
confirmText: '同意',
|
confirmText: '同意',
|
||||||
cancelText: '拒绝',
|
cancelText: '拒绝',
|
||||||
onConfirm: () {
|
onConfirm: () async {
|
||||||
_isAgreed = true;
|
_isAgreed = true;
|
||||||
controller.updateUi();
|
controller.updateUi();
|
||||||
|
|
||||||
|
// 保存隐私政策同意状态
|
||||||
|
await StorageService.to.savePrivacyAgreed(true);
|
||||||
|
|
||||||
|
// 申请通知权限
|
||||||
|
await _requestNotificationPermission();
|
||||||
|
|
||||||
|
// 初始化阿里云推送
|
||||||
|
await _initPushService();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果已经同意过,但推送还没初始化,则初始化
|
||||||
|
if (!isPushInitialized) {
|
||||||
|
await _initPushService();
|
||||||
|
}
|
||||||
|
|
||||||
_tabController.index == 0
|
_tabController.index == 0
|
||||||
? _handleDriverLogin(controller)
|
? _handleDriverLogin(controller)
|
||||||
: _handleStationLogin(controller);
|
: _handleStationLogin(controller);
|
||||||
@@ -536,6 +555,62 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
|
|||||||
addAlias(identifier);
|
addAlias(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 申请通知权限
|
||||||
|
Future<void> _requestNotificationPermission() async {
|
||||||
|
final PermissionStatus status = await Permission.notification.request();
|
||||||
|
if (status.isGranted) {
|
||||||
|
Logger.d('通知权限已授予');
|
||||||
|
} else if (status.isPermanentlyDenied) {
|
||||||
|
Logger.d('通知权限被永久拒绝');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化推送服务
|
||||||
|
Future<void> _initPushService() async {
|
||||||
|
try {
|
||||||
|
final _aliyunPush = AliyunPushFlutter();
|
||||||
|
|
||||||
|
// 初始化推送
|
||||||
|
final String appKey = Platform.isIOS ? AppTheme.ios_key : AppTheme.android_key;
|
||||||
|
final String appSecret = Platform.isIOS
|
||||||
|
? AppTheme.ios_appsecret
|
||||||
|
: AppTheme.android_appsecret;
|
||||||
|
|
||||||
|
final result = await _aliyunPush.initPush(appKey: appKey, appSecret: appSecret);
|
||||||
|
if (result['code'] != kAliyunPushSuccessCode) {
|
||||||
|
Logger.d('推送初始化失败: ${result['errorMsg']}');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置平台特定设置
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
await _aliyunPush.showIOSNoticeWhenForeground(true);
|
||||||
|
} else if (Platform.isAndroid) {
|
||||||
|
await _aliyunPush.setNotificationInGroup(true);
|
||||||
|
await _aliyunPush.createAndroidChannel(
|
||||||
|
"xll_push_android",
|
||||||
|
'新消息通知',
|
||||||
|
4,
|
||||||
|
'用于接收加氢站实时状态提醒',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加推送回调
|
||||||
|
_aliyunPush.addMessageReceiver(
|
||||||
|
onNotificationOpened: _onNotificationOpened,
|
||||||
|
);
|
||||||
|
|
||||||
|
isPushInitialized = true;
|
||||||
|
Logger.d('推送服务初始化成功');
|
||||||
|
} catch (e) {
|
||||||
|
Logger.d('推送服务初始化异常: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onNotificationOpened(Map<dynamic, dynamic> message) async {
|
||||||
|
await Get.to(() => const MessagePage());
|
||||||
|
}
|
||||||
|
|
||||||
final _aliyunPush = AliyunPushFlutter();
|
final _aliyunPush = AliyunPushFlutter();
|
||||||
|
|
||||||
void addAlias(String alias) async {
|
void addAlias(String alias) async {
|
||||||
|
|||||||
@@ -25,11 +25,14 @@ class StorageService extends GetxService {
|
|||||||
static const String _stationAccountKey = 'station_account';
|
static const String _stationAccountKey = 'station_account';
|
||||||
static const String _stationPasswordKey = 'station_password';
|
static const String _stationPasswordKey = 'station_password';
|
||||||
|
|
||||||
// 新增:用于标记“绑定车辆”弹窗是否已在本会话中显示过
|
// 新增:用于标记”绑定车辆”弹窗是否已在本会话中显示过
|
||||||
static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown';
|
static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown';
|
||||||
|
|
||||||
static const String _hostUrlKey = 'host_url';
|
static const String _hostUrlKey = 'host_url';
|
||||||
|
|
||||||
|
// 隐私政策相关
|
||||||
|
static const String _privacyAgreedKey = 'privacy_agreed';
|
||||||
|
|
||||||
static StorageService get to => Get.find();
|
static StorageService get to => Get.find();
|
||||||
|
|
||||||
Future<StorageService> init() async {
|
Future<StorageService> init() async {
|
||||||
@@ -63,9 +66,12 @@ class StorageService extends GetxService {
|
|||||||
|
|
||||||
String? get stationPassword => _box.read<String?>(_stationPasswordKey);
|
String? get stationPassword => _box.read<String?>(_stationPasswordKey);
|
||||||
|
|
||||||
// 新增:获取“绑定车辆”弹窗是否已显示的标志
|
// 新增:获取”绑定车辆”弹窗是否已显示的标志
|
||||||
bool get hasShownBindVehicleDialog => _box.read<bool>(_bindDialogShownKey) ?? false;
|
bool get hasShownBindVehicleDialog => _box.read<bool>(_bindDialogShownKey) ?? false;
|
||||||
|
|
||||||
|
// 获取隐私政策是否已同意
|
||||||
|
bool get isPrivacyAgreed => _box.read<bool>(_privacyAgreedKey) ?? false;
|
||||||
|
|
||||||
VehicleInfo? get vehicleInfo {
|
VehicleInfo? get vehicleInfo {
|
||||||
final vehicleJson = _box.read<String?>(_vehicleInfoKey);
|
final vehicleJson = _box.read<String?>(_vehicleInfoKey);
|
||||||
if (vehicleJson != null) {
|
if (vehicleJson != null) {
|
||||||
@@ -110,6 +116,11 @@ class StorageService extends GetxService {
|
|||||||
await _box.write(_stationPasswordKey, password);
|
await _box.write(_stationPasswordKey, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存隐私政策同意状态
|
||||||
|
Future<void> savePrivacyAgreed(bool agreed) async {
|
||||||
|
await _box.write(_privacyAgreedKey, agreed);
|
||||||
|
}
|
||||||
|
|
||||||
// 新增:标记“绑定车辆”弹窗已显示
|
// 新增:标记“绑定车辆”弹窗已显示
|
||||||
Future<void> markBindVehicleDialogAsShown() async {
|
Future<void> markBindVehicleDialogAsShown() async {
|
||||||
await _box.write(_bindDialogShownKey, true);
|
await _box.write(_bindDialogShownKey, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user