Browse Source
Merge branch 'ios' of http://git.qniao.cn/dating-agency/dating_touchme_app into ios
Merge branch 'ios' of http://git.qniao.cn/dating-agency/dating_touchme_app into ios
# Conflicts: # ios/Podfile.lockios
38 changed files with 1019 additions and 113 deletions
Unified View
Diff Options
-
BIN.DS_Store
-
BINassets/images/login_bg_white.png
-
BINassets/images/real_login_bg.png
-
BINassets/images/real_logo.png
-
BINassets/images/square_nol.png
-
BINassets/images/square_pre.png
-
BINassets/images/star.png
-
BINassets/images/star_sky_bg.png
-
BINassets/images/test1.png
-
BINassets/images/test2.png
-
BINassets/images/test_bg.png
-
1ios/Podfile
-
156ios/Podfile.lock
-
166lib/components/sphere_cloud.dart
-
45lib/controller/home/real_home_controller.dart
-
16lib/controller/mine/edit_info_controller.dart
-
4lib/controller/mine/login_controller.dart
-
10lib/generated/assets.dart
-
3lib/im/im_manager.dart
-
5lib/main.dart
-
3lib/network/network_config.dart
-
183lib/pages/home/real_home_page.dart
-
85lib/pages/home/real_home_timeline_item.dart
-
8lib/pages/home/recommend_tab.dart
-
2lib/pages/home/send_timeline.dart
-
53lib/pages/home/test_page.dart
-
12lib/pages/home/timeline_info.dart
-
13lib/pages/home/timeline_item.dart
-
4lib/pages/home/timeline_page.dart
-
4lib/pages/home/user_information_page.dart
-
7lib/pages/main/main_page.dart
-
60lib/pages/mine/mine_page.dart
-
169lib/pages/mine/phone_login_page.dart
-
104lib/pages/mine/real_login_page.dart
-
3lib/pages/setting/deactivate_page.dart
-
3lib/pages/setting/setting_page.dart
-
11lib/widget/message/voice_input_view.dart
-
2pubspec.yaml
@ -0,0 +1,166 @@ |
|||||
|
import 'dart:math' as math; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class SphereCloud extends StatefulWidget { |
||||
|
SphereCloud({ |
||||
|
super.key, |
||||
|
required this.items, |
||||
|
this.radius = 140, |
||||
|
required this.itemSize, |
||||
|
this.cameraZ = 360, // 相机离球心距离,越大透视越弱 |
||||
|
this.focal = 320, // 焦距,影响投影与缩放 |
||||
|
this.minScale = 0.45, |
||||
|
this.maxScale = 1.25, |
||||
|
}); |
||||
|
|
||||
|
final List<Widget> items; |
||||
|
final double radius; |
||||
|
final double itemSize; |
||||
|
final double cameraZ; |
||||
|
final double focal; |
||||
|
final double minScale; |
||||
|
final double maxScale; |
||||
|
|
||||
|
@override |
||||
|
State<SphereCloud> createState() => _SphereCloudState(); |
||||
|
} |
||||
|
|
||||
|
class _SphereCloudState extends State<SphereCloud> { |
||||
|
late final List<_Point3> _points; |
||||
|
|
||||
|
// 当前旋转角(弧度) |
||||
|
double _rotX = 0.0; |
||||
|
double _rotY = 0.0; |
||||
|
|
||||
|
@override |
||||
|
void initState() { |
||||
|
super.initState(); |
||||
|
_points = _genFibonacciSphere(widget.items.length, widget.radius); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void didUpdateWidget(covariant SphereCloud oldWidget) { |
||||
|
super.didUpdateWidget(oldWidget); |
||||
|
if (oldWidget.items.length != widget.items.length || |
||||
|
oldWidget.radius != widget.radius) { |
||||
|
_points |
||||
|
..clear() |
||||
|
..addAll(_genFibonacciSphere(widget.items.length, widget.radius)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return LayoutBuilder(builder: (_, c) { |
||||
|
final cx = c.maxWidth / 2; |
||||
|
final cy = c.maxHeight / 2; |
||||
|
|
||||
|
// 计算每个点投影后的 2D 信息 |
||||
|
final projected = <_ProjectedItem>[]; |
||||
|
for (int i = 0; i < _points.length; i++) { |
||||
|
final p = _rotate(_points[i], _rotX, _rotY); |
||||
|
|
||||
|
// 透视:避免 cameraZ - z 过小导致爆炸 |
||||
|
final denom = (widget.cameraZ - p.z).clamp(40.0, 1e9); |
||||
|
final perspective = widget.focal / denom; |
||||
|
|
||||
|
final x2 = cx + p.x * perspective; |
||||
|
final y2 = cy + p.y * perspective; |
||||
|
|
||||
|
final scale = perspective.clamp(widget.minScale, widget.maxScale); |
||||
|
|
||||
|
projected.add(_ProjectedItem( |
||||
|
index: i, |
||||
|
x: x2, |
||||
|
y: y2, |
||||
|
z: p.z, |
||||
|
scale: scale, |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
// 按 z 排序:远->近 |
||||
|
projected.sort((a, b) => a.z.compareTo(b.z)); |
||||
|
|
||||
|
return GestureDetector( |
||||
|
behavior: HitTestBehavior.opaque, |
||||
|
onPanUpdate: (d) { |
||||
|
// 你可以按手感调整系数 |
||||
|
setState(() { |
||||
|
_rotY += d.delta.dx * 0.01; |
||||
|
_rotX -= d.delta.dy * 0.01; |
||||
|
}); |
||||
|
}, |
||||
|
child: Stack( |
||||
|
clipBehavior: Clip.none, |
||||
|
children: [ |
||||
|
for (final it in projected) |
||||
|
Positioned( |
||||
|
left: it.x - widget.itemSize / 2, |
||||
|
top: it.y - widget.itemSize / 2, |
||||
|
child: Transform.scale( |
||||
|
scale: it.scale, |
||||
|
child: SizedBox( |
||||
|
width: widget.itemSize, |
||||
|
height: widget.itemSize, |
||||
|
child: widget.items[it.index], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// Fibonacci sphere:简单、分布均匀(比随机更像“均匀铺满球面”) |
||||
|
List<_Point3> _genFibonacciSphere(int n, double r) { |
||||
|
if (n <= 0) return []; |
||||
|
final pts = <_Point3>[]; |
||||
|
final offset = 2.0 / n; |
||||
|
final increment = math.pi * (3.0 - math.sqrt(5.0)); // golden angle |
||||
|
for (int i = 0; i < n; i++) { |
||||
|
final y = ((i * offset) - 1) + (offset / 2); |
||||
|
final rr = math.sqrt(1 - y * y); |
||||
|
final phi = i * increment; |
||||
|
final x = math.cos(phi) * rr; |
||||
|
final z = math.sin(phi) * rr; |
||||
|
pts.add(_Point3(x * r, y * r, z * r)); |
||||
|
} |
||||
|
return pts; |
||||
|
} |
||||
|
|
||||
|
// 绕 X/Y 旋转(右手系) |
||||
|
_Point3 _rotate(_Point3 p, double rx, double ry) { |
||||
|
// rotate around X |
||||
|
final cosX = math.cos(rx), sinX = math.sin(rx); |
||||
|
var y1 = p.y * cosX - p.z * sinX; |
||||
|
var z1 = p.y * sinX + p.z * cosX; |
||||
|
|
||||
|
// rotate around Y |
||||
|
final cosY = math.cos(ry), sinY = math.sin(ry); |
||||
|
var x2 = p.x * cosY + z1 * sinY; |
||||
|
var z2 = -p.x * sinY + z1 * cosY; |
||||
|
|
||||
|
return _Point3(x2, y1, z2); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class _Point3 { |
||||
|
_Point3(this.x, this.y, this.z); |
||||
|
final double x, y, z; |
||||
|
} |
||||
|
|
||||
|
class _ProjectedItem { |
||||
|
_ProjectedItem({ |
||||
|
required this.index, |
||||
|
required this.x, |
||||
|
required this.y, |
||||
|
required this.z, |
||||
|
required this.scale, |
||||
|
}); |
||||
|
|
||||
|
final int index; |
||||
|
final double x, y, z; |
||||
|
final double scale; |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
import 'package:dating_touchme_app/model/home/marriage_data.dart'; |
||||
|
import 'package:dating_touchme_app/network/home_api.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
|
||||
|
class RealHomeController extends GetxController { |
||||
|
|
||||
|
late final HomeApi _homeApi; |
||||
|
// 推荐列表数据 |
||||
|
final recommendFeed = <MarriageData>[].obs; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
// 从全局依赖中获取HomeApi |
||||
|
_homeApi = Get.find<HomeApi>(); |
||||
|
getListData(); |
||||
|
} |
||||
|
|
||||
|
getListData() async { |
||||
|
try { |
||||
|
var response = await _homeApi.getMarriageList( |
||||
|
pageNum: 1, |
||||
|
pageSize: 100, |
||||
|
type: 0, |
||||
|
); |
||||
|
if (response.data.isSuccess) { |
||||
|
final allRecords = response.data.data!.records |
||||
|
.map((item) => MarriageData.fromJson(item as Map<String, dynamic>)) |
||||
|
.toList(); |
||||
|
|
||||
|
// 过滤掉直播类型的项 |
||||
|
final records = allRecords!.where((item) => !item.isLive).toList(); |
||||
|
recommendFeed.addAll(records); |
||||
|
update(); |
||||
|
} else { |
||||
|
// 响应失败,抛出异常 |
||||
|
throw Exception(response.data.message); |
||||
|
} |
||||
|
} catch(e) { |
||||
|
// 向上抛出异常,让调用方处理 |
||||
|
rethrow; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,183 @@ |
|||||
|
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/extension/ex_widget.dart'; |
||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:dating_touchme_app/pages/home/real_home_timeline_item.dart'; |
||||
|
import 'package:dating_touchme_app/pages/home/test_page.dart'; |
||||
|
import 'package:dating_touchme_app/pages/home/user_information_page.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
|
||||
|
class RealHomePage extends StatefulWidget { |
||||
|
const RealHomePage({super.key}); |
||||
|
|
||||
|
@override |
||||
|
State<RealHomePage> createState() => _RealHomePageState(); |
||||
|
} |
||||
|
|
||||
|
class _RealHomePageState extends State<RealHomePage> with AutomaticKeepAliveClientMixin { |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
super.build(context); |
||||
|
return GetBuilder<RealHomeController>( |
||||
|
init: RealHomeController(), |
||||
|
builder: (controller){ |
||||
|
return Stack( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
Assets.imagesStarSkyBg, |
||||
|
width: 375.w, |
||||
|
fit: BoxFit.cover, |
||||
|
alignment: AlignmentGeometry.topCenter, |
||||
|
), |
||||
|
Scaffold( |
||||
|
backgroundColor: Colors.transparent, |
||||
|
appBar: PageAppbar(title: "快乐星球", color: Colors.white, backgroundColor: Colors.transparent,), |
||||
|
body: Container( |
||||
|
width: 375.w, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 15.w), |
||||
|
child: SingleChildScrollView( |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
SizedBox( |
||||
|
width: 345.w, |
||||
|
height: 345.w, |
||||
|
child: SphereCloud( |
||||
|
itemSize: 36.w, |
||||
|
items: [ |
||||
|
...controller.recommendFeed.map((e){ |
||||
|
return SizedBox( |
||||
|
width: 36.w, |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
Text( |
||||
|
e.nickName, |
||||
|
maxLines: 1, |
||||
|
overflow: TextOverflow.ellipsis, |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.w, |
||||
|
color: Colors.white, |
||||
|
fontWeight: FontWeight.w400 |
||||
|
), |
||||
|
), |
||||
|
Image.asset( |
||||
|
Assets.imagesStar, |
||||
|
width: 18.w, |
||||
|
height: 18.w, |
||||
|
fit: BoxFit.cover, |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
).onTap((){ |
||||
|
Get.to(() => UserInformationPage(miId: e.miId, userId: e.userId,)); |
||||
|
}); |
||||
|
}), |
||||
|
] |
||||
|
), |
||||
|
), |
||||
|
Container( |
||||
|
width: 92.w, |
||||
|
height: 21.w, |
||||
|
margin: EdgeInsets.symmetric(vertical: 20.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(21.w)), |
||||
|
color: const Color.fromRGBO(255, 255, 255, .1) |
||||
|
), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
Icon( |
||||
|
Icons.autorenew, |
||||
|
size: 18.w, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
SizedBox(width: 4.w,), |
||||
|
Text( |
||||
|
"换一批", |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.w, |
||||
|
color: Colors.white |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
Row( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"趣味测试", |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.w, |
||||
|
color: Colors.white |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 7.w,), |
||||
|
Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
Assets.imagesTest1, |
||||
|
width: 170.w, |
||||
|
).onTap(() { |
||||
|
Get.to(() => TestPage()); |
||||
|
}), |
||||
|
Image.asset( |
||||
|
Assets.imagesTest2, |
||||
|
width: 170.w, |
||||
|
).onTap(() { |
||||
|
Get.to(() => TestPage()); |
||||
|
}), |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 15.w,), |
||||
|
Row( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"热门帖子", |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.w, |
||||
|
color: Colors.white |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 7.w,), |
||||
|
Wrap( |
||||
|
spacing: 5.w, |
||||
|
runSpacing: 5.w, |
||||
|
children: [ |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
RealHomeTimelineItem(), |
||||
|
], |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@override |
||||
|
bool get wantKeepAlive => true; |
||||
|
} |
||||
|
|
||||
@ -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<RealHomeTimelineItem> createState() => _RealHomeTimelineItemState(); |
||||
|
} |
||||
|
|
||||
|
class _RealHomeTimelineItemState extends State<RealHomeTimelineItem> { |
||||
|
@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) |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
) |
||||
|
], |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
import 'package:dating_touchme_app/components/page_appbar.dart'; |
||||
|
import 'package:dating_touchme_app/generated/assets.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class TestPage extends StatelessWidget { |
||||
|
const TestPage({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Stack( |
||||
|
children: [ |
||||
|
Image.asset( |
||||
|
Assets.imagesTestBg, |
||||
|
width: 375.w, |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
Scaffold( |
||||
|
backgroundColor: Colors.transparent, |
||||
|
appBar: PageAppbar(title: "人格类型测试", color: Colors.white, backgroundColor: Colors.transparent,), |
||||
|
body: Container( |
||||
|
width: 375.w, |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
vertical: 40.w, |
||||
|
horizontal: 12.w |
||||
|
), |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 350.w, |
||||
|
padding: EdgeInsets.all(30.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(16.w)), |
||||
|
color: const Color.fromRGBO(39, 48, 89, 1) |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"在陌生环境中,你通常会在陌生环境中,你通常会在陌生环境中,你通常会", |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.w, |
||||
|
color: Colors.white |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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<LoginController>( |
||||
|
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(); |
||||
|
}), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -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<RealLoginPage> createState() => _RealLoginPageState(); |
||||
|
} |
||||
|
|
||||
|
class _RealLoginPageState extends State<RealLoginPage> { |
||||
|
@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()); |
||||
|
}), |
||||
|
|
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save