1,新增获取设备信息的公用方法

2,用户登录新增入参:设备信息
3,注册接口新增入参:设备信息
This commit is contained in:
Daisy 2024-05-31 14:11:16 +08:00
parent 0a9aeb2027
commit fd4dab3e2e
9 changed files with 142 additions and 74 deletions

View File

@ -1,3 +1,7 @@
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import '../../flavors.dart'; import '../../flavors.dart';
class XSConstantMacro { class XSConstantMacro {
@ -85,4 +89,25 @@ class XSConstantMacro {
static int webBuyTypeVip = 3; //VIP购买 static int webBuyTypeVip = 3; //VIP购买
static int webBuyTypeAuth = 4; // static int webBuyTypeAuth = 4; //
static int webBuyTypeShop = 5; // static int webBuyTypeShop = 5; //
//
Future<Map<String, dynamic>> getDeviceInfoData() async {
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
final Map<String, dynamic> deviceData = <String, dynamic>{};
if (Platform.isAndroid) {
final AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
deviceData['deviceBrand'] = androidInfo.brand;
deviceData['deviceModel'] = androidInfo.model;
deviceData['deviceVersion'] = androidInfo.version.release;
deviceData['deviceType'] = 10;
} else if (Platform.isIOS) {
final IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
deviceData['deviceBrand'] = iosInfo.name;
deviceData['deviceModel'] = iosInfo.model;
deviceData['deviceVersion'] = iosInfo.systemVersion;
deviceData['deviceType'] = 20;
}
return deviceData;
}
} }

View File

@ -1,10 +1,11 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bugly_plugin/flutter_bugly_plugin.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/appRouters.dart'; import 'package:star_lock/appRouters.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/blue/blue_manage.dart'; import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/login/login/entity/LoginEntity.dart'; import 'package:star_lock/login/login/entity/LoginEntity.dart';
import 'package:star_lock/mine/mine/starLockMine_state.dart'; import 'package:star_lock/mine/mine/starLockMine_state.dart';
import 'package:star_lock/tools/baseGetXController.dart'; import 'package:star_lock/tools/baseGetXController.dart';
@ -44,7 +45,8 @@ class StarLockLoginLogic extends BaseGetXController {
loginType: '1', loginType: '1',
password: state.pwd.value, password: state.pwd.value,
countryCode: state.countryCode.value, countryCode: state.countryCode.value,
username: state.emailOrPhone.value); username: state.emailOrPhone.value,
deviceInfo: state.deviceInfoMap.value);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
Storage.saveLoginData(entity.data); Storage.saveLoginData(entity.data);
Storage.setBool(saveIsVip, entity.data!.isVip == 0 ? false : true); Storage.setBool(saveIsVip, entity.data!.isVip == 0 ? false : true);
@ -86,4 +88,16 @@ class StarLockLoginLogic extends BaseGetXController {
state.onClose(); state.onClose();
super.onClose(); super.onClose();
} }
@override
void onReady() {
super.onReady();
XSConstantMacro().getDeviceInfoData().then((Map<String, dynamic> data) {
state.deviceInfoMap.value = data;
}).catchError((error) {
//
AppLog.log('获取设备信息时出错: $error');
});
}
} }

View File

@ -19,6 +19,7 @@ class StarLockLoginState {
FocusNode emailOrPhoneFocusNode = FocusNode(); FocusNode emailOrPhoneFocusNode = FocusNode();
FocusNode pwdFocusNode = FocusNode(); FocusNode pwdFocusNode = FocusNode();
RxMap<String, dynamic> deviceInfoMap = <String, dynamic>{}.obs;
StarLockLoginState() { StarLockLoginState() {
// emailOrPhone.value = StoreService.to.getLastUserAccount() as String; // emailOrPhone.value = StoreService.to.getLastUserAccount() as String;

View File

@ -1,8 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/login/login/entity/LoginEntity.dart';
import 'package:star_lock/login/register/entity/SendValidationCodeEntity.dart';
import '../../network/api_repository.dart'; import '../../network/api_repository.dart';
import '../../tools/baseGetXController.dart'; import '../../tools/baseGetXController.dart';
@ -13,7 +15,7 @@ class StarLockRegisterLogic extends BaseGetXController {
late Timer _timer; late Timer _timer;
void _startTimer() { void _startTimer() {
_timer = Timer.periodic(1.seconds, (timer) { _timer = Timer.periodic(1.seconds, (Timer timer) {
if (state.currentSecond > 1) { if (state.currentSecond > 1) {
state.currentSecond--; state.currentSecond--;
} else { } else {
@ -29,35 +31,38 @@ class StarLockRegisterLogic extends BaseGetXController {
// _timer = null; // _timer = null;
} }
void register() async { Future<void> register() async {
AppLog.log("state.pwd.value:${state.pwd.value} state.surePwd.value:${state.surePwd.value}"); AppLog.log(
if(state.pwd.value != state.surePwd.value){ 'state.pwd.value:${state.pwd.value} state.surePwd.value:${state.surePwd.value}');
showToast("密码不一致哦".tr); if (state.pwd.value != state.surePwd.value) {
showToast('密码不一致哦'.tr);
return; return;
} }
var entity = await ApiRepository.to.register( final LoginEntity entity = await ApiRepository.to.register(
receiverType: state.isIphoneType.value == true ? 1 : 2, receiverType: state.isIphoneType.value == true ? 1 : 2,
countryCode: int.parse(state.countryCode.value), countryCode: int.parse(state.countryCode.value),
account: state.phoneOrEmailStr.value, account: state.phoneOrEmailStr.value,
password: state.pwd.value, password: state.pwd.value,
verificationCode: state.verificationCode.value); verificationCode: state.verificationCode.value,
deviceInfo: state.deviceInfoMap.value);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
showToast("注册成功".tr); showToast('注册成功'.tr);
Get.back(result:{ Get.back(result: <String, String>{
"phoneOrEmailStr":state.phoneOrEmailStr.value, 'phoneOrEmailStr': state.phoneOrEmailStr.value,
"pwd":state.pwd.value 'pwd': state.pwd.value
}); });
} }
} }
void sendValidationCode() async { Future<void> sendValidationCode() async {
var entity = await ApiRepository.to.sendValidationCodeUnLogin( final SendValidationCodeEntity entity =
// state.countryCode.value, await ApiRepository.to.sendValidationCodeUnLogin(
countryCode: state.countryCode.value.toString(), // state.countryCode.value,
account: state.phoneOrEmailStr.value, countryCode: state.countryCode.value.toString(),
channel: state.isIphoneType.value ? "1" : "2", account: state.phoneOrEmailStr.value,
codeType: '1', channel: state.isIphoneType.value ? '1' : '2',
xWidth: state.xWidth.value.toString()); codeType: '1',
xWidth: state.xWidth.value.toString());
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
_startTimer(); _startTimer();
} else {} } else {}
@ -93,4 +98,16 @@ class StarLockRegisterLogic extends BaseGetXController {
state.codeIsOK && state.codeIsOK &&
(state.isIphoneType.value ? state.isIphone : state.isEmail); (state.isIphoneType.value ? state.isIphone : state.isEmail);
} }
@override
void onReady() {
super.onReady();
XSConstantMacro().getDeviceInfoData().then((Map<String, dynamic> data) {
state.deviceInfoMap.value = data;
}).catchError((error) {
//
AppLog.log('获取设备信息时出错: $error');
});
}
} }

View File

@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/login/register/starLock_register_state.dart';
import '../../appRouters.dart'; import '../../appRouters.dart';
import '../../app_settings/app_colors.dart'; import '../../app_settings/app_colors.dart';
@ -21,8 +22,8 @@ class StarLockRegisterPage extends StatefulWidget {
} }
class _StarLockRegisterPageState extends State<StarLockRegisterPage> { class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
final logic = Get.put(StarLockRegisterLogic()); final StarLockRegisterLogic logic = Get.put(StarLockRegisterLogic());
final state = Get.find<StarLockRegisterLogic>().state; final StarLockRegisterState state = Get.find<StarLockRegisterLogic>().state;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -35,7 +36,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
backgroundColor: AppColors.mainColor), backgroundColor: AppColors.mainColor),
body: ListView( body: ListView(
padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w), padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w),
children: [ children: <Widget>[
topSelectCountryAndRegionWidget(), topSelectCountryAndRegionWidget(),
middleTFWidget(), middleTFWidget(),
Obx(() { Obx(() {
@ -67,11 +68,11 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
Widget topSelectCountryAndRegionWidget() { Widget topSelectCountryAndRegionWidget() {
return Column( return Column(
children: [ children: <Widget>[
SizedBox(height: 50.h), SizedBox(height: 50.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: <Widget>[
Container( Container(
width: 340.w, width: 340.w,
height: 60.h, height: 60.h,
@ -81,7 +82,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
border: border:
Border.all(width: 1.0, color: AppColors.greyLineColor)), Border.all(width: 1.0, color: AppColors.greyLineColor)),
child: Row( child: Row(
children: [ children: <Widget>[
GestureDetector( GestureDetector(
onTap: () { onTap: () {
state.isIphoneType.value = true; state.isIphoneType.value = true;
@ -141,19 +142,19 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
SizedBox(height: 60.h), SizedBox(height: 60.h),
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
var result = await Get.toNamed(Routers.selectCountryRegionPage); final result = await Get.toNamed(Routers.selectCountryRegionPage);
if (result != null) { if (result != null) {
result as Map<String, dynamic>; result as Map<String, dynamic>;
state.countryCode.value = result['code']; state.countryCode.value = result['code'];
state.countryName.value = result['countryName']; state.countryName.value = result['countryName'];
} }
AppLog.log( AppLog.log(
"路由返回值: $result, countryCode:${logic.state.countryCode}"); '路由返回值: $result, countryCode:${logic.state.countryCode}');
}, },
child: Obx(() => SizedBox( child: Obx(() => SizedBox(
height: 70.h, height: 70.h,
child: Row( child: Row(
children: [ children: <Widget>[
SizedBox(width: 5.w), SizedBox(width: 5.w),
Expanded( Expanded(
child: Text( child: Text(
@ -163,7 +164,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
SizedBox(width: 20.w), SizedBox(width: 20.w),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: <Widget>[
Text( Text(
state.isIphoneType.value state.isIphoneType.value
? '${state.countryName.value} +${state.countryCode.value}' ? '${state.countryName.value} +${state.countryCode.value}'
@ -194,7 +195,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
Widget middleTFWidget() { Widget middleTFWidget() {
return Column( return Column(
children: [ children: <Widget>[
Obx(() => LoginInput( Obx(() => LoginInput(
controller: state.phoneOrEmailController, controller: state.phoneOrEmailController,
onchangeAction: (v) { onchangeAction: (v) {
@ -207,7 +208,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
child: Image.asset( child: Image.asset(
state.isIphoneType.value state.isIphoneType.value
? 'images/icon_login_account.png' ? 'images/icon_login_account.png'
: "images/icon_login_email.png", : 'images/icon_login_email.png',
width: 30.w, width: 30.w,
height: 30.w, height: 30.w,
), ),
@ -215,7 +216,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
hintText: hintText:
"${TranslationLoader.lanKeys!.pleaseEnter!.tr}${state.isIphoneType.value ? "手机号".tr : TranslationLoader.lanKeys!.email!.tr}", "${TranslationLoader.lanKeys!.pleaseEnter!.tr}${state.isIphoneType.value ? "手机号".tr : TranslationLoader.lanKeys!.email!.tr}",
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [ inputFormatters: <TextInputFormatter>[
// FilteringTextInputFormatter.allow(RegExp('[0-9]')), // FilteringTextInputFormatter.allow(RegExp('[0-9]')),
LengthLimitingTextInputFormatter(30), LengthLimitingTextInputFormatter(30),
])), ])),
@ -236,8 +237,8 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
), ),
), ),
hintText: hintText:
"${TranslationLoader.lanKeys!.pleaseEnter!.tr}${TranslationLoader.lanKeys!.password!.tr}", '${TranslationLoader.lanKeys!.pleaseEnter!.tr}${TranslationLoader.lanKeys!.password!.tr}',
inputFormatters: [ inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(20), LengthLimitingTextInputFormatter(20),
]), ]),
SizedBox(height: 15.w), SizedBox(height: 15.w),
@ -263,13 +264,13 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
), ),
), ),
hintText: hintText:
"${TranslationLoader.lanKeys!.sure!.tr}${TranslationLoader.lanKeys!.password!.tr}", '${TranslationLoader.lanKeys!.sure!.tr}${TranslationLoader.lanKeys!.password!.tr}',
inputFormatters: [ inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(20), LengthLimitingTextInputFormatter(20),
]), ]),
SizedBox(height: 10.w), SizedBox(height: 10.w),
Row( Row(
children: [ children: <Widget>[
Expanded( Expanded(
child: LoginInput( child: LoginInput(
controller: state.codeController, controller: state.codeController,
@ -284,8 +285,8 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
), ),
), ),
hintText: hintText:
"${TranslationLoader.lanKeys!.pleaseEnter!.tr}${TranslationLoader.lanKeys!.verificationCode!.tr}", '${TranslationLoader.lanKeys!.pleaseEnter!.tr}${TranslationLoader.lanKeys!.verificationCode!.tr}',
inputFormatters: [ inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(20), LengthLimitingTextInputFormatter(20),
]), ]),
), ),
@ -297,14 +298,14 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
state.phoneOrEmailStrIsOK.value && state.canResend.value state.phoneOrEmailStrIsOK.value && state.canResend.value
? () async { ? () async {
// Navigator.pushNamed(context, Routers.safetyVerificationPage, arguments: {"countryCode":"+86", "account":state.phoneOrEmailStr.value}); // Navigator.pushNamed(context, Routers.safetyVerificationPage, arguments: {"countryCode":"+86", "account":state.phoneOrEmailStr.value});
var result = await Navigator.pushNamed( final Object? result = await Navigator.pushNamed(
context, Routers.safetyVerificationPage, context, Routers.safetyVerificationPage,
arguments: { arguments: <String, Object>{
"countryCode": state.countryCode, 'countryCode': state.countryCode,
"account": state.phoneOrEmailStr.value 'account': state.phoneOrEmailStr.value
}); });
state.xWidth.value = state.xWidth.value =
(result as Map<String, dynamic>)['xWidth']; (result! as Map<String, dynamic>)['xWidth'];
logic.sendValidationCode(); logic.sendValidationCode();
} }
: null, : null,
@ -337,7 +338,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
Widget _buildBottomAgreement() { Widget _buildBottomAgreement() {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: <Widget>[
Obx(() => GestureDetector( Obx(() => GestureDetector(
onTap: () { onTap: () {
state.agree.value = !state.agree.value; state.agree.value = !state.agree.value;
@ -358,7 +359,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
text: TextSpan( text: TextSpan(
text: TranslationLoader.lanKeys!.readAndAgree!.tr, text: TranslationLoader.lanKeys!.readAndAgree!.tr,
style: TextStyle(color: const Color(0xff333333), fontSize: 20.sp), style: TextStyle(color: const Color(0xff333333), fontSize: 20.sp),
children: [ children: <InlineSpan>[
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: GestureDetector( child: GestureDetector(
@ -367,10 +368,11 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
style: TextStyle( style: TextStyle(
color: AppColors.mainColor, fontSize: 20.sp)), color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, arguments: { Get.toNamed(Routers.webviewShowPage,
"url": XSConstantMacro.userAgreementURL, arguments: <String, String>{
"title": '用户协议'.tr 'url': XSConstantMacro.userAgreementURL,
}); 'title': '用户协议'.tr
});
}, },
)), )),
WidgetSpan( WidgetSpan(
@ -381,10 +383,11 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
style: TextStyle( style: TextStyle(
color: AppColors.mainColor, fontSize: 20.sp)), color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, arguments: { Get.toNamed(Routers.webviewShowPage,
"url": XSConstantMacro.privacyPolicyURL, arguments: <String, String>{
"title": '隐私政策'.tr 'url': XSConstantMacro.privacyPolicyURL,
}); 'title': '隐私政策'.tr
});
}, },
)), )),
], ],

View File

@ -32,6 +32,7 @@ class StarLockRegisterState {
var btnText = ''.obs; var btnText = ''.obs;
var totalSeconds = 120; var totalSeconds = 120;
var currentSecond = 120; var currentSecond = 120;
RxMap<String, dynamic> deviceInfoMap = <String, dynamic>{}.obs;
StarLockRegisterState() { StarLockRegisterState() {
resetResend(); resetResend();

View File

@ -193,18 +193,21 @@ class _StarLockRegisterPageState extends State<StarLockRegisterXHJPage> {
), ),
Obx(() => GestureDetector( Obx(() => GestureDetector(
onTap: onTap:
state.phoneOrEmailStrIsOK.value && state.canResend.value ? () async { state.phoneOrEmailStrIsOK.value && state.canResend.value
? () async {
// Navigator.pushNamed(context, Routers.safetyVerificationPage, arguments: {"countryCode":"+86", "account":state.phoneOrEmailStr.value}); // Navigator.pushNamed(context, Routers.safetyVerificationPage, arguments: {"countryCode":"+86", "account":state.phoneOrEmailStr.value});
if(state.pwd.value != state.surePwd.value){ if (state.pwd.value != state.surePwd.value) {
logic.showToast("密码不一致哦".tr); logic.showToast("密码不一致哦".tr);
return; return;
} }
var result = await Get.toNamed(Routers.safetyVerificationPage, var result = await Get.toNamed(
Routers.safetyVerificationPage,
arguments: { arguments: {
"countryCode": state.countryCode, "countryCode": state.countryCode,
"account": state.phoneOrEmailStr.value "account": state.phoneOrEmailStr.value
}); });
state.xWidth.value = (result as Map<String, dynamic>)['xWidth']; state.xWidth.value =
(result as Map<String, dynamic>)['xWidth'];
logic.sendValidationCode(); logic.sendValidationCode();
} }
: null, : null,

View File

@ -22,6 +22,7 @@ class ApiProvider extends BaseProvider {
String account, String account,
String password, String password,
String verificationCode, String verificationCode,
Map deviceInfo,
) => ) =>
post( post(
registerUrl.toUrl, registerUrl.toUrl,
@ -32,6 +33,7 @@ class ApiProvider extends BaseProvider {
'password': password, 'password': password,
'verificationCode': verificationCode, 'verificationCode': verificationCode,
'platId': '2', 'platId': '2',
'deviceInfo': deviceInfo,
})); }));
// post( // post(
@ -65,7 +67,7 @@ class ApiProvider extends BaseProvider {
})); }));
Future<Response> login(String loginType, String password, String countryCode, Future<Response> login(String loginType, String password, String countryCode,
String username) => String username, Map deviceInfo) =>
post( post(
loginUrl.toUrl, loginUrl.toUrl,
jsonEncode({ jsonEncode({
@ -74,7 +76,8 @@ class ApiProvider extends BaseProvider {
'platId': '2', 'platId': '2',
'uniqueid': '477E6814-289D-402A-9F49-F89A8BD05D63', 'uniqueid': '477E6814-289D-402A-9F49-F89A8BD05D63',
'countryCode': countryCode, 'countryCode': countryCode,
'username': username 'username': username,
'deviceInfo': deviceInfo,
})); }));
Future<Response> resetPassword( Future<Response> resetPassword(

View File

@ -98,9 +98,10 @@ class ApiRepository {
required int countryCode, required int countryCode,
required String account, required String account,
required String password, required String password,
required String verificationCode}) async { required String verificationCode,
final res = await apiProvider.register( required Map deviceInfo}) async {
receiverType, countryCode, account, password, verificationCode); final res = await apiProvider.register(receiverType, countryCode, account,
password, verificationCode, deviceInfo);
return LoginEntity.fromJson(res.body); return LoginEntity.fromJson(res.body);
} }
@ -124,9 +125,10 @@ class ApiRepository {
{required String loginType, {required String loginType,
required String password, required String password,
required String countryCode, required String countryCode,
required String username}) async { required String username,
final res = required Map deviceInfo}) async {
await apiProvider.login(loginType, password, countryCode, username); final res = await apiProvider.login(
loginType, password, countryCode, username, deviceInfo);
return LoginEntity.fromJson(res.body); return LoginEntity.fromJson(res.body);
} }
@ -2154,8 +2156,7 @@ class ApiRepository {
// //
Future<GetAppInfo> getAppInfo() async { Future<GetAppInfo> getAppInfo() async {
final Response<dynamic> res = final Response<dynamic> res = await apiProvider.getAppInfo();
await apiProvider.getAppInfo();
return GetAppInfo.fromJson(res.body); return GetAppInfo.fromJson(res.body);
} }
} }