import 'package:common_pub/screen.dart'; import 'package:common_pub/utils.dart'; import 'package:flutter/gestures.dart'; import 'package:rive/rive.dart'; import 'package:track_common/widget/prelude.dart'; import 'common.dart'; import 'login_controller.dart'; class LoginView extends GetView { static const name = '/LoginView'; const LoginView({super.key}); static Future to({ bool canBack = true, VoidCallback? thenToPageCall, }) async { Future? r; if (canBack) { r = Get.toNamed(LoginView.name, arguments: thenToPageCall); } else { r = Get.offAllNamed(LoginView.name, arguments: thenToPageCall); } if (r != null) { final r2 = await r; if (r2 is bool) { return r2; } } return false; } @override Widget build(BuildContext context) { return Scaffold( // appBar: AppTopBar(title: '登录账号', hasBackText: true, height: context.height*0.3), backgroundColor: Colors.white, body: Container( height: double.infinity, decoration: const BoxDecoration(color: Colors.white), alignment: Alignment.center, clipBehavior: Clip.hardEdge, child: Row( children: [ const Expanded( flex: 2, child: AnimationPage(), ), Expanded( flex: 3, child: wPageRight(context), ) ], ), ), ); } Widget wPageRight(BuildContext context) { var inputHeight = context.height * 0.45; const inputMinHeight = 260.0; if (inputHeight < inputMinHeight) { inputHeight = inputMinHeight; } return Container( // margin: EdgeInsets.fromLTRB(context.width*(6), context.width*5.6), context.width*(6), context.width*(2)), padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), decoration: const BoxDecoration( // color: Color(0xffffcb00), image: DecorationImage( image: AssetImage(Assets.imagesBkLoginRight, package: package), alignment: Alignment.topCenter, fit: BoxFit.fitWidth), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Spacer(), Text( '定向运动活动现场监控系统', textAlign: TextAlign.center, style: TextStyle(fontSize: 29.87, fontWeight: FontWeight.w500), ), // Expanded(child: wInput(context)), SizedBox(height: inputHeight, child: wInput(context)), Image.asset(Assets.imagesIcLoginLogo, height: 24, package: package), Spacer() // Expanded(flex: 10,child: wExtra()), ], )); } InputDecoration wInputDecoration(hintText) { return InputDecoration( // isCollapsed: true, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), hintText: hintText, // hintStyle: TextStyle(fontSize: 12.0.rpx), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.0), borderSide: const BorderSide( color: Colors.blue, width: 1.0, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.0), borderSide: const BorderSide( color: Color(0xffaaaaaa), width: 1.0, ), ), ); } Widget wInput(BuildContext context) { return Container( width: 432.8, height: 424, margin: EdgeInsets.only(top: 22.04, bottom: 21), padding: EdgeInsets.fromLTRB( context.wp(6), context.wp(3.6), context.wp(6), context.wp(2)), decoration: BoxDecoration( color: const Color(0xffffffff), borderRadius: BorderRadius.circular(context.wp(1.0)), boxShadow: const [ BoxShadow( color: Color(0x38000000), offset: Offset(0.0, 3.0), blurRadius: 6) ], ), child: Column( children: [ // const Spacer(flex: 20), TextFormField( decoration: wInputDecoration('请输入手机号'), validator: (String? value) { if (value == null || !value.isPhoneNumber) { return '请输入正确的手机号'; } return null; }, onChanged: (value) { controller.phone.value = value; }, keyboardType: TextInputType.phone), const Spacer(flex: 50), Stack( alignment: Alignment.centerRight, children: [ TextFormField( decoration: wInputDecoration('请输入验证码'), onChanged: (value) { controller.password.value = value; }, keyboardType: TextInputType.number, ), Padding( padding: const EdgeInsets.only(right: 4), child: SizedBox( width: 84, height: 37, child: Obx(() => GetCodeButton( codeRetryLeft: controller.codeRetryLeft.value, onPressed: () => controller.onGetCode(), )), ), ), ], ), // _TextContract(), const Spacer(flex: 80), button( context, '登 录', () => controller.onSignIn(), ), const Spacer(flex: 10), ], )); } Widget wExtra() { return Padding( padding: const EdgeInsets.only(left: 41.67, right: 41.67), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ divider(), const Padding( padding: EdgeInsets.only(left: 22.9, right: 22.9), child: Text( '其他登录方式', style: TextStyle(fontSize: 25.0), )), divider(), ], ), const SizedBox(height: 76.5), const Row(), const Spacer(), Text.rich(TextSpan( text: '还不是我们的会员?', style: const TextStyle(fontSize: 33.33, color: Colors.black), children: [ TextSpan( text: '点击注册', style: const TextStyle(color: Color(0xffffb40b)), recognizer: TapGestureRecognizer() ..onTap = () { // SignUpView.show(); }, ), ])), const SizedBox(height: 76.5), ], )); } Widget divider() { return Expanded( child: Container( height: 2.0, color: Colors.black, )); } } final _duration = 2.seconds; class AnimationPage extends StatefulWidget { const AnimationPage({super.key}); @override State createState() { return _AnimationPageState(); } } class _AnimationPageState extends State with SingleTickerProviderStateMixin { late Animation animation; late AnimationController animationController; @override void initState() { super.initState(); animationController = AnimationController(duration: _duration, vsync: this); animation = Tween(begin: 0, end: 1).animate(animationController); animationController.forward(); } @override void dispose() { animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return wPageLeft(context); } Widget wPageLeft(BuildContext context) { return Container( padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), decoration: const BoxDecoration( image: DecorationImage( image: AssetImage(Assets.imagesBkCommonPage, package: package), fit: BoxFit.cover)), child: Column( children: [ Expanded( flex: 1, child: Container( // color: const Color(0xffffcb00), padding: const EdgeInsets.only(bottom: 32), alignment: Alignment.bottomCenter, child: Stack( alignment: Alignment.center, children: [ Image.asset( Assets.imagesImCompassNoMap, height: context.wp(15.0), fit: BoxFit.fitHeight, package: package, ), SizedBox( height: context.wp(10.0), child: const RiveAnimation.asset( 'packages/$package/${Assets.imagesAmAppStartArrow}', fit: BoxFit.fitHeight, )) ], ), )), Expanded( flex: 1, child: Column( // mainAxisAlignment: MainAxisAlignment.start, children: [ AnimatedText(animation: animation), Expanded( child: Stack( alignment: Alignment.center, children: [ Center( child: AnimatedColors( animation: animation, ), ), // Positioned( // bottom: 2.6.width*, // child: // Image.asset(Assets.imagesIcLogo, height: 5.0.width*)) ], )) ], )), ], ), ); } } class AnimatedText extends AnimatedWidget { const AnimatedText({super.key, required Animation animation}) : super(listenable: animation); @override Widget build(BuildContext context) { final animation = listenable as Animation; var style = (context.textTheme.titleLarge ?? const TextStyle()).copyWith( height: context.wp(0.14), color: Colors.white, fontSize: context.wp(2.2)); return Opacity( opacity: animation.value, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( height: context.wp(0.9), ), Text('确定方向 ', style: style), Text(' 发现你自己的路!', style: style), Text('Orienting, Discover Your Own Way!', style: style.copyWith( color: const Color(0xffade0ff), fontWeight: FontWeight.bold, fontSize: context.wp(1.4))), ], )); } } class AnimatedColors extends AnimatedWidget { const AnimatedColors({super.key, required Animation animation}) : super(listenable: animation); @override Widget build(BuildContext context) { final animation = listenable as Animation; var style = (context.textTheme.titleLarge ?? const TextStyle()) .copyWith(color: Colors.white, fontSize: context.wp(8.33)); var children = []; for (var i = 0; i < hrPColors.length; i++) { final color = hrPColors[i]; var opacity = 0.0; if (i < animation.value * hrPColors.length) { opacity = 1; } children.add(Opacity( opacity: opacity, child: Container( width: context.wp(1.02), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(context.wp(2.0)), border: Border.all(color: Colors.white.withAlpha(100))), ))); } return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: context.wp(5.36)), SizedBox( width: context.wp(7.6), height: context.wp(2.5), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: children, )), // Text('支持心率带检测身体数据', // style: style.copyWith( // color: const Color(0xffffcb00), fontSize: 3.3.width*)), ], ); } }