diff --git a/assets/images/login_bg_white.png b/assets/images/login_bg_white.png new file mode 100644 index 0000000..869cc21 Binary files /dev/null and b/assets/images/login_bg_white.png differ diff --git a/assets/images/real_login_bg.png b/assets/images/real_login_bg.png new file mode 100644 index 0000000..e097ded Binary files /dev/null and b/assets/images/real_login_bg.png differ diff --git a/assets/images/real_logo.png b/assets/images/real_logo.png new file mode 100644 index 0000000..753f879 Binary files /dev/null and b/assets/images/real_logo.png differ diff --git a/lib/controller/mine/login_controller.dart b/lib/controller/mine/login_controller.dart index 2d25f90..e646912 100644 --- a/lib/controller/mine/login_controller.dart +++ b/lib/controller/mine/login_controller.dart @@ -18,6 +18,7 @@ class LoginController extends GetxController with WidgetsBindingObserver { final countdownSeconds = 0.obs; // 是否正在登录中 final isLoggingIn = false.obs; + final passwordController = TextEditingController().obs; DateTime? startTime; @@ -51,6 +52,8 @@ class LoginController extends GetxController with WidgetsBindingObserver { } } + final isSend = false.obs; + // 获取验证码 Future getVerificationCode() async { // 验证手机号格式 @@ -74,6 +77,7 @@ class LoginController extends GetxController with WidgetsBindingObserver { // 处理响应 if (response.data.isSuccess) { + isSend.value = true; // 生产环境移除打印,可考虑使用正式的日志框架 // print('验证码发送成功'); // 开始倒计时 diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index b8b68cc..d68a6ae 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -137,6 +137,7 @@ class Assets { static const String imagesLiveIcon = 'assets/images/live_icon.png'; static const String imagesLocationIcon = 'assets/images/location_icon.png'; static const String imagesLoginBg = 'assets/images/login_bg.png'; + static const String imagesLoginBgWhite = 'assets/images/login_bg_white.png'; static const String imagesLoginLogo = 'assets/images/login_logo.png'; static const String imagesMail = 'assets/images/mail.png'; static const String imagesMale = 'assets/images/male.png'; @@ -173,6 +174,8 @@ class Assets { static const String imagesPublish = 'assets/images/publish.png'; static const String imagesQuestionIcon = 'assets/images/question_icon.png'; static const String imagesRealChecked = 'assets/images/real_checked.png'; + static const String imagesRealLoginBg = 'assets/images/real_login_bg.png'; + static const String imagesRealLogo = 'assets/images/real_logo.png'; static const String imagesRealName = 'assets/images/real_name.png'; static const String imagesRealUncheck = 'assets/images/real_uncheck.png'; static const String imagesRealnameHelp = 'assets/images/realname_help.png'; diff --git a/lib/im/im_manager.dart b/lib/im/im_manager.dart index a9ac66c..ef3a120 100644 --- a/lib/im/im_manager.dart +++ b/lib/im/im_manager.dart @@ -13,6 +13,7 @@ import '../controller/message/chat_controller.dart'; import '../controller/global.dart'; import '../pages/mine/login_page.dart'; import '../network/user_api.dart'; +import '../pages/mine/real_login_page.dart'; // 完整的IM管理器实现,使用实际的SDK类型和方法 class IMManager { @@ -582,7 +583,7 @@ class IMManager { await Future.delayed(Duration(milliseconds: 500)); // 跳转到登录页 - Get.offAll(() => LoginPage()); + Get.offAll(() => RealLoginPage()); if (Get.isLogEnable) { Get.log('✅ [IMManager] 用户被踢下线处理完成,已跳转到登录页'); diff --git a/lib/main.dart b/lib/main.dart index 2137042..3cc9654 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,7 @@ import 'package:dating_touchme_app/im/im_manager.dart'; import 'package:dating_touchme_app/network/network_service.dart'; import 'package:dating_touchme_app/pages/main/main_page.dart'; import 'package:dating_touchme_app/pages/mine/login_page.dart'; +import 'package:dating_touchme_app/pages/mine/real_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'; @@ -274,7 +275,7 @@ class _MyAppState extends State { GlobalData().userId = userId; homeWidget = MainPage(); } else { - homeWidget = LoginPage(); + homeWidget = RealLoginPage(); } // 如果需要显示协议弹框,则显示 diff --git a/lib/network/network_config.dart b/lib/network/network_config.dart index a86d420..031c1a8 100644 --- a/lib/network/network_config.dart +++ b/lib/network/network_config.dart @@ -4,6 +4,7 @@ import 'package:dating_touchme_app/controller/home/home_controller.dart'; import 'package:dating_touchme_app/controller/message/conversation_controller.dart'; import 'package:dating_touchme_app/controller/mine/mine_controller.dart'; import 'package:dating_touchme_app/im/im_manager.dart'; +import 'package:dating_touchme_app/pages/mine/real_login_page.dart'; import 'package:dio/dio.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart' hide Response; @@ -176,6 +177,6 @@ class ResponseInterceptor extends Interceptor { // 清除全局数据 GlobalData().logout(); - Get.offAll(() => LoginPage()); + Get.offAll(() => RealLoginPage()); } } \ No newline at end of file diff --git a/lib/pages/home/real_home_page.dart b/lib/pages/home/real_home_page.dart index 5e249b8..73b9b68 100644 --- a/lib/pages/home/real_home_page.dart +++ b/lib/pages/home/real_home_page.dart @@ -2,6 +2,7 @@ import 'package:dating_touchme_app/components/page_appbar.dart'; import 'package:dating_touchme_app/components/sphere_cloud.dart'; import 'package:dating_touchme_app/controller/home/real_home_controller.dart'; import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/pages/home/real_home_timeline_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; @@ -137,6 +138,24 @@ class _RealHomePageState extends State with AutomaticKeepAliveClie ], ), SizedBox(height: 7.w,), + Wrap( + spacing: 5.w, + runSpacing: 5.w, + children: [ + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + RealHomeTimelineItem(), + ], + ) ], ), ), diff --git a/lib/pages/home/real_home_timeline_item.dart b/lib/pages/home/real_home_timeline_item.dart new file mode 100644 index 0000000..0a57626 --- /dev/null +++ b/lib/pages/home/real_home_timeline_item.dart @@ -0,0 +1,85 @@ +import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class RealHomeTimelineItem extends StatefulWidget { + const RealHomeTimelineItem({super.key}); + + @override + State createState() => _RealHomeTimelineItemState(); +} + +class _RealHomeTimelineItemState extends State { + @override + Widget build(BuildContext context) { + return ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(8.w)), + child: Container( + width: 170.w, + height: 205.w, + color: Colors.white, + child: Column( + children: [ + Image.asset( + Assets.imagesUserAvatar, + width: 170.w, + height: 170.w, + ), + Container( + width: 170.w, + height: 35.w, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(23.w)), + child: Image.asset( + Assets.imagesUserAvatar, + width: 23.w, + height: 23.w, + ), + ), + SizedBox(width: 3.w,), + Text( + "大西瓜", + style: TextStyle( + fontSize: 12.w, + fontWeight: FontWeight.w400 + ), + ) + ], + ), + Row( + children: [ + Row( + children: [ + Image.asset( + (false) ? Assets.imagesLikeActive : Assets.imagesLikeIcon, + width: 14.w, + height: 12.w, + ), + SizedBox(width: 6.w,), + Text( + "${23}", + style: TextStyle( + fontSize: 11.w, + color: const Color.fromRGBO(144, 144, 144, .6) + ), + ) + ], + ) + ], + ) + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/pages/mine/phone_login_page.dart b/lib/pages/mine/phone_login_page.dart new file mode 100644 index 0000000..74fe76e --- /dev/null +++ b/lib/pages/mine/phone_login_page.dart @@ -0,0 +1,169 @@ +import 'package:dating_touchme_app/controller/mine/login_controller.dart'; +import 'package:dating_touchme_app/extension/ex_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:pinput/pinput.dart'; + +class PhoneLoginPage extends StatelessWidget { + const PhoneLoginPage({super.key}); + + @override + Widget build(BuildContext context) { + return GetX( + init: LoginController(), + builder: (controller){ + return Scaffold( + backgroundColor: Colors.white, + body: !(controller.isSend.value) ? Container( + width: 375.w, + padding: EdgeInsets.only( + top: 310.w, + left: 25.w, + right: 25.w + ), + child: Column( + children: [ + Container( + height: 52.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(9.w)), + border: Border.all(width: 1.w, color: const Color.fromRGBO(230, 230, 230, 1)) + ), + child: Center( + child: TextField( + decoration: const InputDecoration( + hintText: '请输入你的手机号', + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 15, + vertical: 0, + ), + counterText: '', + ), + keyboardType: TextInputType.phone, + inputFormatters: [ + // 只允许 0-9 + FilteringTextInputFormatter.digitsOnly, + ], + maxLength: 11, + onChanged: (value) { + controller.phoneNumber.value = value; + }, + style: const TextStyle(fontSize: 16), + ), + ), + ), + SizedBox(height: 10.w,), + Text( + "未注册的手机号将在登录后自动注册", + style: TextStyle( + fontSize: 11.w, + color: const Color.fromRGBO(189, 189, 189, 1) + ), + ), + SizedBox(height: 30.w,), + Container( + width: 325.w, + height: 52.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(52.w)), + gradient: controller.phoneNumber.value.isNotEmpty ? LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Color.fromRGBO(131, 89, 255, 1), + Color.fromRGBO(61, 138, 224, 1), + ], + ) : null, + color: const Color.fromRGBO(217, 217, 217, 1) + ), + child: Center( + child: Text( + "获取验证码", + style: TextStyle( + fontSize: 18.w, + color: Colors.white + ), + ), + ), + ).onTap(() { + controller.isSendingCode.value || + controller.countdownSeconds.value > 0 + ? null + : controller.getVerificationCode(); + }), + ], + ), + ) : Container( + width: 375.w, + padding: EdgeInsets.only( + top: 271.w, + left: 25.w, + right: 25.w + ), + child: Column( + children: [ + Text( + "已发送到${controller.phoneNumber.value}", + style: TextStyle( + fontSize: 14.w + ), + ), + SizedBox(height: 20.w,), + + Pinput( + length: 6, + controller: controller.passwordController.value, + inputFormatters: [ + // 只允许 0-9 + FilteringTextInputFormatter.digitsOnly, + ], + onCompleted: (pin) { + controller.verificationCode.value = pin; + controller.isLoggingIn.value + ? null + : controller.login(); + }, + ), + SizedBox(height: 40.w,), + Container( + width: 325.w, + height: 52.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(52.w)), + gradient: controller.countdownSeconds.value <= 0 ? LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Color.fromRGBO(131, 89, 255, 1), + Color.fromRGBO(61, 138, 224, 1), + ], + ) : null, + color: const Color.fromRGBO(217, 217, 217, 1) + ), + child: Center( + child: Text( + controller.countdownSeconds.value > 0 ? "获取验证码 ${controller.countdownSeconds.value}s" : "获取验证码", + style: TextStyle( + fontSize: 18.w, + color: Colors.white + ), + ), + ), + ).onTap(() { + controller.isSendingCode.value || + controller.countdownSeconds.value > 0 + ? null + : controller.getVerificationCode(); + }), + ], + ), + ), + ); + }, + ); + } +} + diff --git a/lib/pages/mine/real_login_page.dart b/lib/pages/mine/real_login_page.dart new file mode 100644 index 0000000..8ee1f84 --- /dev/null +++ b/lib/pages/mine/real_login_page.dart @@ -0,0 +1,104 @@ +import 'package:dating_touchme_app/extension/ex_widget.dart'; +import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/pages/mine/phone_login_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + +class RealLoginPage extends StatefulWidget { + const RealLoginPage({super.key}); + + @override + State createState() => _RealLoginPageState(); +} + +class _RealLoginPageState extends State { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + width: 375.w, + height: 812.h, + color: Colors.white, + ), + Image.asset( + Assets.imagesRealLoginBg, + width: 375.w, + fit: BoxFit.cover, + alignment: AlignmentGeometry.topCenter, + ), + Image.asset( + Assets.imagesLoginBgWhite, + width: 375.w, + fit: BoxFit.cover, + alignment: AlignmentGeometry.topCenter, + ), + Scaffold( + backgroundColor: Colors.transparent, + body: Container( + width: 375.w, + padding: EdgeInsets.only( + top: 126.w, + left: 20.w, + right: 20.w + ), + child: Column( + children: [ + Image.asset( + Assets.imagesRealLogo, + width: 55.w, + height: 55.w, + ), + SizedBox(height: 12.w,), + Text( + "快乐星球", + style: TextStyle( + fontSize: 24.w + ), + ), + SizedBox(height: 261.w,), + Container( + width: 335.w, + height: 52.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(52.w)), + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Color.fromRGBO(131, 89, 255, 1), + Color.fromRGBO(61, 138, 224, 1), + ], + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.phone_iphone, + size: 28.w, + color: Colors.white, + ), + SizedBox(width: 12.w,), + Text( + "手机登录注册", + style: TextStyle( + fontSize: 18.w, + color: Colors.white + ), + ) + ], + ), + ).onTap(() { + Get.to(() => PhoneLoginPage()); + }), + + ], + ), + ), + ) + ], + ); + } +} diff --git a/lib/pages/setting/deactivate_page.dart b/lib/pages/setting/deactivate_page.dart index b0801cb..4f9c720 100644 --- a/lib/pages/setting/deactivate_page.dart +++ b/lib/pages/setting/deactivate_page.dart @@ -3,6 +3,7 @@ import 'package:dating_touchme_app/controller/mine/deactivate_controller.dart'; import 'package:dating_touchme_app/extension/ex_widget.dart'; import 'package:dating_touchme_app/generated/assets.dart'; import 'package:dating_touchme_app/pages/mine/login_page.dart'; +import 'package:dating_touchme_app/pages/mine/real_login_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; @@ -164,7 +165,7 @@ class DeactivatePage extends StatelessWidget { ), onTap: () { controller.logout(); - Get.offAll(() => LoginPage()); + Get.offAll(() => RealLoginPage()); }, ), ], diff --git a/lib/pages/setting/setting_page.dart b/lib/pages/setting/setting_page.dart index 3043ca7..f13933a 100644 --- a/lib/pages/setting/setting_page.dart +++ b/lib/pages/setting/setting_page.dart @@ -15,6 +15,7 @@ import 'package:tdesign_flutter/tdesign_flutter.dart'; import '../../components/page_appbar.dart'; import '../../controller/setting/setting_controller.dart'; +import '../mine/real_login_page.dart'; import 'blacklist_page.dart'; import 'notice_page.dart'; @@ -183,7 +184,7 @@ class SettingPage extends StatelessWidget { ), onTap: () { controller.logout(); - Get.offAll(() => LoginPage()); + Get.offAll(() => RealLoginPage()); }, ), ],