diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e668ae5..b193cf8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -124,6 +124,9 @@ PODS: - libwebp - wakelock_plus (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter + - FlutterMacOS - WechatOpenSDK-XCFramework (2.0.5) DEPENDENCIES: @@ -151,6 +154,7 @@ DEPENDENCIES: - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) - video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) SPEC REPOS: trunk: @@ -212,6 +216,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/video_thumbnail/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: agora_rtc_engine: da45ea14c402317c9e22fdb9ffe504d9a1acbe68 @@ -245,6 +251,7 @@ SPEC CHECKSUMS: video_player_avfoundation: 7993f492ae0bd77edaea24d9dc051d8bb2cd7c86 video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1 wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e + webview_flutter_wkwebview: 29eb20d43355b48fe7d07113835b9128f84e3af4 WechatOpenSDK-XCFramework: ff342ae616bb86df3d236aca38059dfd4bc4a949 PODFILE CHECKSUM: 9f921d5f3a6aff46b310102d923e8942abc7114d diff --git a/lib/main.dart b/lib/main.dart index 61cbb96..05dd43a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:dating_touchme_app/pages/mine/login_page.dart'; import 'package:dating_touchme_app/pages/setting/teenager_mode_page.dart'; import 'package:dating_touchme_app/rtc/rtc_manager.dart'; import 'package:dating_touchme_app/widget/live/draggable_overlay_widget.dart'; +import 'package:dating_touchme_app/widget/user_agreement_dialog.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; @@ -157,6 +158,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { Fluwx fluwx = Fluwx(); bool _screenUtilInitialized = false; + bool _showAgreementDialog = false; @override void initState() { @@ -164,6 +166,42 @@ class _MyAppState extends State { _initFluwx(); // 异步初始化IM,避免阻塞应用启动 _initIMAsync(); + // 检查是否已同意协议 + _checkAgreement(); + } + + /// 检查是否已同意用户协议 + void _checkAgreement() { + final storage = GetStorage(); + final hasAgreed = storage.read('hasAgreedUserAgreement') ?? false; + if (!hasAgreed) { + // 延迟显示弹框,确保UI已初始化 + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + _showAgreementDialog = true; + }); + }); + } + } + + /// 处理同意协议 + void _onAgreeAgreement() { + final storage = GetStorage(); + storage.write('hasAgreedUserAgreement', true); + setState(() { + _showAgreementDialog = false; + }); + } + + /// 处理不同意协议 - 退出应用 + void _onDisagreeAgreement() { + if (Platform.isIOS) { + // iOS上退出应用 + exit(0); + } else { + // Android上退出应用 + SystemNavigator.pop(); + } } /// 异步初始化IM SDK,避免阻塞应用启动 @@ -227,15 +265,32 @@ class _MyAppState extends State { final userId = storage.read('userId'); final teenagerMode = storage.read('teenagerMode') ?? false; GlobalData().teenagerMode = teenagerMode; + + Widget homeWidget; if(teenagerMode){ - return TeenagerModePage(); + homeWidget = TeenagerModePage(); } else if (userId != null && userId.isNotEmpty) { // 如果token不为空,显示主页;如果token为空,显示登录页面 GlobalData().userId = userId; - return MainPage(); + homeWidget = MainPage(); } else { - return LoginPage(); + homeWidget = LoginPage(); } + + // 如果需要显示协议弹框,则显示 + if (_showAgreementDialog) { + return Stack( + children: [ + homeWidget, + UserAgreementDialog( + onAgree: _onAgreeAgreement, + onDisagree: _onDisagreeAgreement, + ), + ], + ); + } + + return homeWidget; } } diff --git a/lib/pages/mine/open_webview.dart b/lib/pages/mine/open_webview.dart index 29b5107..a3dd9a5 100644 --- a/lib/pages/mine/open_webview.dart +++ b/lib/pages/mine/open_webview.dart @@ -5,8 +5,9 @@ import 'package:webview_flutter/webview_flutter.dart'; class OpenWebView extends StatefulWidget { final String url; + final String? title; - const OpenWebView({super.key, required this.url}); + const OpenWebView({super.key, required this.url, this.title}); @override State createState() => _OpenWebViewState(); @@ -28,11 +29,8 @@ class _OpenWebViewState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: const PageAppbar(title: "",), - body: controller != null ? WebViewWidget(controller: controller) : const Padding( - padding: EdgeInsets.all(16.0), - child: Center(child: CircularProgressIndicator()), - ), + appBar: PageAppbar(title: widget.title ?? "",), + body: WebViewWidget(controller: controller), ); } } diff --git a/lib/widget/user_agreement_dialog.dart b/lib/widget/user_agreement_dialog.dart new file mode 100644 index 0000000..16358f3 --- /dev/null +++ b/lib/widget/user_agreement_dialog.dart @@ -0,0 +1,213 @@ +import 'package:dating_touchme_app/pages/mine/open_webview.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + +class UserAgreementDialog extends StatefulWidget { + final VoidCallback onAgree; + final VoidCallback onDisagree; + + const UserAgreementDialog({ + super.key, + required this.onAgree, + required this.onDisagree, + }); + + @override + State createState() => _UserAgreementDialogState(); +} + +class _UserAgreementDialogState extends State { + late TapGestureRecognizer _userAgreementRecognizer; + late TapGestureRecognizer _privacyPolicyRecognizer; + + @override + void initState() { + super.initState(); + _userAgreementRecognizer = TapGestureRecognizer() + ..onTap = () { + Get.to(() => const OpenWebView( + url: "https://www.quzhaoqin.com/privacy.html", + title: "用户协议", + )); + }; + _privacyPolicyRecognizer = TapGestureRecognizer() + ..onTap = () { + Get.to(() => const OpenWebView( + url: "https://www.quzhaoqin.com/information.html", + title: "隐私政策", + )); + }; + } + + @override + void dispose() { + _userAgreementRecognizer.dispose(); + _privacyPolicyRecognizer.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.transparent, + child: Container( + width: double.infinity, + height: double.infinity, + color: Colors.black.withOpacity(0.5), + child: Center( + child: Container( + margin: EdgeInsets.symmetric(horizontal: 40.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.r), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 标题 + Container( + padding: EdgeInsets.symmetric(vertical: 20.h), + child: Text( + '用户协议及隐私政策', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + // 协议内容区域 + Flexible( + child: Container( + margin: EdgeInsets.symmetric(horizontal: 16.w), + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.5, + ), + child: SingleChildScrollView( + child: _buildAgreementContent(), + ), + ), + ), + SizedBox(height: 20.h), + // 按钮区域 + Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), + child: Row( + children: [ + // 不同意按钮 + Expanded( + child: _buildDisagreeButton(), + ), + SizedBox(width: 12.w), + // 同意按钮 + Expanded( + child: _buildAgreeButton(), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildAgreementContent() { + return RichText( + text: TextSpan( + style: TextStyle( + fontSize: 14.sp, + color: Colors.black87, + height: 1.5, + ), + children: [ + const TextSpan(text: '欢迎使用趣恋恋。\n\n'), + const TextSpan(text: '在使用本应用前,请你仔细阅读并充分理解\n'), + TextSpan( + text: '《用户协议》', + style: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(74, 99, 235, 1), + ), + recognizer: _userAgreementRecognizer, + ), + const TextSpan(text: ' 和 '), + TextSpan( + text: '《隐私政策》', + style: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(74, 99, 235, 1), + ), + recognizer: _privacyPolicyRecognizer, + ), + const TextSpan(text: '。\n\n'), + const TextSpan(text: '我们将严格按照协议内容使用并保护你的个人信息。\n\n'), + const TextSpan(text: '点击「同意」即表示你已阅读并同意上述协议。'), + ], + ), + ); + } + + Widget _buildDisagreeButton() { + return InkWell( + onTap: widget.onDisagree, + borderRadius: BorderRadius.circular(8.r), + child: Container( + height: 44.h, + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromRGBO(131, 89, 255, 1), + width: 1, + ), + borderRadius: BorderRadius.circular(8.r), + ), + child: Center( + child: Text( + '不同意', + style: TextStyle( + fontSize: 16.sp, + color: const Color.fromRGBO(131, 89, 255, 1), + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ); + } + + Widget _buildAgreeButton() { + return InkWell( + onTap: widget.onAgree, + borderRadius: BorderRadius.circular(8.r), + child: Container( + height: 44.h, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [ + Color.fromRGBO(131, 89, 255, 1), + Color.fromRGBO(61, 138, 224, 1), + ], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + borderRadius: BorderRadius.circular(8.r), + ), + child: Center( + child: Text( + '同意', + style: TextStyle( + fontSize: 16.sp, + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ); + } +} +