Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
book-app
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
book-app
Commits
de62e122
提交
de62e122
authored
1月 03, 2024
作者:
yueweilu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
登录界面
上级
e695958e
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
233 行增加
和
36 行删除
+233
-36
controller.dart
lib/pages/login/controller.dart
+69
-3
index.dart
lib/pages/login/index.dart
+2
-0
view.dart
lib/pages/login/view.dart
+95
-33
validator.dart
lib/utils/validator.dart
+18
-0
button.dart
lib/widgets/button.dart
+49
-0
没有找到文件。
lib/pages/login/controller.dart
浏览文件 @
de62e122
...
@@ -5,18 +5,75 @@ enum LoginType{code, password}
...
@@ -5,18 +5,75 @@ enum LoginType{code, password}
class
LoginController
extends
GetxController
{
class
LoginController
extends
GetxController
{
/// 2、密码登录
// 0:密码登录 1:验证码登录
/// 账号
late
int
loginType
=
0
;
// 2、密码登录
// 账号
final
TextEditingController
phoneInput
=
TextEditingController
();
final
TextEditingController
phoneInput
=
TextEditingController
();
//
/
密码
// 密码
final
TextEditingController
passwordInput
=
TextEditingController
();
final
TextEditingController
passwordInput
=
TextEditingController
();
// 验证码
final
TextEditingController
codeInput
=
TextEditingController
();
// 显示密码
// 显示密码
final
ValueNotifier
<
bool
>
showPassword
=
ValueNotifier
(
false
);
final
ValueNotifier
<
bool
>
showPassword
=
ValueNotifier
(
false
);
// 定时器
late
Timer
_timer
;
// 按钮是否可用
bool
_enable
=
false
;
bool
get
enable
=>
_enable
;
// 倒计时60秒
int
_countDown
=
60
;
int
get
countDown
=>
_countDown
;
bool
_isCounting
=
false
;
bool
get
isCounting
=>
_isCounting
;
// 同意协议
bool
_agree
=
false
;
bool
get
agree
=>
_agree
;
void
setAgree
()
{
_agree
=
!
_agree
;
}
// 开启定时器
void
start
()
{
_isCounting
=
true
;
_timer
=
Timer
.
periodic
(
const
Duration
(
seconds:
1
),
(
timer
)
{
if
(
_countDown
>
1
)
{
_countDown
--;
}
else
{
stop
();
}
update
();
});
}
// 停止计时器
void
stop
()
{
if
(
_timer
!=
null
){
_timer
.
cancel
();
_isCounting
=
false
;
}
_countDown
=
60
;
}
void
setCanClick
(){
if
(
phoneInput
.
text
.
length
==
11
&&
passwordInput
.
text
.
length
==
4
){
_enable
=
true
;
}
else
{
_enable
=
false
;
}
update
();
}
@override
@override
void
onInit
()
{
void
onInit
()
{
_timer
=
Timer
.
periodic
(
const
Duration
(
seconds:
1
),
(
timer
)
{
// 定时器回调
});
/// 测试账号
/// 测试账号
if
(
kDebugMode
)
{
if
(
kDebugMode
)
{
phoneInput
.
text
=
'13521054068'
;
phoneInput
.
text
=
'13521054068'
;
...
@@ -30,11 +87,20 @@ class LoginController extends GetxController {
...
@@ -30,11 +87,20 @@ class LoginController extends GetxController {
phoneInput
.
dispose
();
phoneInput
.
dispose
();
passwordInput
.
dispose
();
passwordInput
.
dispose
();
showPassword
.
dispose
();
showPassword
.
dispose
();
codeInput
.
dispose
();
_timer
.
cancel
();
_isCounting
=
false
;
super
.
onClose
();
super
.
onClose
();
}
}
void
onShowPassword
()
=>
showPassword
.
value
=
!
showPassword
.
value
;
void
onShowPassword
()
=>
showPassword
.
value
=
!
showPassword
.
value
;
void
updateLoginType
(
int
value
){
stop
();
loginType
=
value
;
update
();
}
Future
<
bool
>
onLogin
(
GlobalKey
<
FormState
>
key
)
async
{
Future
<
bool
>
onLogin
(
GlobalKey
<
FormState
>
key
)
async
{
final
result
=
AccountAPI
.
login
(
final
result
=
AccountAPI
.
login
(
...
...
lib/pages/login/index.dart
浏览文件 @
de62e122
library
login
;
library
login
;
import
'dart:async'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/services.dart'
;
...
...
lib/pages/login/view.dart
浏览文件 @
de62e122
...
@@ -11,6 +11,8 @@ class LoginPage extends StatefulWidget {
...
@@ -11,6 +11,8 @@ class LoginPage extends StatefulWidget {
class
_LoginPageState
extends
State
<
LoginPage
>
{
class
_LoginPageState
extends
State
<
LoginPage
>
{
final
_formKey
=
GlobalKey
<
FormState
>();
final
_formKey
=
GlobalKey
<
FormState
>();
bool
isChecked
=
false
;
bool
isChecked
=
false
;
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
GetBuilder
<
LoginController
>(
return
GetBuilder
<
LoginController
>(
...
@@ -33,10 +35,18 @@ class _LoginPageState extends State<LoginPage> {
...
@@ -33,10 +35,18 @@ class _LoginPageState extends State<LoginPage> {
right:
25
,
right:
25
,
bottom:
25
bottom:
25
),
),
child:
Column
(
children:
[
Expanded
(
child:
SingleChildScrollView
(
child:
Form
(
child:
Form
(
autovalidateMode:
AutovalidateMode
.
always
,
onChanged:
(){
setState
(()
{
print
(
'++++++++++++++++'
);
});
},
key:
_formKey
,
key:
_formKey
,
child:
Container
(
// color: Colors.green,
child:
Column
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
children:
[
...
@@ -51,15 +61,19 @@ class _LoginPageState extends State<LoginPage> {
...
@@ -51,15 +61,19 @@ class _LoginPageState extends State<LoginPage> {
color:
Colors
.
cyan
,
color:
Colors
.
cyan
,
),
),
const
SizedBox
(
height:
66
),
const
SizedBox
(
height:
66
),
//
CustomFormInput
(
CustomFormInput
(
// label: 'Phone',
// label: 'Phone',
// required: true,
// required: true,
hintText:
'请输入手机号'
,
hintText:
'请输入手机号'
,
keyboardType:
TextInputType
.
number
,
keyboardType:
TextInputType
.
number
,
controller:
controller
.
phoneInput
,
controller:
controller
.
phoneInput
,
validator:
EmailValidator
(),
onChanged:
(
text
){
controller
.
setCanClick
();
},
),
),
Gaps
.
vGaps13
,
Gaps
.
vGaps13
,
(
controller
.
loginType
==
0
)?
ValueListenableBuilder
<
bool
>(
ValueListenableBuilder
<
bool
>(
valueListenable:
controller
.
showPassword
,
valueListenable:
controller
.
showPassword
,
builder:
(
context
,
value
,
child
)
=>
CustomFormInput
(
builder:
(
context
,
value
,
child
)
=>
CustomFormInput
(
...
@@ -68,49 +82,86 @@ class _LoginPageState extends State<LoginPage> {
...
@@ -68,49 +82,86 @@ class _LoginPageState extends State<LoginPage> {
iconData:
iconData:
value
?
Icons
.
visibility
:
Icons
.
visibility_off
,
value
?
Icons
.
visibility
:
Icons
.
visibility_off
,
controller:
controller
.
passwordInput
,
controller:
controller
.
passwordInput
,
validator:
EmailValidator
(),
onChanged:
(
text
){
controller
.
setCanClick
();
},
onIcon:
controller
.
onShowPassword
,
onIcon:
controller
.
onShowPassword
,
),
),
):
Stack
(
alignment:
Alignment
.
centerRight
,
children:
[
CustomFormInput
(
// label: 'Phone',
// required: true,
hintText:
'请输入验证码'
,
keyboardType:
TextInputType
.
number
,
controller:
controller
.
codeInput
,
),
Positioned
(
right:
10
,
child:
Row
(
children:
[
Container
(
height:
20
,
width:
1
,
color:
const
Color
(
0xFFEBEBEB
),),
Gaps
.
hGaps10
,
GestureDetector
(
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
10
),
color:
Colors
.
yellow
,
child:
Text
(
controller
.
isCounting
?
'
${controller.countDown}
'
:
'获取验证码'
,
style:
const
TextStyle
(
fontSize:
11
,
color:
AppTheme
.
primary
,
height:
1.4
),)),
onTap:
(){
controller
.
start
();
},
),
],
)
)
],
),
),
Container
(
Container
(
margin:
const
EdgeInsets
.
only
(
left:
10
,
right:
10
,
top:
8.5
),
margin:
const
EdgeInsets
.
only
(
left:
10
,
right:
10
,
top:
8.5
),
child:
const
Row
(
alignment:
Alignment
.
centerLeft
,
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
children:
[
Text
(
'验证码登录'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
c6
),),
controller
.
loginType
==
0
?
GestureDetector
(
Text
(
'忘记密码'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
cBlue
),),
child:
const
Text
(
'验证码登录'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
c6
),),
],
onTap:
(){
controller
.
updateLoginType
(
1
);
},
):
GestureDetector
(
child:
const
Text
(
'密码登录'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
c6
),),
onTap:
(){
controller
.
updateLoginType
(
0
);
},
),
),
controller
.
loginType
==
0
?
const
Text
(
'忘记密码'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
cBlue
),):
const
Text
(
'*登录后将自动完成注册'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
c6
),),
],
)
),
),
const
SizedBox
(
height:
30
,),
const
SizedBox
(
height:
30
,),
// 登录按钮
CustomGradientButton
(
Container
(
text:
'立即登录'
,
height:
42
,
isEnabled:
!
controller
.
enable
,
width:
double
.
infinity
,
onPressed:
()
{
decoration:
BoxDecoration
(
gradient:
const
LinearGradient
(
colors:
[
Color
(
0xFFDE2E5E
),
Color
(
0xFFC31F4C
)],
begin:
Alignment
.
centerLeft
,
end:
Alignment
.
centerRight
),
borderRadius:
BorderRadius
.
circular
(
21
),
),
child:
TextButton
(
onPressed:
()
async
{
FocusScope
.
of
(
context
).
requestFocus
(
FocusNode
());
final
result
=
await
controller
.
onLogin
(
_formKey
);
},
},
style:
TextButton
.
styleFrom
(
)
padding:
const
EdgeInsets
.
symmetric
(
vertical:
10.5
),
],
// textStyle: TextStyle(fontSize: 15.0,color: Colors.white),
),
],
),
),
child:
Text
(
'立即登录'
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
15.0
.
w
),),
),
),
),
),
],
),
),
Row
(
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
GestureDetector
(
onTap:
(){
///TODO: 同意协议
},
child:
Row
(
children:
[
children:
[
Container
(
Container
(
width:
10
.
w
,
width:
10
.
w
,
...
@@ -119,13 +170,24 @@ class _LoginPageState extends State<LoginPage> {
...
@@ -119,13 +170,24 @@ class _LoginPageState extends State<LoginPage> {
),
),
Gaps
.
hGaps10
,
Gaps
.
hGaps10
,
const
Text
(
'我已阅读并同意'
,
style:
TextStyle
(
color:
Colours
.
c9
,
fontSize:
10
)),
const
Text
(
'我已阅读并同意'
,
style:
TextStyle
(
color:
Colours
.
c9
,
fontSize:
10
)),
const
Text
(
'《用户协议》'
,
style:
TextStyle
(
color:
Colours
.
cBlue
,
fontSize:
10
)),
const
Text
(
'《隐私政策》'
,
style:
TextStyle
(
color:
Colours
.
cBlue
,
fontSize:
10
)),
],
)
],
],
),
),
),
),
GestureDetector
(
child:
const
Text
(
'《用户协议》'
,
style:
TextStyle
(
color:
Colours
.
cBlue
,
fontSize:
10
)),
onTap:
(){
context
.
pushNamed
(
Routes
.
terms
);
},
),
GestureDetector
(
child:
const
Text
(
'《隐私政策》'
,
style:
TextStyle
(
color:
Colours
.
cBlue
,
fontSize:
10
)),
onTap:
(){
context
.
pushNamed
(
Routes
.
terms
);
},
),
],
)
],
),
),
)
)
),
),
...
...
lib/utils/validator.dart
浏览文件 @
de62e122
...
@@ -79,3 +79,21 @@ class AmountValidator extends Validator<String?> {
...
@@ -79,3 +79,21 @@ class AmountValidator extends Validator<String?> {
return
hasMatch
(
_pattern
.
toString
(),
value
!,
caseSensitive:
false
);
return
hasMatch
(
_pattern
.
toString
(),
value
!,
caseSensitive:
false
);
}
}
}
}
class
ValidatorTool
{
// 验证手机号
static
bool
isValidPhoneNumber
(
String
value
)
{
RegExp
phonePattern
=
RegExp
(
r'^1[3-9]\d{9}$'
);
return
phonePattern
.
hasMatch
(
value
);
}
// 验证密码
static
bool
isValidPassword
(
String
value
)
{
RegExp
passwordPattern
=
RegExp
(
r'^[A-Za-z0-9!@#\$%^&*()_+{}\[\]:;<>,.?~\\/-]{6,20}$'
);;
return
passwordPattern
.
hasMatch
(
value
);
}
}
lib/widgets/button.dart
浏览文件 @
de62e122
...
@@ -239,3 +239,52 @@ class _ButtonWithIconChild extends StatelessWidget {
...
@@ -239,3 +239,52 @@ class _ButtonWithIconChild extends StatelessWidget {
);
);
}
}
}
}
class
CustomGradientButton
extends
StatelessWidget
{
final
String
text
;
final
bool
isEnabled
;
final
VoidCallback
onPressed
;
const
CustomGradientButton
({
Key
?
key
,
required
this
.
text
,
required
this
.
isEnabled
,
required
this
.
onPressed
,
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
height:
42
,
width:
double
.
infinity
,
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
21
),
gradient:
LinearGradient
(
colors:
isEnabled
?
[
const
Color
(
0xFFDE2E5E
).
withOpacity
(
0.7
),
const
Color
(
0xFFC31F4C
).
withOpacity
(
0.7
)]
// 可点击时的颜色
:
[
const
Color
(
0xFFDE2E5E
),
const
Color
(
0xFFC31F4C
)],
// 不可点击时的颜色,透明度为0.7
begin:
Alignment
.
centerLeft
,
end:
Alignment
.
centerRight
,
),
),
child:
TextButton
(
onPressed:
isEnabled
?
onPressed
:
null
,
style:
TextButton
.
styleFrom
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
10.5
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
21
),
),
backgroundColor:
Colors
.
transparent
,
),
child:
Text
(
text
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
15.0
),
),
),
);
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论