feat: 登录页 闪屏图

This commit is contained in:
louis 2024-03-19 08:59:08 +08:00
parent 78628e2242
commit 916272bf3b
32 changed files with 466 additions and 552 deletions

25
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,25 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "sk_base_mobile",
"request": "launch",
"type": "dart"
},
{
"name": "sk_base_mobile (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "sk_base_mobile (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
</layer-list>

BIN
assets/images/edit_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/images/mine_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -1,2 +1,8 @@
flutter_native_splash:
background_image: 'assets/images/launch_image.jpg'
android: true
ios: true
landscape:
image: assets/images/launch_image_landscape.jpg
android: true
ios: true

View File

@ -5,10 +5,19 @@ import 'package:sk_base_mobile/constants/global_url.dart';
import 'package:sk_base_mobile/services/dio.service.dart';
import '../constants/constants.dart';
Future<Response> login(String? oauthType, String? token) {
return DioService.dio.post(Urls.login,
data: {'oauthType': oauthType, 'token': token},
options: Options(contentType: "application/x-www-form-urlencoded"));
//
Future<Response> login(String username, String password) {
return DioService.dio.post(
Urls.login,
data: {'username': username, 'password': password},
);
}
//
Future<Response> getUserInfo() {
return DioService.dio.get(
Urls.getUserInfo,
);
}
Future<Response> logout() {
@ -32,13 +41,6 @@ Future<Response> saveUserInfo(Map<String, dynamic> data) {
return DioService.dio.post(Urls.saveUserInfo, data: data);
}
Future<Response> getUserInfo(String userId) {
Map<String, dynamic> data = {
"userId": userId,
};
return DioService.dio.get(Urls.getUserInfo, queryParameters: data);
}
Future<Response> uploadImg(File file) async {
// DateTime dateTime = DateTime.now();
// String fileName = file.path.split('/').last;

View File

@ -19,7 +19,7 @@ class AppTheme {
static const Color snackbarErrorBackgroudColor = Colors.red;
static const Color snackbarSuccessBackgroudColor = Colors.green;
static const Color snackbarWarningBackgroudColor = Colors.orange;
static const Color dismissibleBackground = Color(0xFF364A54);
static Color barrierColor = Colors.black.withOpacity(0.5);
static const String fontName = 'NotoSans';
}
@ -33,6 +33,11 @@ final theme = ThemeData(
dividerColor: AppTheme.grey,
cardColor: AppTheme.white,
scaffoldBackgroundColor: AppTheme.nearlyWhite,
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: AppTheme.nearlyWhite,
unselectedLabelStyle: TextStyle(fontSize: ScreenAdaper.sp(20)),
selectedLabelStyle: TextStyle(fontSize: ScreenAdaper.sp(20)),
selectedItemColor: AppTheme.primaryColor),
tabBarTheme: TabBarTheme(
indicator: BoxDecoration(
border:
@ -44,7 +49,7 @@ final theme = ThemeData(
backgroundColor: AppTheme.primaryColor,
titleTextStyle: TextStyle(
color: Colors.black,
fontSize: ScreenAdaper.sp(20),
fontSize: ScreenAdaper.sp(25),
fontWeight: FontWeight.bold),
),
inputDecorationTheme: InputDecorationTheme(

View File

@ -1,6 +1,7 @@
/// Global config
class GloablConfig {
static const BASE_URL = "http://172.21.128.1:3000/";
// static const BASE_URL = "http://172.21.128.1:3000/api";
static const BASE_URL = "http://10.0.2.2:7001/api/";
static const DOMAIN_NAME = "山矿通";
static const DEBUG = true;
static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html';

View File

@ -1,27 +1,10 @@
class Urls {
static String getAppConfig = 'config/getAppConfig';
static String login = 'security/oauth';
static String login = 'auth/login';
static String isValidToken = 'security/isValidToken';
static String logout = 'security/logout';
static String deleteAccount = 'user/deleteAccount';
static String rankList = 'broadcaster/wall/search';
static String addFriend = 'user/addFriend';
static String removeFriend = 'user/unfriend';
static String goodsList = 'coin/goods/search';
static String saveUserInfo = 'user/saveUserInfo';
static String getUserInfo = 'user/getUserInfo';
static String getOssPolicy = 'user/oss/policy';
static String getUserInfo = 'account/profile';
static String updateAvatar = 'user/updateAvatar';
static String getFollowedList = 'user/getFriendsListPage';
static String reportComplain = 'report/complain/insertRecord';
static String blockList = 'report/complain/blockList';
static String unblock = 'report/complain/removeBlock';
static String googleTranslate =
'https://translation.googleapis.com/language/translate/v2';
static String getIMStrategy = 'config/getStrategy';
static String getIMToken = 'user/rongcloud/token';
static String trackingLog = 'log/live-chat';
static String createOrder = 'coin/recharge/create';
static String validateOrder = 'coin/recharge/payment/ipa';
static String reviewModeConsume = 'coin/reviewModeConsume';
}

View File

@ -7,6 +7,7 @@ import 'package:sk_base_mobile/services/app_info.service.dart';
import 'package:sk_base_mobile/services/dio.service.dart';
import 'package:sk_base_mobile/services/storage.service.dart';
import 'store/store.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
///
class Global {

View File

@ -1,9 +1,10 @@
import 'package:flutter/cupertino.dart';
class AppBottomNavItem {
String? icon;
String? activeIcon;
Icon icon;
Icon activeIcon;
String? label;
Widget? page;
AppBottomNavItem({this.icon, this.activeIcon, this.label, this.page});
AppBottomNavItem(
{required this.icon, required this.activeIcon, this.label, this.page});
}

View File

@ -1,27 +1,15 @@
import 'package:sk_base_mobile/models/user_info.model.dart';
class Auth {
bool? isFirstRegister;
String? token;
UserInfoModel? userInfo;
Auth({this.isFirstRegister, this.token, this.userInfo});
Auth({this.token});
Auth.fromJson(Map<String, dynamic> json) {
isFirstRegister = json['isFirstRegister'];
token = json['token'];
userInfo = json['userInfo'] != null
? UserInfoModel.fromJson(json['userInfo'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['isFirstRegister'] = isFirstRegister;
data['token'] = token;
if (userInfo != null) {
data['userInfo'] = userInfo!.toJson();
}
return data;
}
}

View File

@ -0,0 +1,40 @@
class RoleModel {
int? id;
String? createdAt;
String? updatedAt;
String? name;
String? value;
String? remark;
int? status;
RoleModel(
{this.id,
this.createdAt,
this.updatedAt,
this.name,
this.value,
this.remark,
this.status});
RoleModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
createdAt = json['createdAt'];
updatedAt = json['updatedAt'];
name = json['name'];
value = json['value'];
remark = json['remark'];
status = json['status'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['createdAt'] = createdAt;
data['updatedAt'] = updatedAt;
data['name'] = name;
data['value'] = value;
data['remark'] = remark;
data['status'] = status;
return data;
}
}

View File

@ -1,230 +1,69 @@
class UserInfoModel {
String? userId;
int? userType;
String? nickname;
bool? isInternal;
String? avatar;
String? avatarUrl;
String? avatarThumbUrl;
String? avatarMiddleThumbUrl;
List<String>? mediumList;
List<AvatarRespList>? avatarRespList;
int? gender;
String? birthday;
int? age;
String? country;
String? pkgName;
bool? isAnswer;
int? availableCoins;
int? auditStatus;
bool? isShowReviewSupplementTips;
List<String>? tagsList;
List<TagDetails>? tagDetails;
String? rongcloudToken;
bool? isRecharge;
bool? isVip;
int? level;
int? followNum;
int? praiseNum;
bool? isBlock;
bool? isSwitchNotDisturbIm;
bool? isSwitchNotDisturbCall;
bool? isHavePassword;
bool? isReview;
bool? isMultiple;
String? registerPkgName;
String? registerCountry;
String? loginPkgName;
int? giftWallAction;
import 'package:sk_base_mobile/models/role.model.dart';
UserInfoModel({
this.userId,
this.userType,
class UserInfoModel {
int? id;
String? createdAt;
String? updatedAt;
String? username;
String? nickname;
String? avatar;
String? qq;
String? email;
String? phone;
String? remark;
int? status;
List<RoleModel>? roles;
UserInfoModel(
{this.id,
this.createdAt,
this.updatedAt,
this.username,
this.nickname,
this.isInternal,
this.avatar,
this.avatarUrl,
this.avatarThumbUrl,
this.avatarMiddleThumbUrl,
this.mediumList,
this.avatarRespList,
this.gender,
this.birthday,
this.age,
this.country,
this.pkgName,
this.isAnswer,
this.availableCoins,
this.auditStatus,
this.isShowReviewSupplementTips,
this.tagsList,
this.tagDetails,
this.rongcloudToken,
this.isRecharge,
this.isVip,
this.level,
this.followNum,
this.praiseNum,
this.isBlock,
this.isSwitchNotDisturbIm,
this.isSwitchNotDisturbCall,
this.isHavePassword,
this.isReview,
this.isMultiple,
this.registerPkgName,
this.registerCountry,
this.loginPkgName,
this.giftWallAction,
});
this.qq,
this.email,
this.phone,
this.remark,
this.status,
this.roles});
UserInfoModel.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
userType = json['userType'];
id = json['id'];
createdAt = json['createdAt'];
updatedAt = json['updatedAt'];
username = json['username'];
nickname = json['nickname'];
isInternal = json['isInternal'];
avatar = json['avatar'];
avatarUrl = json['avatarUrl'];
avatarThumbUrl = json['avatarThumbUrl'];
avatarMiddleThumbUrl = json['avatarMiddleThumbUrl'];
if (json['avatarRespList'] != null) {
avatarRespList = <AvatarRespList>[];
json['avatarRespList'].forEach((v) {
avatarRespList!.add(AvatarRespList.fromJson(v));
qq = json['qq'];
email = json['email'];
phone = json['phone'];
remark = json['remark'];
status = json['status'];
if (json['roles'] != null) {
roles = <RoleModel>[];
json['roles'].forEach((v) {
roles!.add(RoleModel.fromJson(v));
});
}
gender = json['gender'];
birthday = json['birthday'];
age = json['age'];
country = json['country'];
pkgName = json['pkgName'];
isAnswer = json['isAnswer'];
availableCoins = json['availableCoins'];
auditStatus = json['auditStatus'];
isShowReviewSupplementTips = json['isShowReviewSupplementTips'];
if (json['tagsList'] != null) {
tagsList = <String>[];
json['tagsList'].forEach((v) {
tagsList!.add(v);
});
}
if (json['tagDetails'] != null) {
tagDetails = <TagDetails>[];
json['tagDetails'].forEach((v) {
tagDetails!.add(TagDetails.fromJson(v));
});
}
rongcloudToken = json['rongcloudToken'];
isRecharge = json['isRecharge'];
isVip = json['isVip'];
level = json['level'];
followNum = json['followNum'];
praiseNum = json['praiseNum'];
isBlock = json['isBlock'];
isSwitchNotDisturbIm = json['isSwitchNotDisturbIm'];
isSwitchNotDisturbCall = json['isSwitchNotDisturbCall'];
isHavePassword = json['isHavePassword'];
isReview = json['isReview'];
isMultiple = json['isMultiple'];
registerPkgName = json['registerPkgName'];
registerCountry = json['registerCountry'];
loginPkgName = json['loginPkgName'];
giftWallAction = json['giftWallAction'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['userId'] = userId;
data['userType'] = userType;
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['createdAt'] = createdAt;
data['updatedAt'] = updatedAt;
data['username'] = username;
data['nickname'] = nickname;
data['isInternal'] = isInternal;
data['avatar'] = avatar;
data['avatarUrl'] = avatarUrl;
data['avatarThumbUrl'] = avatarThumbUrl;
data['avatarMiddleThumbUrl'] = avatarMiddleThumbUrl;
if (this.avatarRespList != null) {
data['avatarRespList'] = avatarRespList!.map((v) => v.toJson()).toList();
data['qq'] = qq;
data['email'] = email;
data['phone'] = phone;
data['remark'] = remark;
data['status'] = status;
if (roles != null) {
data['roles'] = roles!.map((v) => v.toJson()).toList();
}
data['gender'] = gender;
data['birthday'] = birthday;
data['age'] = age;
data['country'] = country;
data['pkgName'] = pkgName;
data['isAnswer'] = isAnswer;
data['availableCoins'] = availableCoins;
data['auditStatus'] = auditStatus;
data['isShowReviewSupplementTips'] = isShowReviewSupplementTips;
if (this.tagsList != null) {
data['tagsList'] = tagsList!.map((v) => v).toList();
}
if (this.tagDetails != null) {
data['tagDetails'] = tagDetails!.map((v) => v.toJson()).toList();
}
data['rongcloudToken'] = rongcloudToken;
data['isRecharge'] = isRecharge;
data['isVip'] = isVip;
data['level'] = level;
data['followNum'] = followNum;
data['praiseNum'] = praiseNum;
data['isBlock'] = isBlock;
data['isSwitchNotDisturbIm'] = isSwitchNotDisturbIm;
data['isSwitchNotDisturbCall'] = isSwitchNotDisturbCall;
data['isHavePassword'] = isHavePassword;
data['isReview'] = isReview;
data['isMultiple'] = isMultiple;
data['registerPkgName'] = registerPkgName;
data['registerCountry'] = registerCountry;
data['loginPkgName'] = loginPkgName;
data['giftWallAction'] = giftWallAction;
return data;
}
}
class AvatarRespList {
String? mediaPath;
String? mediaUrl;
String? middleThumbUrl;
String? thumbUrl;
AvatarRespList({this.mediaPath, mediaUrl, middleThumbUrl, thumbUrl});
AvatarRespList.fromJson(Map<String, dynamic> json) {
mediaPath = json['mediaPath'];
mediaUrl = json['mediaUrl'];
middleThumbUrl = json['middleThumbUrl'];
thumbUrl = json['thumbUrl'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['mediaPath'] = mediaPath;
data['mediaUrl'] = mediaUrl;
data['middleThumbUrl'] = middleThumbUrl;
data['thumbUrl'] = thumbUrl;
return data;
}
}
class TagDetails {
String? tag;
String? tagTip;
String? tagColor;
TagDetails({this.tag, tagTip, tagColor});
TagDetails.fromJson(Map<String, dynamic> json) {
tag = json['tag'];
tagTip = json['tagTip'];
tagColor = json['tagColor'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['tag'] = tag;
data['tagTip'] = tagTip;
data['tagColor'] = tagColor;
return data;
}
}

View File

@ -5,6 +5,9 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Placeholder();
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: SizedBox(child: Text('sss')),
);
}
}

View File

@ -34,26 +34,16 @@ class _LandingPageState extends State<LandingPage> {
AppInfoService.to.bottomNavItems!;
bottomNavItems = roleWithBottomNavItems
.map((e) => BottomNavigationBarItem(
icon: Image.asset(
e.icon!,
height: ScreenAdaper.width(30),
width: ScreenAdaper.width(30),
),
activeIcon: Image.asset(
e.activeIcon!,
height: ScreenAdaper.width(30),
width: ScreenAdaper.width(30),
),
label: e.label))
icon: e.icon, activeIcon: e.activeIcon, label: e.label))
.toList();
pages = roleWithBottomNavItems.map((e) => e.page!).toList();
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
iconSize: ScreenAdaper.sp(25),
iconSize: ScreenAdaper.sp(40),
type: BottomNavigationBarType.fixed,
items: bottomNavItems,
showSelectedLabels: false,
showUnselectedLabels: false,
showSelectedLabels: true,
showUnselectedLabels: true,
currentIndex: _selectedLanding,
onTap: (landing) {
_onItemTapped(landing);

View File

@ -9,10 +9,14 @@ class LoginController extends GetxController {
final isAgreeTerm = RxBool(false);
final formKey = GlobalKey<FormState>();
final passwordFocusNode = FocusNode();
String username = '';
String password = '';
bool loading = false;
Future<void> doLogin() async {
if (!formKey.currentState!.validate()) {
return;
}
// form中的数据
AuthStore.to.login(username: username, password: password);
}
}

View File

@ -162,7 +162,9 @@ class LoginScreen extends StatelessWidget {
_controller.passwordFocusNode.requestFocus();
},
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
onChanged: (value) {},
onChanged: (value) {
_controller.username = value;
},
);
}
@ -181,8 +183,11 @@ class LoginScreen extends StatelessWidget {
onFieldSubmitted: (value) {
_controller.doLogin();
},
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
onChanged: (value) {},
onChanged: (value) {
_controller.password = value;
},
// validator: (String? value) {
// return (value ?? '').length >= 6 ? null : '密码长度至少6位';
// },

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sk_base_mobile/screens/mine/mine.controller.dart';
import 'package:sk_base_mobile/screens/mine/settings/mine_settings.dart';
// import 'package:sk_base_mobile/screens/mine/mine_about.dart';
// import 'package:sk_base_mobile/screens/mine/mine_block.dart';
// import 'package:sk_base_mobile/screens/mine/mine_mytickets.dart';
@ -29,10 +30,6 @@ class _MinePageState extends State<MinePage>
@override
void initState() {
super.initState();
_controller.tabController ??= TabController(
initialIndex: _controller.selectedTabIndex.value,
length: 4,
vsync: this);
}
@override
@ -41,7 +38,7 @@ class _MinePageState extends State<MinePage>
}
Widget _buildBody() {
return Column(mainAxisSize: MainAxisSize.max, children: [
return Column(children: [
Container(
height: ScreenAdaper.height(360),
width: ScreenAdaper.screenWidth(),
@ -115,7 +112,7 @@ class _MinePageState extends State<MinePage>
SizedBox(
width: ScreenAdaper.width(210),
child: Text(
'ID: ${AuthStore.to.userInfo.value.userId}',
'ID: ${AuthStore.to.userInfo.value.id}',
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
@ -149,65 +146,20 @@ class _MinePageState extends State<MinePage>
]),
),
),
Expanded(
child: DefaultTabController(
length: 4,
initialIndex: _controller.selectedTabIndex.value,
child: Scaffold(
backgroundColor: AppTheme.white,
appBar: AppBar(
backgroundColor: AppTheme.white,
elevation: 0,
automaticallyImplyLeading: false,
flexibleSpace: _buildTabBar(),
),
body: _buildTabView())))
Expanded(child: MineSettingsPage())
// Expanded(
// child: DefaultTabController(
// length: 4,
// initialIndex: _controller.selectedTabIndex.value,
// child: Scaffold(
// backgroundColor: AppTheme.white,
// appBar: AppBar(
// backgroundColor: AppTheme.white,
// elevation: 0,
// automaticallyImplyLeading: false,
// flexibleSpace: _buildTabBar(),
// ),
// body: _buildTabView())))
]);
}
Widget _buildTabBar() {
final tabs = _controller.mineTabs
.asMap()
.map((index, item) {
return MapEntry(
index,
Obx(
() => Tab(
child: Image(
image: AssetImage(
'assets/images/$item${_controller.selectedTabIndex.value == index ? '_active' : ''}.png'))),
));
})
.values
.toList();
return Container(
margin: EdgeInsets.only(top: ScreenAdaper.height(20)),
padding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(10)),
decoration: const BoxDecoration(
border: Border.symmetric(
horizontal: BorderSide(color: Color(0xFFCCCCCC)))),
child: TabBar(
controller: _controller.tabController,
tabs: tabs,
indicator: const BoxDecoration(),
onTap: (index) {
_controller.selectedTabIndex.value = index;
}, /* */
),
);
}
Widget _buildTabView() {
return TabBarView(
controller: _controller.tabController,
physics: const NeverScrollableScrollPhysics(),
children: [
SizedBox(),
SizedBox(),
SizedBox(),
SizedBox(),
],
);
}
}

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sk_base_mobile/models/mine_about.model.dart';
class MineController extends GetxController {
final selectedTabIndex = 0.obs;
TabController? tabController;
@override
void onInit() {
super.onInit();
}
}

View File

@ -0,0 +1,71 @@
import 'package:flutter/cupertino.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/mine/mine.controller.dart';
import 'package:sk_base_mobile/store/auth.store.dart';
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
class MineSettingsPage extends StatelessWidget {
final _controller = Get.find<MineController>();
MineSettingsPage({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: ScreenAdaper.width(15)),
child: ListView.separated(
separatorBuilder: (_, index) => const Divider(
color: Color(0xFFCCCCCC),
),
itemBuilder: ((_, index) => _buildSettingsItem(
index,
)),
itemCount: 4),
);
}
Widget _buildSettingsItem(int index) {
switch (index) {
// auto translate
case 0:
return Container(
padding: EdgeInsets.symmetric(vertical: ScreenAdaper.width(10)),
child: Row(
children: [],
));
case 1:
return InkWell(
onTap: () async {
await AuthStore.to.deleteAccount();
},
child: Container(
padding: EdgeInsets.symmetric(vertical: ScreenAdaper.width(10)),
child: Row(
children: [
Text(
'Delete acount',
style: TextStyle(fontSize: ScreenAdaper.sp(18)),
),
],
)));
case 2:
return InkWell(
onTap: () async {
await AuthStore.to.logout(force: true);
},
child: Container(
padding: EdgeInsets.symmetric(vertical: ScreenAdaper.width(10)),
child: Row(
children: [
Text(
'Logout',
style: TextStyle(fontSize: ScreenAdaper.sp(18)),
),
],
)));
default:
return SizedBox();
}
}
}

View File

@ -6,22 +6,16 @@ import 'package:sk_base_mobile/apis/api.dart' as Api;
class UserInfoController extends GetxController {
final nickNameController = TextEditingController(text: '');
final countryController = TextEditingController(text: '');
final birthdayController = TextEditingController();
@override
void onReady() async {
nickNameController.text = AuthStore.to.userInfo.value.nickname ?? '';
birthdayController.text = AuthStore.to.userInfo.value.birthday ?? '';
countryController.text = AuthStore.to.userInfo.value.country ?? '';
super.onReady();
}
Future<void> saveUserInfo() async {
Map<String, dynamic> data = {
'nickname': nickNameController.text,
'birthday': birthdayController.text,
'country': countryController.text,
};
await AuthStore.to.saveUserInfo(data);
}

View File

@ -74,109 +74,109 @@ class UserInfoPage extends StatelessWidget {
SizedBox(
height: ScreenAdaper.height(15),
),
TextFormField(
controller: _controller.birthdayController,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(
ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0),
labelText: "Date of birth",
labelStyle: TextStyle(
color: const Color.fromARGB(255, 136, 136, 136),
fontSize: ScreenAdaper.sp(18)),
enabledBorder: const UnderlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(153, 191, 190, 190),
),
),
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(153, 191, 190, 190),
),
),
),
onTap: () async {
await showCupertinoModalPopup(
context: Get.context!,
builder: (context) => Container(
color: Colors.white,
height: 300,
child: CupertinoDatePicker(
initialDateTime: DateTime.parse(
_controller.birthdayController.text),
minimumDate: DateTime(1900),
maximumDate: DateTime.now()
.subtract(const Duration(days: 18 * 365)),
minimumYear: DateTime(1900).year,
maximumYear: DateTime.now()
.subtract(const Duration(days: 18 * 365))
.year,
mode: CupertinoDatePickerMode.date,
onDateTimeChanged: (pickeddate) {
_controller.birthdayController.text =
formatDate(pickeddate, [
yyyy,
'-',
mm,
'-',
dd,
]);
}),
));
},
style:
TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black),
cursorColor: const Color.fromARGB(255, 87, 86, 86)),
// TextFormField(
// controller: _controller.birthdayController,
// decoration: InputDecoration(
// contentPadding: EdgeInsets.fromLTRB(
// ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0),
// labelText: "Date of birth",
// labelStyle: TextStyle(
// color: const Color.fromARGB(255, 136, 136, 136),
// fontSize: ScreenAdaper.sp(18)),
// enabledBorder: const UnderlineInputBorder(
// borderSide: BorderSide(
// color: Color.fromARGB(153, 191, 190, 190),
// ),
// ),
// focusedBorder: const UnderlineInputBorder(
// borderSide: BorderSide(
// color: Color.fromARGB(153, 191, 190, 190),
// ),
// ),
// ),
// onTap: () async {
// await showCupertinoModalPopup(
// context: Get.context!,
// builder: (context) => Container(
// color: Colors.white,
// height: 300,
// child: CupertinoDatePicker(
// initialDateTime: DateTime.parse(
// _controller.birthdayController.text),
// minimumDate: DateTime(1900),
// maximumDate: DateTime.now()
// .subtract(const Duration(days: 18 * 365)),
// minimumYear: DateTime(1900).year,
// maximumYear: DateTime.now()
// .subtract(const Duration(days: 18 * 365))
// .year,
// mode: CupertinoDatePickerMode.date,
// onDateTimeChanged: (pickeddate) {
// _controller.birthdayController.text =
// formatDate(pickeddate, [
// yyyy,
// '-',
// mm,
// '-',
// dd,
// ]);
// }),
// ));
// },
// style:
// TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black),
// cursorColor: const Color.fromARGB(255, 87, 86, 86)),
SizedBox(
height: ScreenAdaper.height(15),
),
TextFormField(
controller: _controller.countryController,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(
ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0),
labelText: "Country",
labelStyle: TextStyle(
color: const Color.fromARGB(255, 136, 136, 136),
fontSize: ScreenAdaper.sp(18)),
enabledBorder: const UnderlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(153, 191, 190, 190),
),
),
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(
color: Color.fromARGB(153, 191, 190, 190),
),
),
),
onTap: () async {
await showCupertinoModalPopup(
context: Get.context!,
builder: (context) => Container(
color: Colors.white,
height: 300,
child: CupertinoPicker(
itemExtent: 50,
onSelectedItemChanged: (index) {
_controller.countryController.text =
Data.countryCodes[index];
},
children: Data.countryCodes
.map((e) => Container(
height: ScreenAdaper.height(50),
alignment: Alignment.center,
child: Text(
e,
style: TextStyle(
fontSize: ScreenAdaper.sp(30)),
),
))
.toList(),
)));
},
style:
TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black),
cursorColor: const Color.fromARGB(255, 87, 86, 86))
// TextFormField(
// controller: _controller.countryController,
// decoration: InputDecoration(
// contentPadding: EdgeInsets.fromLTRB(
// ScreenAdaper.width(12), 0, ScreenAdaper.width(12), 0),
// labelText: "Country",
// labelStyle: TextStyle(
// color: const Color.fromARGB(255, 136, 136, 136),
// fontSize: ScreenAdaper.sp(18)),
// enabledBorder: const UnderlineInputBorder(
// borderSide: BorderSide(
// color: Color.fromARGB(153, 191, 190, 190),
// ),
// ),
// focusedBorder: const UnderlineInputBorder(
// borderSide: BorderSide(
// color: Color.fromARGB(153, 191, 190, 190),
// ),
// ),
// ),
// onTap: () async {
// await showCupertinoModalPopup(
// context: Get.context!,
// builder: (context) => Container(
// color: Colors.white,
// height: 300,
// child: CupertinoPicker(
// itemExtent: 50,
// onSelectedItemChanged: (index) {
// _controller.countryController.text =
// Data.countryCodes[index];
// },
// children: Data.countryCodes
// .map((e) => Container(
// height: ScreenAdaper.height(50),
// alignment: Alignment.center,
// child: Text(
// e,
// style: TextStyle(
// fontSize: ScreenAdaper.sp(30)),
// ),
// ))
// .toList(),
// )));
// },
// style:
// TextStyle(fontSize: ScreenAdaper.sp(18), color: Colors.black),
// cursorColor: const Color.fromARGB(255, 87, 86, 86))
],
);
}

View File

@ -1,8 +1,10 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:package_info/package_info.dart';
import 'package:sk_base_mobile/app_theme.dart';
import 'package:sk_base_mobile/models/app_bottom_nav_item.dart';
import 'package:sk_base_mobile/models/app_config.dart';
import 'package:sk_base_mobile/screens/home/home.dart';
@ -25,14 +27,18 @@ class AppInfoService extends GetxService {
final isCameraing = RxBool(false);
List<AppBottomNavItem>? bottomNavItems = [
AppBottomNavItem(
icon: 'assets/images/landing_icon_bottom_0.png',
activeIcon: 'assets/images/landing_icon_bottom_active_0.png',
label: 'homepage',
icon: const Icon(Icons.home_outlined),
activeIcon: const Icon(
Icons.home,
),
label: '首页',
page: const HomePage()),
AppBottomNavItem(
icon: 'assets/images/landing_icon_bottom_3.png',
activeIcon: 'assets/images/landing_icon_bottom_active_3.png',
label: 'mine',
icon: const Icon(Icons.person_outline_outlined),
activeIcon: const Icon(
Icons.person,
),
label: '我的',
page: MinePage()),
];
Future<AppInfoService> init() async {
@ -40,8 +46,8 @@ class AppInfoService extends GetxService {
.info("[service-appInfo] Register app-related information service");
try {
await Future.wait(
[getDeviceInfo(), getPackageInfo(), getAppConfig(), getossPolicy()]);
// await Future.wait(
// [getDeviceInfo(), getPackageInfo(), getAppConfig(), getossPolicy()]);
requestPermission();
} catch (e) {
LoggerUtil().error(e);

View File

@ -14,9 +14,9 @@ class DioService extends Get.GetxService {
static DioService get to => Get.Get.find();
static Dio get dio => _dio;
static late Dio _dio;
List<String> whiteList = [Urls.googleTranslate];
List<String> whiteList = [Urls.login];
BaseOptions dioBaseOptions = BaseOptions(
connectTimeout: const Duration(minutes: 10),
connectTimeout: const Duration(seconds: 5),
baseUrl: '${GloablConfig.BASE_URL}',
followRedirects: true);
@ -33,7 +33,6 @@ class DioService extends Get.GetxService {
void onError(DioException e, ErrorInterceptorHandler handler) async {
if (whiteList.contains(e.requestOptions.path)) {
await SnackBarUtil().error(e.message);
return handler.next(e);
}
if (GloablConfig.DEBUG) {
@ -139,31 +138,6 @@ class DioService extends Get.GetxService {
if (response.data is String) {
responseData = jsonDecode(response.data);
}
switch (responseData['code']) {
case 0:
handler.next(response);
return;
//
case 10010304:
await AuthStore().logout(force: true);
await SnackBarUtil()
.error('Other devices have logged in, please log in again.');
break;
case 100103:
case 10010303:
await AuthStore().logout(force: true);
await SnackBarUtil()
.error('Login has timed out, please log in again.');
break;
case 10010301:
await AuthStore().logout(force: true);
await SnackBarUtil().error('Token can not empty');
break;
default:
await SnackBarUtil()
.error('${responseData['key']}: ${responseData['msg']}');
break;
}
} catch (e) {
printError(info: e.toString());
}

View File

@ -15,7 +15,7 @@ class StorageService extends GetxService {
{bool isWithUser = true}) async {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return await _prefs.setString(storeKey, value);
}
@ -23,7 +23,7 @@ class StorageService extends GetxService {
Future<bool> setBool(String key, bool value, {bool isWithUser = true}) async {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return await _prefs.setBool(storeKey, value);
}
@ -31,7 +31,7 @@ class StorageService extends GetxService {
Future<bool> setInt(String key, int value, {bool isWithUser = true}) async {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return await _prefs.setInt(storeKey, value);
}
@ -40,7 +40,7 @@ class StorageService extends GetxService {
{bool isWithUser = true}) async {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return await _prefs.setStringList(storeKey, value);
}
@ -48,7 +48,7 @@ class StorageService extends GetxService {
String? getString(String key, {bool isWithUser = true}) {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return _prefs.getString(storeKey);
}
@ -56,7 +56,7 @@ class StorageService extends GetxService {
int? getInt(String key, {bool isWithUser = true}) {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return _prefs.getInt(storeKey);
}
@ -64,7 +64,7 @@ class StorageService extends GetxService {
bool? getBool(String key, {bool isWithUser = true}) {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return _prefs.getBool(storeKey) ?? false;
}
@ -72,7 +72,7 @@ class StorageService extends GetxService {
List<String> getList(String key, {bool isWithUser = true}) {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return _prefs.getStringList(storeKey) ?? [];
}
@ -80,7 +80,7 @@ class StorageService extends GetxService {
Future<bool> remove(String key, {bool isWithUser = true}) async {
String storeKey = key;
if (isWithUser) {
storeKey = '${AuthStore.to.userInfo.value.userId}_$key';
storeKey = '${AuthStore.to.userInfo.value.id}_$key';
}
return await _prefs.remove(storeKey);
}

View File

@ -63,59 +63,49 @@ class AuthStore extends GetxController {
}
Future<void> logout({bool force = false}) async {
await LoadingUtil.show(status: 'Logout...');
LoadingUtil.show(status: 'Logout...');
await StorageService.to.remove(CacheKeys.token, isWithUser: false);
await StorageService.to.remove(CacheKeys.userInfo, isWithUser: false);
try {
final response = await Api.logout();
if (response.data != null) {
// final response = await Api.logout();
// if (response.data != null) {
LoggerUtil().info('[Store-Auth] Logout succeed.');
if (Get.context != null) Get.offAllNamed(RouteConfig.login);
}
// }
} catch (e) {
} finally {
LoadingUtil.dismiss();
}
}
Future<void> login(LoginEnum type, {String? identityToken}) async {
Future<void> login(
{required String username, required String password}) async {
Dio.Response response;
if (type == LoginEnum.fastLogin &&
StorageService.to.getString(CacheKeys.deviceUUID, isWithUser: false) ==
null) {
SnackBarUtil().error('Need DeviceUUID. Please restart app.');
return;
}
// if (type == LoginEnum.fastLogin &&
// StorageService.to.getString(CacheKeys.deviceUUID, isWithUser: false) ==
// null) {
// SnackBarUtil().error('Need DeviceUUID. Please restart app.');
// return;
// }
LoadingUtil.show(status: 'Login...');
// Hide keyboard
TapToDismissKeyboard.dismissOf(context: Get.context!);
try {
response = await Api.login(
'4',
type == LoginEnum.fastLogin
? (StorageService.to
.getString(CacheKeys.deviceUUID, isWithUser: false))
: identityToken);
await Future.delayed(const Duration(seconds: 1));
response = await Api.login(username, password);
if (response.data != null) {
final auth = Auth.fromJson(response.data['data']);
if (auth.token != null) {
await StorageService.to
.setString(CacheKeys.token, auth.token!, isWithUser: false);
}
if (auth.userInfo != null) {
userInfo(auth.userInfo!);
await StorageService.to.setString(
CacheKeys.userInfo, jsonEncode(auth.userInfo),
isWithUser: false);
LoggerUtil().info('[Store-Auth] Login succeed.');
}
await getUserInfo();
Get.offNamed(RouteConfig.home);
getCommonInfo();
// getCommonInfo();
}
} catch (e) {
SnackBarUtil().error('${e}');
await SnackBarUtil().error('账号密码错误');
} finally {
LoadingUtil.dismiss();
}
@ -130,7 +120,7 @@ class AuthStore extends GetxController {
Future<void> getUserInfo() async {
await LoadingUtil.show(status: 'Loading...');
try {
final response = await Api.getUserInfo(userInfo.value.userId!);
final response = await Api.getUserInfo();
if (response.data != null) {
UserInfoModel userInfo = UserInfoModel.fromJson(response.data['data']);
await updateUserInfoState(userInfo);

View File

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:sk_base_mobile/app_theme.dart';
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
/// Loading工具
class LoadingUtil {
LoadingUtil() {}
init() {}
LoadingUtil();
static Future<void> show({String? status}) async {
return showLoading(status: status ?? 'Loading...');
@ -14,27 +15,35 @@ class LoadingUtil {
return hideLoading();
}
static showLoading({String? status}) {
Get.dialog(
GestureDetector(
static showLoading({String? status}) async {
await showDialog(
context: Get.context!,
barrierColor: AppTheme.barrierColor,
barrierDismissible: false,
builder: (BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: GestureDetector(
child: Container(
color: Colors.black54,
child: const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
child: Center(
child: LoadingAnimationWidget.fourRotatingDots(
color: AppTheme.primaryColor,
size: ScreenAdaper.sp(50),
),
),
),
onTap: () {
// 退
Get.back();
// Navigator.of(context).pop();
},
),
barrierDismissible: false,
);
},
);
}
static hideLoading() {
Get.back();
Navigator.of(Get.context!).pop();
}
}

View File

@ -2,6 +2,7 @@ import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sk_base_mobile/app_theme.dart';
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
// SnackBar
class SnackBarUtil {
@ -25,13 +26,18 @@ class SnackBarUtil {
await Get.closeCurrentSnackbar();
}
Get.rawSnackbar(
message: title,
snackPosition: SnackPosition.TOP,
backgroundColor: AppTheme.snackbarErrorBackgroudColor,
borderRadius: 15,
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
borderRadius: ScreenAdaper.sp(15),
messageText: Text(
'$title',
style: TextStyle(
fontSize: ScreenAdaper.sp(25), color: AppTheme.nearlyWhite),
),
margin: EdgeInsets.symmetric(
horizontal: ScreenAdaper.width(20), vertical: 0),
overlayColor: Colors.white,
duration: Duration(seconds: 3),
duration: const Duration(seconds: 3),
forwardAnimationCurve: Curves.fastLinearToSlowEaseIn,
reverseAnimationCurve: Curves.linearToEaseOut);
}

View File

@ -51,7 +51,7 @@ class MyAvatarWidget extends StatelessWidget {
return _controller.uploadImgFilePath.value.isNotEmpty
? FileImage(File(_controller.uploadImgFilePath.value))
: NetworkImage(
AuthStore.to.userInfo.value.avatarThumbUrl ?? '',
AuthStore.to.userInfo.value.avatar ?? '',
);
}
// Widget getShowImg() {