feat: login page init

This commit is contained in:
louis 2024-03-18 15:54:06 +08:00
parent 9abc9c0f2b
commit 78628e2242
12 changed files with 392 additions and 193 deletions

BIN
assets/images/bg copy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
assets/images/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,40 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
class AppTheme {
AppTheme._();
static const Color primaryColor = Color(0xFFB0F320);
static const Color primaryColorDark = Color(0xFFABEE1C);
static const Color nearlyWhite = Color(0xFFFEFEFE);
static const Color primaryColor = Color(0xFFC89607);
static Color primaryColorLight = primaryColor.withOpacity(0.7);
static Color primaryColorDark = Color.fromRGBO(
primaryColor.red,
primaryColor.green,
primaryColor.blue,
1 - primaryColor.computeLuminance(),
);
static const Color white = Color(0xFFFFFFFF);
static const Color nearlyWhite = Color(0xFFFEFEFE);
static const Color black = Color(0xFF000000);
static const Color nearlyBlack = Color(0xFF213333);
static const Color grey = Color(0xFF3A5160);
static const Color dark_grey = Color(0xFF313A44);
static const Color snackbarErrorBackgroudColor = Colors.red;
static const Color snackbarSuccessBackgroudColor = Colors.green;
static const Color snackbarWarningBackgroudColor = Colors.orange;
static const Color roleIconBackgroudColor = Color(0xff002f5f);
static const Color fixturePublishStatusColor = Color(0xFF5B8C00);
static const Color fixtureNotPublishStatusColor = Color(0xFFD7616E);
static const Color darkText = Color(0xFF253840);
static const Color darkerText = Color(0xFF17262A);
static const Color lightText = Color(0xFF4A6572);
static const Color dismissibleBackground = Color(0xFF364A54);
static const String fontName = 'NotoSans';
}
final theme = ThemeData(
fontFamily: AppTheme.fontName,
// primarySwatch:MaterialColor() AppTheme.primaryColor,
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryColor: AppTheme.primaryColor,
primaryColorDark: AppTheme.primaryColorDark,
progressIndicatorTheme:
ProgressIndicatorThemeData(color: AppTheme.primaryColor),
dividerColor: Color(0xFFDBDBDA),
cardColor: Colors.white,
scaffoldBackgroundColor: Color(0xFFF8F8F8),
const ProgressIndicatorThemeData(color: AppTheme.primaryColor),
dividerColor: AppTheme.grey,
cardColor: AppTheme.white,
scaffoldBackgroundColor: AppTheme.nearlyWhite,
tabBarTheme: TabBarTheme(
indicator: BoxDecoration(
border:
@ -42,11 +40,27 @@ final theme = ThemeData(
)),
appBarTheme: AppBarTheme(
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
iconTheme: const IconThemeData(color: Colors.black),
backgroundColor: AppTheme.primaryColor,
titleTextStyle: TextStyle(
color: Colors.black,
fontSize: ScreenAdaper.sp(20),
fontWeight: FontWeight.bold),
),
inputDecorationTheme: InputDecorationTheme(
floatingLabelStyle: TextStyle(
color: AppTheme.primaryColor,
fontSize: ScreenAdaper.sp(30),
),
labelStyle: TextStyle(
fontSize: ScreenAdaper.sp(25),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(ScreenAdaper.sp(15))),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(ScreenAdaper.sp(15)),
borderSide: BorderSide(
color: AppTheme.primaryColorLight, width: 2), //
),
),
);

View File

@ -14,7 +14,10 @@ class Global {
WidgetsFlutterBinding.ensureInitialized();
///
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
///
await SystemChrome.setPreferredOrientations(DeviceOrientation.values);
/// UI bug先隐藏功能
setSystemUi();

View File

@ -16,9 +16,13 @@ class IndexPage extends StatelessWidget {
const IndexPage({super.key});
@override
Widget build(BuildContext context) {
final isLandscape =
MediaQuery.of(context).orientation == Orientation.landscape;
return ScreenUtilInit(
minTextAdapt: true,
designSize: const Size(932, 1490), // 2800 * 1800p 309ppi
designSize: isLandscape
? const Size(1490, 932)
: const Size(932, 1490), // 2800 * 1800p 309ppi
builder: (buildContext, child) => RefreshConfiguration(
headerBuilder: () => RefreshHeader(),
footerBuilder: () => const RefreshFooter(),
@ -33,20 +37,13 @@ class IndexPage extends StatelessWidget {
initialRoute: getInitialRoute(),
// initialRoute: RouteConfig.onboarding,
debugShowCheckedModeBanner: false,
builder: (_, widget) => Obx(() => MediaQuery(
//
data: MediaQuery.of(context).copyWith(
textScaleFactor: AppInfoService.to.scale.value),
child: GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
},
child: widget!,
))))));
builder: (_, widget) {
return Obx(() => MediaQuery(
//
data: MediaQuery.of(context).copyWith(
textScaleFactor: AppInfoService.to.scale.value),
child: widget!));
})));
}
String getInitialRoute() {

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:sk_base_mobile/global.dart';
import 'package:sk_base_mobile/index.dart';
import 'package:sk_base_mobile/util/logger_util.dart';
@ -9,6 +10,5 @@ Future<void> main() async {
} catch (e) {
LoggerUtil().error('Init failed, please try again.${e}');
}
runApp(const IndexPage());
}

View File

@ -0,0 +1,194 @@
import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sk_base_mobile/app_theme.dart';
import 'package:sk_base_mobile/screens/login/login.controller.dart';
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
class LoginScreen extends StatelessWidget {
LoginScreen({super.key});
final _controller = Get.put<LoginController>(LoginController());
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/bg.jpg'),
fit: BoxFit.cover,
),
),
child: buildBody()));
// return Scaffold(
// body: SafeArea(child: buildBody()));
}
buildBody() {
return Center(
child: SingleChildScrollView(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
//
FocusScope.of(Get.context!).unfocus();
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(
height: ScreenAdaper.width(150),
image: const AssetImage(
'assets/images/company_logo.png',
)),
SizedBox(
width: ScreenAdaper.width(10),
),
Text(
'山矿通',
style: TextStyle(
fontWeight: FontWeight.w700,
color: AppTheme.nearlyWhite,
letterSpacing: ScreenAdaper.sp(5),
fontSize: ScreenAdaper.sp(70)),
)
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Text(
// '山矿通',
// style: TextStyle(
// letterSpacing: ScreenAdaper.sp(10),
// fontSize: ScreenAdaper.sp(70)),
// )
// ],
// ),
SizedBox(height: ScreenAdaper.height(50)),
buildForm(),
SizedBox(height: ScreenAdaper.height(50)),
],
),
),
));
}
Widget buildForm() {
final children = [
buildUserNameInput(),
SizedBox(
height: ScreenAdaper.height(20),
),
buildPasswordInput(),
SizedBox(
height: ScreenAdaper.height(20),
),
buildForgotPassword(),
SizedBox(
height: ScreenAdaper.height(20),
),
buildSubmitButton(),
];
final child = Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: children,
);
return Form(
key: _controller.formKey,
child: Container(
alignment: Alignment.center,
width: ScreenAdaper.width(800),
padding: EdgeInsets.symmetric(
vertical: 0, horizontal: ScreenAdaper.width(50)),
child: child,
));
}
Widget buildSubmitButton() {
final button = ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(ScreenAdaper.sp(30))),
padding: EdgeInsets.symmetric(
horizontal: ScreenAdaper.height(25),
vertical: ScreenAdaper.height(20)),
foregroundColor: AppTheme.nearlyWhite,
textStyle: TextStyle(
letterSpacing: 5,
fontWeight: FontWeight.bold,
fontSize: ScreenAdaper.sp(25)),
backgroundColor: AppTheme.primaryColor),
onPressed: _controller.doLogin,
child: const Text('登录'),
);
final child = Expanded(
child: button,
);
return Row(
children: [child],
);
}
Widget buildUserNameInput() {
return TextFormField(
decoration: const InputDecoration(
labelText: '用户名',
),
onFieldSubmitted: (value) {
_controller.passwordFocusNode.requestFocus();
},
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
onChanged: (value) {},
validator: (String? value) {
if (value == null || value == '') {
return '用户名必填';
} else {
return null;
}
},
);
}
Widget buildPasswordInput() {
return TextFormField(
decoration: const InputDecoration(
labelText: '密码',
),
obscureText: true,
focusNode: _controller.passwordFocusNode,
onFieldSubmitted: (value) {
_controller.doLogin();
},
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
onChanged: (value) {},
validator: (String? value) {
return (value ?? '').length >= 6 ? null : '密码长度至少6位';
},
);
}
Widget buildForgotPassword() {
return GestureDetector(
onTap: () {},
child: Container(
alignment: Alignment.centerRight,
child: Text(
'忘记密码?',
style: TextStyle(
color: Colors.grey,
fontSize: ScreenAdaper.sp(20),
decoration: TextDecoration.underline,
),
)),
);
}
}

View File

@ -7,31 +7,12 @@ import '../../util/util.dart';
class LoginController extends GetxController {
final isAgreeTerm = RxBool(false);
Future<void> fastLogin() async {
await confirmAgreement().then((value) async {
if (value != null) {
await AuthStore.to.login(LoginEnum.fastLogin);
}
});
}
Future confirmAgreement() async {
// if (!isAgreeTerm.value) {
// return Get.defaultDialog(
// title: '',
// content: ConfirmAgreement(),
// titlePadding: const EdgeInsets.all(0));
// } else {
// return Future(() => true);
// }
}
Future<void> onPrivacyPolicyTap() async {
// launchUrl(Uri.parse(GloablConfig.PRIVACY_POLICY));
}
Future<void> onTermTap() async {
// launchUrl(Uri.parse(GloablConfig.TERM_OF_USER));
final formKey = GlobalKey<FormState>();
final passwordFocusNode = FocusNode();
bool loading = false;
Future<void> doLogin() async {
if (!formKey.currentState!.validate()) {
return;
}
}
}

View File

@ -1,195 +1,204 @@
import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sk_base_mobile/app_theme.dart';
import 'package:sk_base_mobile/screens/login/login.controller.dart';
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
class LoginScreen extends StatelessWidget {
LoginScreen({super.key});
final formKey = GlobalKey<FormState>();
late BuildContext theContext;
bool loading = false;
String? username;
String? password;
final _controller = Get.put<LoginController>(LoginController());
double formWidth = 700;
@override
Widget build(BuildContext context) {
return Scaffold(body: SafeArea(child: buildBody()));
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/bg.jpg'),
fit: BoxFit.cover,
),
),
child: buildBody()));
}
buildBody() {
Widget buildBody() {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
//
//
FocusScope.of(Get.context!).unfocus();
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 0, 10, 30),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo(size: 120),
SizedBox(height: 30),
buildForm(),
SizedBox(height: 30),
],
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(
height: ScreenAdaper.width(150),
image: const AssetImage(
'assets/images/company_logo.png',
)),
SizedBox(
width: ScreenAdaper.width(10),
),
),
buildGoRegister(),
buildNotice(),
],
),
)));
}
Widget buildNotice() {
return Padding(
padding: EdgeInsets.fromLTRB(50, 5, 50, 5),
child: Text(
'If you have registered as a PLAYER, COACH, MANAGER or REFEREE, please use your login details provided.',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold)));
Text(
'山矿通',
style: TextStyle(
fontWeight: FontWeight.w700,
color: AppTheme.nearlyWhite,
letterSpacing: ScreenAdaper.sp(5),
fontSize: ScreenAdaper.sp(70)),
)
],
),
SizedBox(height: ScreenAdaper.height(50)),
buildForm(),
SizedBox(height: ScreenAdaper.height(50)),
buildSubmitButton(),
SizedBox(height: ScreenAdaper.height(50)),
],
),
),
));
}
Widget buildForm() {
final children = [
buildUserNameInput(),
SizedBox(
height: 15,
Divider(
thickness: ScreenAdaper.height(2),
),
buildPasswordInput(),
SizedBox(
height: 12,
),
buildForgotPassword(),
SizedBox(
height: 12,
),
buildSubmitButton(),
/* SizedBox(
height: 12,
),
buildRegistry() */
];
final child = Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: children,
);
return Form(
key: formKey,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 50),
key: _controller.formKey,
child: Container(
padding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(10)),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: AppTheme.black.withOpacity(0.3),
spreadRadius: ScreenAdaper.sp(10),
blurRadius: ScreenAdaper.sp(10),
offset: Offset(
0, ScreenAdaper.height(2)), // changes position of shadow
),
],
border: Border.all(width: 0),
borderRadius: BorderRadius.circular(ScreenAdaper.sp(30)),
color: AppTheme.nearlyWhite.withOpacity(0.9),
),
alignment: Alignment.center,
width: ScreenAdaper.width(formWidth),
child: child,
));
}
Widget buildGoRegister() => Container(
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text('Don\'t have an account?'),
SizedBox(width: 5),
GestureDetector(
onTap: () {},
child: Text('Create',
style: TextStyle(
color: AppTheme.primaryColor,
decoration: TextDecoration.underline,
))),
]),
);
Widget buildSubmitButton() {
final color = AppTheme.primaryColor;
// final button = RaisedButton(
// shape: StadiumBorder(),
// child: loading
// ? SizedBox(
// child: CircularProgressIndicator(
// color: AppTheme.primaryColorDark,
// ),
// height: 18,
// width: 18,
// )
// : Text('Sign In'),
// onPressed: () {
// _submit();
// },
// color: color,
// /* elevation: 20, */
// padding: EdgeInsets.all(12),
// );
// final child = Expanded(
// child: button,
// );
return Row(
children: [],
final button = ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(ScreenAdaper.sp(30))),
padding: EdgeInsets.symmetric(
horizontal: ScreenAdaper.height(25),
vertical: ScreenAdaper.height(20)),
foregroundColor: AppTheme.nearlyWhite,
textStyle: TextStyle(
letterSpacing: 5,
fontWeight: FontWeight.bold,
fontSize: ScreenAdaper.sp(25)),
backgroundColor: AppTheme.primaryColor),
onPressed: _controller.doLogin,
child: const Text('登录'),
);
final child = Expanded(
child: button,
);
return Container(
decoration: BoxDecoration(
border: Border.all(width: 0),
borderRadius: BorderRadius.circular(ScreenAdaper.sp(30)),
boxShadow: [
BoxShadow(
color: AppTheme.black.withOpacity(0.3),
spreadRadius: ScreenAdaper.sp(10),
blurRadius: ScreenAdaper.sp(10),
offset:
Offset(0, ScreenAdaper.height(5)), // changes position of shadow
),
],
),
alignment: Alignment.center,
width: ScreenAdaper.width(formWidth),
child: Row(
children: [child],
),
);
}
Widget buildUserNameInput() {
return TextFormField(
initialValue: username,
decoration: InputDecoration(
labelText: 'Email / Reg ID',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(ScreenAdaper.sp(10))),
fillColor: Color(0xFFF8F8F8),
),
onChanged: (value) {
this.username = value;
},
validator: (String? value) {
if (value == null || value == '') {
return 'Email / Reg ID is required';
} else {
return null;
}
prefixIcon: Icon(
Icons.person_2_outlined,
size: ScreenAdaper.sp(40),
),
hintText: '用户名',
border: InputBorder.none,
focusedBorder: InputBorder.none),
onFieldSubmitted: (value) {
_controller.passwordFocusNode.requestFocus();
},
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
onChanged: (value) {},
);
}
Widget buildPasswordInput() {
return TextFormField(
initialValue: password,
decoration: InputDecoration(
labelText: 'Password',
/* border: OutlineInputBorder(), */
fillColor: Color(0xFFF8F8F8),
),
prefixIcon: Icon(
Icons.lock_outlined,
size: ScreenAdaper.sp(40),
),
hintText: '密码',
border: InputBorder.none,
focusedBorder: InputBorder.none),
obscureText: true,
onChanged: (value) {
this.password = value;
},
validator: (String? value) {
return (value ?? '').length >= 6 ? null : 'Invalid password';
focusNode: _controller.passwordFocusNode,
onFieldSubmitted: (value) {
_controller.doLogin();
},
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
onChanged: (value) {},
// validator: (String? value) {
// return (value ?? '').length >= 6 ? null : '密码长度至少6位';
// },
);
}
Future<void> _submit() async {
if (!formKey.currentState!.validate()) {
return;
}
return;
}
Widget buildForgotPassword() {
return GestureDetector(
onTap: () {},
child: Container(
alignment: Alignment.centerRight,
child: Text(
'Forgot Password?',
'忘记密码?',
style: TextStyle(
color: Colors.grey,
fontSize: ScreenAdaper.sp(20),
decoration: TextDecoration.underline,
),
)),

View File

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
@ -45,6 +46,6 @@ class ScreenAdaper {
}
static isLandspace() {
return Get.width > Get.height;
return Get.context?.orientation == Orientation.landscape;
}
}