基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

434 lines
14 KiB

  1. import 'dart:convert';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/gestures.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter_alibc/alibc_model.dart';
  7. import 'package:flutter_alibc/flutter_alibc.dart';
  8. import 'package:flutter_bloc/flutter_bloc.dart';
  9. import 'package:fluttertoast/fluttertoast.dart';
  10. import 'package:sharesdk_plugin/sharesdk_plugin.dart';
  11. import 'package:zhiying_comm/pages/login_page/account/login_account_page.dart';
  12. import 'package:zhiying_comm/pages/login_page/bind/login_bind_phone_page.dart';
  13. import 'package:zhiying_comm/util/dialog/loading/loading.dart';
  14. import 'package:zhiying_comm/util/empty_util.dart';
  15. import 'package:zhiying_comm/util/mob_util/mob_util.dart';
  16. import 'package:zhiying_comm/zhiying_comm.dart';
  17. import 'package:provider/provider.dart';
  18. import 'bloc/bloc.dart';
  19. import 'bloc/login_repository.dart';
  20. import 'login_page_sk.dart';
  21. import 'model/login_style_model.dart';
  22. ///
  23. /// 登陆页面
  24. ///
  25. class LoginPage extends StatelessWidget {
  26. const LoginPage({Key key}) : super(key: key);
  27. @override
  28. Widget build(BuildContext context) {
  29. return Scaffold(
  30. backgroundColor: HexColor.fromHex('#FFFFFF'),
  31. body: BlocProvider<LoginBloc>(
  32. create: (_) => LoginBloc(repository: LoginRepository())..add(LoginInitEvent()),
  33. child: LoginPageContainer(),
  34. ),
  35. );
  36. }
  37. }
  38. class LoginPageContainer extends StatefulWidget {
  39. @override
  40. _LoginPageContainerState createState() => _LoginPageContainerState();
  41. }
  42. class _LoginPageContainerState extends State<LoginPageContainer> {
  43. LoginModel _taoBao;
  44. var _qqUserData;
  45. /// 微信or手机登陆
  46. void _loginClick(String type, LoginStyleModel model) {
  47. print('登陆$type');
  48. RouterUtil.hideKeyboard(context);
  49. if ('mobile' == type) {
  50. if (model?.flashLoginEnable == '1') {
  51. // mob 一键登录
  52. MobUtil.openQuickLoginPage(context, model?.quick);
  53. } else {
  54. Navigator.push(context, CupertinoPageRoute(builder: (_) => LoginAccountPage(null)));
  55. }
  56. } else if ('wechat' == type) {
  57. /// 微信登录
  58. Loading.show(context);
  59. SharesdkPlugin.getUserInfo(ShareSDKPlatforms.wechatSession, (SSDKResponseState state, Map user, SSDKError error) {
  60. if(state == SSDKResponseState.Success){
  61. }
  62. });
  63. Fluttertoast.showToast(msg: '暂不支持~');
  64. }
  65. }
  66. /// 第三方登陆
  67. void _otherLoginClick(BottomIcons model) async {
  68. print('第三方登陆${model.type}');
  69. if (EmptyUtil.isEmpty(model) || EmptyUtil.isEmpty(model.type)) {
  70. Fluttertoast.showToast(msg: '暂不支持~');
  71. return;
  72. }
  73. /// 淘宝登录
  74. if ('taobao' == model.type) {
  75. Loading.show(context);
  76. _taoBao = await FlutterAlibc.loginTaoBao();
  77. if (!EmptyUtil.isEmpty(_taoBao) && !EmptyUtil.isEmpty(_taoBao?.errorCode) && _taoBao.errorCode == '0') {
  78. BlocProvider.of<LoginBloc>(context).add(LoginThirdAliEvent(
  79. nick: _taoBao?.data?.nick,
  80. avatarUrl: _taoBao?.data?.avatarUrl,
  81. openId: _taoBao?.data?.openId,
  82. openSid: _taoBao?.data?.openSid,
  83. topAccessToken: _taoBao?.data?.topAccessToken,
  84. topAuthCode: _taoBao?.data?.topAuthCode));
  85. // Logger.warn(' tao login = ${_taoBao?.errorCode} , msg = ${_taoBao?.errorMessage}, nick = ${_taoBao?.data?.nick}, '
  86. // 'avatar = ${_taoBao?.data?.avatarUrl}, openId = ${_taoBao?.data?.openId}, openSid = ${_taoBao?.data?.openSid}, '
  87. // 'topAccessToken = ${_taoBao?.data?.topAccessToken}, topAuthCode = ${_taoBao?.data?.topAuthCode}');
  88. }
  89. Loading.dismiss();
  90. }
  91. /// QQ登录
  92. if ('qq' == model.type) {
  93. Loading.show(context);
  94. SharesdkPlugin.getUserInfo(ShareSDKPlatforms.qq, (SSDKResponseState state, Map userdata, SSDKError error) {
  95. Logger.log('state = ${state?.toString()}\nuserData = ${userdata?.toString()}');
  96. if (state == SSDKResponseState.Success && !EmptyUtil.isEmpty(userdata)) {
  97. try{
  98. _qqUserData = jsonDecode(userdata['dbInfo']);;
  99. }catch(e){}
  100. BlocProvider.of<LoginBloc>(context).add(LoginThirdQQEvent(model: userdata));
  101. Loading.dismiss();
  102. } else {
  103. Loading.dismiss();
  104. }
  105. });
  106. // Fluttertoast.showToast(msg: '暂不支持~');
  107. }
  108. /// 苹果登录
  109. if ('apple' == model.type) {
  110. Fluttertoast.showToast(msg: '暂不支持~');
  111. }
  112. }
  113. /// 跳到用户协议
  114. void _jumpUserAgreement(String url) {
  115. if (!EmptyUtil.isEmpty(url)) {
  116. print('协议');
  117. RouterUtil.openWebview(url, context);
  118. }
  119. }
  120. /// 跳到绑定手机号
  121. void _jumpBindPhonePage(String thirdType) {
  122. /// 如果是淘宝登录
  123. if (GlobalConfig.LOGIN_THIRD_ALI == thirdType) {
  124. Navigator.push(
  125. context,
  126. CupertinoPageRoute(
  127. builder: (_) => LoginBindPhonePage({
  128. 'thirdType': thirdType,
  129. 'nick': _taoBao?.data?.nick,
  130. 'avatarUrl': _taoBao?.data?.avatarUrl,
  131. 'openId': _taoBao?.data?.openId,
  132. 'openSid': _taoBao?.data?.openSid,
  133. 'topAccessToken': _taoBao?.data?.topAccessToken,
  134. 'topAuthCode': _taoBao?.data?.topAuthCode,
  135. })));
  136. }
  137. /// 如果是QQ登录
  138. if(GlobalConfig.LOGIN_THIRD_QQ == thirdType) {
  139. if (!EmptyUtil.isEmpty(_qqUserData)) {
  140. Navigator.push(
  141. context,
  142. CupertinoPageRoute(
  143. builder: (_) =>
  144. LoginBindPhonePage({
  145. 'thirdType': thirdType,
  146. 'nickname': _qqUserData['nickname']?.toString(),
  147. 'avatar_url': _qqUserData['icon']?.toString(),
  148. 'open_id': _qqUserData['userID']?.toString(),
  149. 'gender': _qqUserData['gender']?.toString() == '0' ? '1' : '2',
  150. 'unionid': _qqUserData['unionid']?.toString(),
  151. 'token': _qqUserData['token']?.toString(),
  152. })));
  153. }
  154. }
  155. }
  156. /// 跳到首页
  157. void _jumpHomePage() {
  158. RouterUtil.goBackHomePage(context);
  159. }
  160. /// 展开关闭其它登陆
  161. void _showOrCloseOtherLogin() {
  162. setState(() {
  163. _showOther = !_showOther;
  164. });
  165. }
  166. final _sizedHeight50 = const SizedBox(height: 50);
  167. final _sizedHeight9 = const SizedBox(height: 9);
  168. final _sizedHeight18 = const SizedBox(height: 18);
  169. final _sizedHeight21 = const SizedBox(height: 21);
  170. bool _showOther = true;
  171. @override
  172. Widget build(BuildContext context) {
  173. return BlocConsumer<LoginBloc, LoginState>(
  174. listener: (context, state) {
  175. // Fluttertoast.showToast(msg: '网络异常');
  176. },
  177. buildWhen: (prev, current) {
  178. if (current is LoginErrorState) {
  179. return false;
  180. }
  181. /// 登录失败
  182. if (current is LoginThirdLoginErrorState) {
  183. return false;
  184. }
  185. /// 登录成功
  186. if (current is LoginThirdLoginSuccessState) {
  187. // 需要绑定手机号
  188. if (current.model.bindPhoneEnable == '1') {
  189. // 打开绑定手机号页面
  190. _jumpBindPhonePage(current.thirdType);
  191. } else {
  192. // 更新登录数据
  193. Provider.of<UserInfoNotifier>(context, listen: false)?.setUserInfo(current.model);
  194. // 直接打开首页
  195. _jumpHomePage();
  196. Fluttertoast.showToast(msg: '登录成功~');
  197. }
  198. return false;
  199. }
  200. return true;
  201. },
  202. builder: (context, state) {
  203. if (state is LoginCacheState) {
  204. return _getMainWidget(state.model);
  205. }
  206. if (state is LoginLoadedState) {
  207. return _getMainWidget(state.model);
  208. }
  209. return LoginPageSkeleton(); // 骨架屏幕
  210. },
  211. );
  212. }
  213. /// 主视图
  214. Widget _getMainWidget(LoginStyleModel model) {
  215. return Column(
  216. children: <Widget>[
  217. /// 头部
  218. _headWidget(model),
  219. _sizedHeight50,
  220. /// 按钮
  221. _buttonsWidget(model),
  222. _sizedHeight9,
  223. /// 协议
  224. _protocolWidget(model),
  225. /// 其它登陆方式
  226. _otherLoginWidget(model),
  227. ],
  228. );
  229. }
  230. /// 头部Widget
  231. Widget _headWidget(LoginStyleModel model) {
  232. return Container(
  233. height: 228 + MediaQuery.of(context).padding.top,
  234. width: double.infinity,
  235. decoration: BoxDecoration(
  236. image: DecorationImage(
  237. image: CachedNetworkImageProvider(model?.main?.backgroundImg ?? ''),
  238. fit: BoxFit.fill,
  239. ),
  240. ),
  241. child: Stack(
  242. alignment: Alignment.center,
  243. children: <Widget>[
  244. AppBar(
  245. backgroundColor: Colors.transparent,
  246. elevation: 0,
  247. leading: IconButton(
  248. icon: Icon(
  249. Icons.arrow_back_ios,
  250. size: 22,
  251. color: HexColor.fromHex('#333333'),
  252. ),
  253. onPressed: () => Navigator.maybePop(context),
  254. ),
  255. ),
  256. Column(
  257. crossAxisAlignment: CrossAxisAlignment.center,
  258. mainAxisAlignment: MainAxisAlignment.center,
  259. children: <Widget>[
  260. /// logo
  261. Container(
  262. margin: EdgeInsets.only(bottom: 12, top: MediaQuery.of(context).padding.top),
  263. decoration: BoxDecoration(
  264. borderRadius: BorderRadius.circular(14),
  265. boxShadow: [
  266. BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0), blurRadius: 10.0, spreadRadius: 1.0),
  267. BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0)),
  268. ],
  269. ),
  270. height: 80,
  271. width: 80,
  272. child: CachedNetworkImage(imageUrl: model?.logoImg ?? ''),
  273. ),
  274. /// logo 名字
  275. CachedNetworkImage(
  276. imageUrl: model?.main?.appNameImg ?? '',
  277. width: 90,
  278. ),
  279. ],
  280. ),
  281. ],
  282. ),
  283. );
  284. }
  285. /// 按钮
  286. Widget _buttonsWidget(LoginStyleModel model) {
  287. return Container(
  288. padding: const EdgeInsets.symmetric(horizontal: 27.5),
  289. child: Column(
  290. children: model.main.importanceLogin.map((item) {
  291. return Padding(
  292. padding: const EdgeInsets.only(bottom: 8),
  293. child: _customButton(
  294. height: 40,
  295. text: item?.btnText,
  296. iconUrl: item?.btnMobileIcon ?? '',
  297. textColor: item?.btnTextColor,
  298. bgColor: item?.btnBgColor,
  299. borderColor: item?.btnBorderColor,
  300. onTap: () => _loginClick(item?.type, model)),
  301. );
  302. }).toList(),
  303. ),
  304. );
  305. }
  306. /// 协议
  307. Widget _protocolWidget(LoginStyleModel model) {
  308. return RichText(
  309. text: TextSpan(
  310. text: '',
  311. children: model.main.agreements.map((item) {
  312. return TextSpan(
  313. text: item?.text,
  314. style: TextStyle(color: HexColor.fromHex(item?.textColor), fontSize: 10),
  315. recognizer: TapGestureRecognizer()
  316. ..onTap = () {
  317. _jumpUserAgreement(item?.url);
  318. });
  319. }).toList()),
  320. );
  321. }
  322. /// 其它登陆方式
  323. Widget _otherLoginWidget(LoginStyleModel model) {
  324. return Expanded(
  325. child: Column(
  326. mainAxisAlignment: MainAxisAlignment.end,
  327. children: <Widget>[
  328. _getOtherLoginTitle(model),
  329. _sizedHeight18,
  330. Visibility(visible: _showOther, child: _getOtherLoginIcons(model)),
  331. Visibility(visible: _showOther, child: _sizedHeight21),
  332. ],
  333. ),
  334. );
  335. }
  336. /// 其它登陆方式的title
  337. Widget _getOtherLoginTitle(LoginStyleModel model) {
  338. return GestureDetector(
  339. behavior: HitTestBehavior.opaque,
  340. onTap: () => _showOrCloseOtherLogin(),
  341. child: Row(
  342. mainAxisAlignment: MainAxisAlignment.center,
  343. crossAxisAlignment: CrossAxisAlignment.center,
  344. children: <Widget>[
  345. Text('${model?.main?.otherIconsTitle}', style: TextStyle(fontSize: 13, color: HexColor.fromHex(model?.main?.otherIconsTitleColor))),
  346. SizedBox(width: 5.5),
  347. RotatedBox(
  348. quarterTurns: _showOther ? 0 : 2,
  349. child: CachedNetworkImage(imageUrl: model?.main?.otherExpansionIcon ?? '', width: 12),
  350. ),
  351. ],
  352. ),
  353. );
  354. }
  355. /// 其它登陆方式的按钮
  356. Widget _getOtherLoginIcons(LoginStyleModel model) {
  357. return Row(
  358. mainAxisAlignment: MainAxisAlignment.center,
  359. children: model.main.bottomIcons.map((item) {
  360. return GestureDetector(
  361. behavior: HitTestBehavior.opaque,
  362. onTap: () => _otherLoginClick(item),
  363. child: Container(
  364. width: 30,
  365. margin: const EdgeInsets.symmetric(horizontal: 20),
  366. child: CachedNetworkImage(imageUrl: item?.img ?? ''),
  367. ),
  368. );
  369. }).toList(),
  370. );
  371. }
  372. /// 自定义按钮
  373. Widget _customButton({double height, String text, String iconUrl, String textColor, String bgColor, String borderColor, GestureTapCallback onTap}) {
  374. return GestureDetector(
  375. onTap: onTap,
  376. child: Container(
  377. width: double.infinity,
  378. height: height ?? 0,
  379. decoration: BoxDecoration(
  380. border: Border.all(color: HexColor.fromHex(borderColor), width: 0.5),
  381. borderRadius: BorderRadius.circular(height ?? 0 / 2),
  382. color: HexColor.fromHex(bgColor),
  383. ),
  384. child: Row(
  385. mainAxisAlignment: MainAxisAlignment.center,
  386. crossAxisAlignment: CrossAxisAlignment.center,
  387. children: <Widget>[
  388. // icon
  389. CachedNetworkImage(imageUrl: iconUrl, width: 12),
  390. SizedBox(width: 8),
  391. // text
  392. Text(text, style: TextStyle(color: HexColor.fromHex(textColor), fontSize: 15))
  393. ],
  394. ),
  395. ),
  396. );
  397. }
  398. }