change the way of auto login to auto login at welcome screen with nice login prompt

main
htylight 2024-03-16 16:46:53 +08:00
parent ecd1e8d052
commit 83b02b3e60
12 changed files with 250 additions and 96 deletions

View File

@ -5,7 +5,7 @@ import './constants.dart';
ThemeData lightThemeData(BuildContext context) { ThemeData lightThemeData(BuildContext context) {
return ThemeData( return ThemeData(
// useMaterial3: true, useMaterial3: true,
primaryColor: kPrimaryColor, primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.white, scaffoldBackgroundColor: Colors.white,
appBarTheme: appBarThemeLight, appBarTheme: appBarThemeLight,
@ -33,7 +33,7 @@ ThemeData lightThemeData(BuildContext context) {
ThemeData darkThemeData(BuildContext context) { ThemeData darkThemeData(BuildContext context) {
return ThemeData( return ThemeData(
// useMaterial3: true, useMaterial3: true,
primaryColor: kPrimaryColor, primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.black, scaffoldBackgroundColor: Colors.black,
appBarTheme: appBarThemeDark, appBarTheme: appBarThemeDark,

View File

@ -54,11 +54,15 @@ class _SignTextFieldState extends State<SignTextField> {
await hasAccountExisted(widget.type, widget.controller.text); await hasAccountExisted(widget.type, widget.controller.text);
if (widget.type == 'username') { if (widget.type == 'username') {
setState(() { setState(() {
res['code'] == 10100 ? _errorText = null : _errorText = '用户名已存在'; res['code'] == 10100
? _errorText = null
: _errorText = '用户名已存在';
}); });
} else { } else {
setState(() { setState(() {
res['code'] == 10100 ? _errorText = null : _errorText = '邮箱已被使用'; res['code'] == 10100
? _errorText = null
: _errorText = '邮箱已被使用';
}); });
} }
} }
@ -190,41 +194,89 @@ class _SignTextFieldState extends State<SignTextField> {
} }
} }
TextField textField({ class CommonTextField extends StatelessWidget {
Color color = kPrimaryColor, const CommonTextField({
bool obscureText = false, super.key,
required String labelText, this.color = kPrimaryColor,
required TextEditingController controller, this.obscureText = false,
}) { required this.labelText,
return TextField( required this.controller,
controller: controller, });
obscureText: obscureText,
cursorColor: kSecondaryColor, final Color color;
textAlignVertical: TextAlignVertical.bottom, final bool obscureText;
decoration: InputDecoration( final String labelText;
helperText: '5-10位', final TextEditingController controller;
errorText: 'xxx',
labelText: labelText, @override
floatingLabelStyle: const TextStyle(color: kSecondaryColor), Widget build(BuildContext context) {
focusedBorder: return TextField(
UnderlineInputBorder(borderSide: BorderSide(color: color))), controller: controller,
); obscureText: obscureText,
cursorColor: kSecondaryColor,
textAlignVertical: TextAlignVertical.bottom,
decoration: InputDecoration(
helperText: '5-10位',
errorText: 'xxx',
labelText: labelText,
floatingLabelStyle: const TextStyle(color: kSecondaryColor),
focusedBorder:
UnderlineInputBorder(borderSide: BorderSide(color: color))),
);
}
} }
ElevatedButton elevatedButton( // TextField textField({
{required VoidCallback onPressed, // Color color = kPrimaryColor,
required String text, // bool obscureText = false,
Color? color = kPrimaryColor}) { // required String labelText,
return ElevatedButton( // required TextEditingController controller,
onPressed: onPressed, // }) {
style: ElevatedButton.styleFrom( // return TextField(
backgroundColor: color, // controller: controller,
elevation: 0, // obscureText: obscureText,
fixedSize: const Size(150, 20), // cursorColor: kSecondaryColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))), // textAlignVertical: TextAlignVertical.bottom,
child: Text( // decoration: InputDecoration(
text, // helperText: '5-10位',
style: const TextStyle(fontSize: 20.0, letterSpacing: 10), // errorText: 'xxx',
), // labelText: labelText,
); // floatingLabelStyle: const TextStyle(color: kSecondaryColor),
// focusedBorder:
// UnderlineInputBorder(borderSide: BorderSide(color: color))),
// );
// }
class CommonElevatedButton extends StatelessWidget {
const CommonElevatedButton({
super.key,
required this.onPressed,
required this.text,
this.color = kPrimaryColor,
});
final VoidCallback onPressed;
final String text;
final Color color;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: color,
elevation: 0,
fixedSize: const Size(150, 20),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
child: Text(
text,
style: const TextStyle(
fontSize: 20.0,
letterSpacing: 10,
color: kContentColorDark,
),
),
);
}
} }

View File

@ -1,11 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:together_mobile/common/theme.dart'; import 'package:together_mobile/common/theme.dart';
import 'package:together_mobile/database/hive_database.dart'; import 'package:together_mobile/database/hive_database.dart';
import 'package:together_mobile/router/router.dart'; import 'package:together_mobile/router/router.dart';
import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/init_get_it.dart';
import 'notification_api.dart'; import 'notification_api.dart';
final easyLoading = EasyLoading.init();
void main() async { void main() async {
initGetIt(); initGetIt();
await NotificationAPI.init(); await NotificationAPI.init();
@ -27,7 +31,8 @@ class Together extends StatelessWidget {
// This builder is used to dismiss keyboard while tap anywhere of the // This builder is used to dismiss keyboard while tap anywhere of the
// screen excluding the input widgets. // screen excluding the input widgets.
builder: (context, child) { builder: (context, child) {
return GestureDetector( child = easyLoading(context, child);
child = GestureDetector(
onTap: () { onTap: () {
if (FocusManager.instance.primaryFocus != null) { if (FocusManager.instance.primaryFocus != null) {
FocusManager.instance.primaryFocus!.unfocus(); FocusManager.instance.primaryFocus!.unfocus();
@ -35,6 +40,7 @@ class Together extends StatelessWidget {
}, },
child: child, child: child,
); );
return child;
}, },
); );
} }

View File

@ -46,8 +46,6 @@ var request = Dio(baseOptions)
} }
}, },
onError: (DioException e, ErrorInterceptorHandler handler) { onError: (DioException e, ErrorInterceptorHandler handler) {
print('错误信息:' + e.response?.data);
print('错误码: ${e.response?.statusCode}');
handler.reject(e); handler.reject(e);
}, },
), ),

View File

@ -36,13 +36,18 @@ final GoRouter router = GoRouter(
redirect: (context, state) async { redirect: (context, state) async {
await getIt.get<Token>().init(); await getIt.get<Token>().init();
if (getIt.get<Token>().token.isNotEmpty) { if (getIt.get<Token>().token.isNotEmpty) {
Map<String, dynamic> res = await signinByToken(); print(1111111);
if (res['code'] == 10200) { try {
await getIt.get<Token>().updateToken(res['token']); Map<String, dynamic> res = await signinByToken();
getIt.get<UserAccount>().init(res['data']); if (res['code'] == 10200) {
await HiveDatabase.init(); await getIt.get<Token>().updateToken(res['token']);
return '/chat'; getIt.get<UserAccount>().init(res['data']);
} else { await HiveDatabase.init();
return '/chat';
} else {
return null;
}
} catch (e) {
return null; return null;
} }
} }

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:cherry_toast/cherry_toast.dart'; import 'package:cherry_toast/cherry_toast.dart';
import 'common_widgets.dart'; import '../../../components/common_widgets.dart';
import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/common/constants.dart';
import 'package:together_mobile/request/signup_signin.dart'; import 'package:together_mobile/request/signup_signin.dart';
@ -92,7 +92,7 @@ class _EmailSigninBodyState extends State<EmailSigninBody> {
width: double.infinity, width: double.infinity,
height: kDefaultPadding, height: kDefaultPadding,
), ),
elevatedButton( CommonElevatedButton(
onPressed: confirm, onPressed: confirm,
text: '确定', text: '确定',
), ),

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:cherry_toast/cherry_toast.dart'; import 'package:cherry_toast/cherry_toast.dart';
import 'common_widgets.dart'; import '../../../components/common_widgets.dart';
import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/common/constants.dart';
import 'package:together_mobile/request/signup_signin.dart' as signup_request; import 'package:together_mobile/request/signup_signin.dart' as signup_request;
@ -135,7 +135,7 @@ class _SignupBodyState extends State<SignupBody> {
], ],
), ),
), ),
elevatedButton( CommonElevatedButton(
onPressed: () { onPressed: () {
_confirm(context); _confirm(context);
}, },

View File

@ -3,10 +3,11 @@ import 'package:flutter/material.dart';
import 'package:cherry_toast/cherry_toast.dart'; import 'package:cherry_toast/cherry_toast.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:together_mobile/database/hive_database.dart'; import 'package:together_mobile/database/hive_database.dart';
import 'package:together_mobile/models/token_model.dart'; import 'package:together_mobile/models/token_model.dart';
import '../../../components/common_widgets.dart';
import 'common_widgets.dart';
import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/common/constants.dart';
import 'package:together_mobile/request/signup_signin.dart'; import 'package:together_mobile/request/signup_signin.dart';
import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/init_get_it.dart';
@ -49,19 +50,23 @@ class _UsernameSigninBodyState extends State<UsernameSigninBody> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Stack( // Stack(
alignment: Alignment.center, // alignment: Alignment.center,
children: [ // children: [
const SizedBox( // const SizedBox(
width: double.infinity, // width: double.infinity,
height: 100, // height: 100,
), // ),
if (_isProgressShow) // if (_isProgressShow)
const CircularProgressIndicator( // const CircularProgressIndicator(
color: kPrimaryColor, // color: kPrimaryColor,
strokeWidth: 6.0, // strokeWidth: 6.0,
), // ),
], // ],
// ),
const SizedBox(
width: double.infinity,
height: 100,
), ),
SizedBox( SizedBox(
width: 250, width: 250,
@ -92,7 +97,7 @@ class _UsernameSigninBodyState extends State<UsernameSigninBody> {
height: kDefaultPadding, height: kDefaultPadding,
width: double.infinity, width: double.infinity,
), ),
elevatedButton( CommonElevatedButton(
onPressed: () { onPressed: () {
_signin(context); _signin(context);
}, },
@ -116,18 +121,29 @@ class _UsernameSigninBodyState extends State<UsernameSigninBody> {
if (!_isProgressShow) _isProgressShow = true; if (!_isProgressShow) _isProgressShow = true;
}); });
EasyLoading.showInfo('正在登录中......');
late Map<String, dynamic> result; late Map<String, dynamic> result;
if (_isProgressShow && !_isHttpSend) { if (_isProgressShow && !_isHttpSend) {
_isHttpSend = true; _isHttpSend = true;
result = await signinByUsername( try {
usernameController.text, passwordController.text); result = await signinByUsername(
usernameController.text,
passwordController.text,
);
} catch (e) {
EasyLoading.showError('连接服务器失败,请稍后重试...');
return;
} finally {
setState(() {
_isHttpSend = false;
_isProgressShow = false;
});
}
} }
setState(() {
_isHttpSend = false;
_isProgressShow = false;
});
if (result['code'] == 10200) { if (result['code'] == 10200) {
getIt<UserAccount>().init(result['data']); getIt<UserAccount>().init(result['data']);
@ -141,6 +157,7 @@ class _UsernameSigninBodyState extends State<UsernameSigninBody> {
getIt.get<Token>().updateToken(res['token']); getIt.get<Token>().updateToken(res['token']);
await HiveDatabase.init(); await HiveDatabase.init();
EasyLoading.dismiss();
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
context.go('/chat'); context.go('/chat');
} else { } else {

View File

@ -31,7 +31,11 @@ class _SigninScreenState extends State<SigninScreen> {
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
onPressed: () => context.pop(), onPressed: () => context.pop(),
), ),
title: _method == 'username' ? const Text('用户名登录') : const Text('邮箱注册'), title: _method == 'username'
? const Text(
'用户名登录',
)
: const Text('邮箱登录'),
centerTitle: true, centerTitle: true,
actions: [ actions: [
TextButton( TextButton(

View File

@ -1,10 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:together_mobile/common/constants.dart'; import '../../common/constants.dart';
import 'package:together_mobile/screens/signin_signup/components/common_widgets.dart' import '../../components/common_widgets.dart' show CommonElevatedButton;
show elevatedButton; import '../../database/hive_database.dart';
import '../../models/init_get_it.dart';
import '../../models/token_model.dart';
import '../../models/user_model.dart';
import '../../request/signup_signin.dart';
class WelcomeScreen extends StatefulWidget { class WelcomeScreen extends StatefulWidget {
const WelcomeScreen({super.key}); const WelcomeScreen({super.key});
@ -14,27 +19,77 @@ class WelcomeScreen extends StatefulWidget {
} }
class _WelcomeScreenState extends State<WelcomeScreen> { class _WelcomeScreenState extends State<WelcomeScreen> {
Future<int> _tryLoginUseToken() async {
await getIt.get<Token>().init();
if (getIt.get<Token>().token.isNotEmpty) {
try {
Map<String, dynamic> res = await signinByToken();
if (res['code'] == 10200) {
await getIt.get<Token>().updateToken(res['token']);
getIt.get<UserAccount>().init(res['data']);
await HiveDatabase.init();
return 10200;
} else {
getIt.get<Token>().clear();
return 9999;
}
} catch (e) {
return 500;
}
} else {
return 200;
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: SafeArea( body: SafeArea(
child: Column( child: FutureBuilder<int>(
children: [ future: _tryLoginUseToken(),
const SizedBox( builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
height: kDefaultPadding, if (snapshot.hasData) {
), int? data = snapshot.data;
Image.asset('assets/images/welcome_image.png'), if (data == 10200) {
elevatedButton( EasyLoading.showSuccess(
onPressed: () => context.push('/signin'), '登录成功!',
text: '登录', duration: const Duration(milliseconds: 500),
), );
elevatedButton( context.pushNamed('Chat');
onPressed: () => context.push('/signup'), } else if (data == 9999) {
text: '注册', EasyLoading.showInfo(
color: kSecondaryColor, '登录状态已过期,请重新登录!',
), duration: const Duration(milliseconds: 500),
], );
), } else if (data == 500) {
EasyLoading.showError(
'连接服务器失败,请稍后再试!',
duration: const Duration(milliseconds: 500),
);
} else {
EasyLoading.dismiss();
}
} else {
EasyLoading.show(status: '自动登录中...');
}
return Column(
children: [
const SizedBox(
height: kDefaultPadding,
),
Image.asset('assets/images/welcome_image.png'),
CommonElevatedButton(
onPressed: () => context.push('/signin'),
text: '登录',
),
CommonElevatedButton(
onPressed: () => context.push('/signup'),
text: '注册',
color: kSecondaryColor,
),
],
);
}),
), ),
); );
} }

View File

@ -390,6 +390,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.3" version: "1.0.3"
flutter_easyloading:
dependency: "direct main"
description:
name: flutter_easyloading
sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.5"
flutter_image_compress: flutter_image_compress:
dependency: transitive dependency: transitive
description: description:
@ -542,6 +550,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
flutter_spinkit:
dependency: transitive
description:
name: flutter_spinkit
sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.2.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter

View File

@ -39,6 +39,7 @@ dependencies:
fast_rsa: ^3.5.7 fast_rsa: ^3.5.7
flutter: flutter:
sdk: flutter sdk: flutter
flutter_easyloading: ^3.0.5
flutter_local_notifications: ^17.0.0 flutter_local_notifications: ^17.0.0
flutter_pickers: ^2.1.9 flutter_pickers: ^2.1.9
flutter_secure_storage: ^9.0.0 flutter_secure_storage: ^9.0.0