Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
ChatGPT
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
关振斌
ChatGPT
Commits
8fcf01e0
Commit
8fcf01e0
authored
Feb 14, 2023
by
关振斌
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pay
parent
d91de89f
Changes
18
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
736 additions
and
545 deletions
+736
-545
ios/Podfile.lock
ios/Podfile.lock
+6
-0
lib/constant/app_urls.dart
lib/constant/app_urls.dart
+3
-1
lib/entity/login_entity.dart
lib/entity/login_entity.dart
+13
-12
lib/entity/user_entity.dart
lib/entity/user_entity.dart
+31
-0
lib/models/user_model.dart
lib/models/user_model.dart
+23
-26
lib/pages/goods/goods_page.dart
lib/pages/goods/goods_page.dart
+10
-0
lib/pages/login/authentication_screen.dart
lib/pages/login/authentication_screen.dart
+0
-83
lib/pages/login/login_page.dart
lib/pages/login/login_page.dart
+163
-58
lib/pages/login/msm_page.dart
lib/pages/login/msm_page.dart
+300
-0
lib/pages/login/splash_screen.dart
lib/pages/login/splash_screen.dart
+0
-48
lib/pages/login/verify_phone_number_screen.dart
lib/pages/login/verify_phone_number_screen.dart
+0
-236
lib/pages/user/user_page.dart
lib/pages/user/user_page.dart
+111
-78
lib/router/router_handlers.dart
lib/router/router_handlers.dart
+6
-0
lib/router/routers.dart
lib/router/routers.dart
+3
-0
lib/service/user_service.dart
lib/service/user_service.dart
+20
-1
lib/utils/http_util.dart
lib/utils/http_util.dart
+4
-2
pubspec.lock
pubspec.lock
+42
-0
pubspec.yaml
pubspec.yaml
+1
-0
No files found.
ios/Podfile.lock
View file @
8fcf01e0
...
...
@@ -73,6 +73,8 @@ PODS:
- flutter_inappwebview/Core (0.0.1):
- Flutter
- OrderedSet (~> 5.0)
- fluttercontactpicker (4.6.0):
- Flutter
- fluttertoast (0.0.2):
- Flutter
- Toast
...
...
@@ -127,6 +129,7 @@ DEPENDENCIES:
- flutter_icmp_ping (from `.symlinks/plugins/flutter_icmp_ping/ios`)
- flutter_inapp_purchase (from `.symlinks/plugins/flutter_inapp_purchase/ios`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- fluttercontactpicker (from `.symlinks/plugins/fluttercontactpicker/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
...
...
@@ -172,6 +175,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_inapp_purchase/ios"
flutter_inappwebview:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
fluttercontactpicker:
:path: ".symlinks/plugins/fluttercontactpicker/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
image_picker_ios:
...
...
@@ -205,6 +210,7 @@ SPEC CHECKSUMS:
flutter_icmp_ping: 2b159955eee0c487c766ad83fec224ae35e7c935
flutter_inapp_purchase: 5c6a1ac3f11b11d0c8c0321c0c41c1f05805e4c8
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
fluttercontactpicker: d582836dea6b5d489f3d259f35d7817ae82ee5e6
fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0
GoogleUtilities: c2bdc4cf2ce786c4d2e6b3bcfd599a25ca78f06f
GTMSessionFetcher: c9e714f7eec91a55641e2bab9f45fd83a219b882
...
...
lib/constant/app_urls.dart
View file @
8fcf01e0
...
...
@@ -3,6 +3,7 @@ class AppUrls {
static
const
String
baseApiUrl
=
'
${baseUrl}
/api'
;
// 基础接口地址
// http://101.34.153.228:8083/api/doc.html
//'http://192.168.110.1:8083';
// static const String login = '$baseApiUrl/passport/auth/login';
// static const String register = '$baseApiUrl/passport/auth/register';
// static const String getQuickLoginUrl =
...
...
@@ -20,6 +21,7 @@ class AppUrls {
static
const
String
getUserIntegral
=
'
$baseApiUrl
/user/getUserIntegral'
;
static
const
String
getSearchRecord
=
'
$baseApiUrl
/searchRecord/getSearchRecord'
;
static
const
String
sendSms
=
'
$baseApiUrl
/sms/sendSms'
;
static
const
String
applePayCallBack
=
'
$baseApiUrl
/pay/notifyApplePay'
;
static
const
String
register
=
'
$baseApiUrl
/user/register'
;
}
lib/entity/login_entity.dart
View file @
8fcf01e0
...
...
@@ -5,25 +5,26 @@
import
'dart:convert'
;
class
LoginEntity
{
LoginEntity
({
required
this
.
token
,
required
this
.
authData
,
});
LoginEntity
({
required
this
.
username
,
required
this
.
id
,
required
this
.
token
});
final
String
username
;
final
int
id
;
final
String
token
;
final
String
authData
;
factory
LoginEntity
.
fromJson
(
String
str
)
=>
LoginEntity
.
fromMap
(
json
.
decode
(
str
));
factory
LoginEntity
.
fromJson
(
String
str
)
=>
LoginEntity
.
fromMap
(
json
.
decode
(
str
));
String
toJson
()
=>
json
.
encode
(
toMap
());
factory
LoginEntity
.
fromMap
(
Map
<
String
,
dynamic
>
json
)
=>
LoginEntity
(
token:
json
[
"token"
],
authData:
json
[
"auth_data"
],
);
username:
json
[
"username"
],
id:
json
[
"id"
],
token:
json
[
'token'
],
);
Map
<
String
,
dynamic
>
toMap
()
=>
{
"token"
:
token
,
"auth_token"
:
authData
,
};
"username"
:
username
,
"id"
:
id
,
"token"
:
token
,
};
}
lib/entity/user_entity.dart
View file @
8fcf01e0
...
...
@@ -215,3 +215,34 @@ class ApplePayEntity {
"timestamp"
:
timestamp
};
}
class
MsmEntity
{
MsmEntity
(
{
required
this
.
status
,
required
this
.
message
,
required
this
.
data
,
required
this
.
timestamp
});
final
int
status
;
final
String
message
;
final
dynamic
data
;
final
int
timestamp
;
factory
MsmEntity
.
fromJson
(
String
str
)
=>
MsmEntity
.
fromMap
(
json
.
decode
(
str
));
String
toJson
()
=>
json
.
encode
(
toMap
());
factory
MsmEntity
.
fromMap
(
Map
<
String
,
dynamic
>
json
)
=>
MsmEntity
(
status:
json
[
"status"
],
message:
json
[
"message"
],
timestamp:
json
[
'timestamp'
],
data:
json
[
'data'
],
);
Map
<
String
,
dynamic
>
toMap
()
=>
{
"status"
:
status
,
"message"
:
message
,
"data"
:
data
,
"timestamp"
:
timestamp
};
}
lib/models/user_model.dart
View file @
8fcf01e0
...
...
@@ -33,32 +33,29 @@ class UserModel extends BaseModel {
refreshData
()
async
{
_integralEntity
=
IntegralEntity
(
id:
1
,
username:
''
);
//
_isFirstOpen = await SharedPreferencesUtil.getInstance()
//
?.getBool(AppStrings.isFirstOpen) ??
//
true;
//
String token = await SharedPreferencesUtil.getInstance()
//
?.getString(AppStrings.token) ??
//
'';
_isFirstOpen
=
await
SharedPreferencesUtil
.
getInstance
()
?.
getBool
(
AppStrings
.
isFirstOpen
)
??
true
;
String
token
=
await
SharedPreferencesUtil
.
getInstance
()
?.
getString
(
AppStrings
.
token
)
??
''
;
// String authData = await SharedPreferencesUtil.getInstance()
// ?.getString(AppStrings.authData) ??
// '';
// if (token != null &&
// token.isNotEmpty &&
// authData != null &&
// authData.isNotEmpty) {
// _isLogin = true;
// _token = token;
// _authData = authData;
// Map<String, dynamic> userEntityMap =
// await SharedPreferencesUtil.getInstance()
// ?.getMap(AppStrings.userInfo) ??
// <String, dynamic>{};
// _userEntity = UserEntity.fromMap(userEntityMap);
// notifyListeners();
// }
if
(
token
!=
null
&&
token
.
isNotEmpty
)
{
_isLogin
=
true
;
_token
=
token
;
// _authData = authData;
// Map<String, dynamic> userEntityMap =
// await SharedPreferencesUtil.getInstance()
// ?.getMap(AppStrings.userInfo) ??
// <String, dynamic>{};
// _userEntity = UserEntity.fromMap(userEntityMap);
// notifyListeners();
}
}
logout
()
{
...
...
@@ -88,7 +85,7 @@ class UserModel extends BaseModel {
SharedPreferencesUtil
.
getInstance
();
await
sharedPreferencesUtil
?.
setString
(
AppStrings
.
authData
,
loginEntity
.
authData
);
AppStrings
.
authData
,
loginEntity
.
username
);
}
_saveUserInfo
()
async
{
...
...
@@ -105,11 +102,11 @@ class UserModel extends BaseModel {
_saveIsFirstOpen
();
}
setToken
(
LoginEntity
loginEntity
)
{
setToken
(
LoginEntity
loginEntity
)
async
{
_token
=
loginEntity
.
token
;
_authData
=
loginEntity
.
authData
;
//
_authData = loginEntity.authData;
_isLogin
=
true
;
await
setIntegralInfo
();
_saveUserToken
(
loginEntity
);
_setUserAuthData
(
loginEntity
);
}
...
...
lib/pages/goods/goods_page.dart
View file @
8fcf01e0
...
...
@@ -40,6 +40,7 @@ class GoodsPageState extends State<GoodsPage> {
String
_platformVersion
=
'Unknown'
;
List
<
IAPItem
>
_items
=
[];
List
<
PurchasedItem
>
_purchases
=
[];
// var guides = [AppImages.guide1, AppImages.guide2, AppImages.guide3];
// var _showButton = false;
...
...
@@ -130,6 +131,7 @@ class GoodsPageState extends State<GoodsPage> {
});
if
(
res
?.
status
==
200
)
{
await
FlutterInappPurchase
.
instance
.
clearTransactionIOS
();
EasyLoading
.
showSuccess
(
'
${res?.message}
'
);
EasyLoading
.
dismiss
();
}
else
{
...
...
@@ -163,6 +165,14 @@ class GoodsPageState extends State<GoodsPage> {
});
}
@override
dispose
()
{
_purchaseUpdatedSubscription
.
cancel
();
_purchaseErrorSubscription
.
cancel
();
_conectionSubscription
.
cancel
();
super
.
dispose
();
}
Future
_getProduct
()
async
{
try
{
List
<
IAPItem
>
items
=
...
...
lib/pages/login/authentication_screen.dart
deleted
100644 → 0
View file @
d91de89f
import
'package:easy_container/easy_container.dart'
;
import
'package:flutter/material.dart'
;
import
'package:intl_phone_field/intl_phone_field.dart'
;
import
'package:chart/utils/helpers.dart'
;
import
'package:chart/pages/login/verify_phone_number_screen.dart'
;
class
AuthenticationScreen
extends
StatefulWidget
{
static
const
id
=
'AuthenticationScreen'
;
const
AuthenticationScreen
({
Key
?
key
,
})
:
super
(
key:
key
);
@override
// ignore: library_private_types_in_public_api
_AuthenticationScreenState
createState
()
=>
_AuthenticationScreenState
();
}
class
_AuthenticationScreenState
extends
State
<
AuthenticationScreen
>
{
String
?
phoneNumber
;
final
_formKey
=
GlobalKey
<
FormState
>();
@override
Widget
build
(
BuildContext
context
)
{
return
SafeArea
(
child:
Scaffold
(
body:
Padding
(
padding:
const
EdgeInsets
.
all
(
15
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
const
Text
(
"We'll send an SMS with a verification code..."
,
style:
TextStyle
(
fontSize:
22
),
),
const
SizedBox
(
height:
15
),
EasyContainer
(
elevation:
0
,
borderRadius:
10
,
color:
Colors
.
transparent
,
child:
Form
(
key:
_formKey
,
child:
IntlPhoneField
(
autofocus:
true
,
invalidNumberMessage:
'Invalid Phone Number!'
,
textAlignVertical:
TextAlignVertical
.
center
,
style:
const
TextStyle
(
fontSize:
25
),
onChanged:
(
phone
)
=>
phoneNumber
=
phone
.
completeNumber
,
initialCountryCode:
'IN'
,
flagsButtonPadding:
const
EdgeInsets
.
only
(
right:
10
),
showDropdownIcon:
false
,
keyboardType:
TextInputType
.
phone
,
),
),
),
const
SizedBox
(
height:
15
),
EasyContainer
(
width:
double
.
infinity
,
onTap:
()
async
{
if
(
isNullOrBlank
(
phoneNumber
)
||
!
_formKey
.
currentState
!.
validate
())
{
showSnackBar
(
'Please enter a valid phone number!'
);
}
else
{
Navigator
.
pushNamed
(
context
,
VerifyPhoneNumberScreen
.
id
,
arguments:
phoneNumber
,
);
}
},
child:
const
Text
(
'Verify'
,
style:
TextStyle
(
fontSize:
18
),
),
),
],
),
),
),
);
}
}
lib/pages/login/login_page.dart
View file @
8fcf01e0
import
'package:easy_container/easy_container.dart'
;
import
'package:firebase_phone_auth_handler/firebase_phone_auth_handler.dart'
;
import
'dart:async'
;
import
'package:chart/entity/user_entity.dart'
;
import
'package:chart/pages/dashboard/dashboard_page.dart'
;
import
'package:flutter_easyloading/flutter_easyloading.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'package:flutter/material.dart'
;
import
'package:chart/pages/login/authentication_screen.dart'
;
import
'package:chart/utils/globals.dart'
;
import
'package:chart/utils/helpers.dart'
;
import
'package:flutter/services.dart'
;
import
'package:url_launcher/link.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'package:pinput/pinput.dart'
;
import
"package:chart/service/user_service.dart"
;
// import 'package:intl_phone_field/intl_phone_field.dart';
class
LoginPage
extends
StatefulWidget
{
const
LoginPage
({
super
.
key
});
class
LoginPage
extends
StatelessWidget
{
static
const
id
=
'LoginPage'
;
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
const
LoginPage
({
Key
?
key
,
})
:
super
(
key:
key
);
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
@override
State
<
LoginPage
>
createState
()
=>
_MyHomePageState
();
}
class
_MyHomePageState
extends
State
<
LoginPage
>
{
TextEditingController
controller
=
TextEditingController
();
// final pinController = TextEditingController();
// final focusNode = FocusNode();
final
formKey
=
GlobalKey
<
FormState
>();
@override
void
dispose
()
{
// pinController.dispose();
// focusNode.dispose();
super
.
dispose
();
}
// bool _hasCallSupport = false;
// Future<void>? _launched;
// String _phone = '';
@override
void
initState
()
{
super
.
initState
();
// Check for phone call support.
// canLaunchUrl(Uri(scheme: 'tel', path: '123')).then((bool result) {
// setState(() {
// _hasCallSupport = result;
// });
// });
}
_getCode
()
async
{
EasyLoading
.
show
(
status:
"发送验证码..."
);
var
phone
=
controller
.
text
.
replaceAll
(
"+"
,
""
)
.
replaceAll
(
new
RegExp
(
r"\s+\b|\b\s"
),
""
);
try
{
MsmEntity
?
res
=
await
UserService
().
sendSms
({
"phone"
:
phone
});
print
(
"
$res
"
);
if
(
res
?.
status
==
200
)
{
EasyLoading
.
showSuccess
(
'验证码发送正确'
);
Navigator
.
of
(
context
)
.
pushNamed
(
'/ms-code'
,
arguments:
{
"phone"
:
phone
});
// Navigator.of(context).pushNamed("/chat",
// arguments: {"phone": message.question})
}
else
{
EasyLoading
.
showError
(
"
${res?.message}
"
);
}
EasyLoading
.
dismiss
();
}
catch
(
e
)
{
EasyLoading
.
showError
(
"发送验证码频率过快"
);
EasyLoading
.
dismiss
();
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
SafeArea
(
child:
Scaffold
(
body:
Padding
(
padding:
const
EdgeInsets
.
all
(
15
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
children:
[
const
Padding
(
padding:
EdgeInsets
.
all
(
15
),
// child: ,
// child: SizedBox(
// width: double.infinity,
// child: FittedBox(
// child: Text('Logged in user UID'),
// ),
// ),
// onPressed calls using this URL are not gated on a 'canLaunch' check
// because the assumption is that every device can launch a web URL.
final
Uri
toLaunch
=
Uri
(
scheme:
'https'
,
host:
'www.cylog.org'
,
path:
'headers/'
);
const
focusedBorderColor
=
Color
.
fromRGBO
(
23
,
171
,
144
,
1
);
const
fillColor
=
Color
.
fromRGBO
(
243
,
246
,
249
,
0
);
const
borderColor
=
Color
.
fromRGBO
(
23
,
171
,
144
,
0.4
);
final
defaultPinTheme
=
PinTheme
(
width:
56
,
height:
56
,
textStyle:
const
TextStyle
(
fontSize:
22
,
color:
Color
.
fromRGBO
(
30
,
60
,
87
,
1
),
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
19
),
border:
Border
.
all
(
color:
borderColor
),
),
);
return
Scaffold
(
appBar:
AppBar
(),
body:
Container
(
decoration:
BoxDecoration
(
image:
DecorationImage
(
image:
Image
.
asset
(
"assets/images/bg.png"
).
image
,
fit:
BoxFit
.
cover
),
),
// p
padding:
EdgeInsets
.
symmetric
(
horizontal:
40
),
// color: Colors.red,
width:
double
.
infinity
,
height:
double
.
infinity
,
child:
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
TextField
(
autofocus:
true
,
controller:
controller
,
keyboardType:
TextInputType
.
phone
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
),
decoration:
InputDecoration
(
labelText:
'电话号码'
,
border:
OutlineInputBorder
(
borderSide:
BorderSide
(),
),
),
textInputAction:
TextInputAction
.
done
,
inputFormatters:
<
TextInputFormatter
>[
LengthLimitingTextInputFormatter
(
13
)
],
onChanged:
(
v
)
=>
_splitPhoneNumber
(
v
),
),
// SizedBox(
// width: double.infinity,
// child: FittedBox(
// // child: Text(Globals.firebaseUser!.uid),
// ),
// ),
EasyContainer
(
onTap:
()
async
{
// await FirebasePhoneAuthHandler.signOut(context);
// showSnackBar('Logged out successfully!');
// ignore: use_build_context_synchronously
// Navigator.pushNamedAndRemoveUntil(
// context,
// AuthenticationScreen.id,
// (route) => false,
// );
},
child:
const
Text
(
'Logout'
),
SizedBox
(
height:
20
,
),
],
MaterialButton
(
child:
Text
(
'确定'
),
color:
Theme
.
of
(
context
).
primaryColor
,
textColor:
Colors
.
white
,
onPressed:
_getCode
),
]),
),
),
),
);
));
}
}
int
inputLength
=
0
;
void
_splitPhoneNumber
(
String
text
)
{
if
(
text
.
length
>
inputLength
)
{
//输入
if
(
text
.
length
==
4
||
text
.
length
==
9
)
{
text
=
text
.
substring
(
0
,
text
.
length
-
1
)
+
" "
+
text
.
substring
(
text
.
length
-
1
,
text
.
length
);
controller
.
text
=
text
;
controller
.
selection
=
TextSelection
.
fromPosition
(
TextPosition
(
affinity:
TextAffinity
.
downstream
,
offset:
text
.
length
));
}
}
else
{
//删除
if
(
text
.
length
==
4
||
text
.
length
==
9
)
{
text
=
text
.
substring
(
0
,
text
.
length
-
1
);
controller
.
text
=
text
;
controller
.
selection
=
TextSelection
.
fromPosition
(
TextPosition
(
affinity:
TextAffinity
.
downstream
,
offset:
text
.
length
));
}
}
// Scaffold(
// appBar: AppBar(
// title: Text('Phone Field Example'),
// ),
// body: ,
// );
\ No newline at end of file
inputLength
=
text
.
length
;
}
}
lib/pages/login/msm_page.dart
0 → 100644
View file @
8fcf01e0
This diff is collapsed.
Click to expand it.
lib/pages/login/splash_screen.dart
deleted
100644 → 0
View file @
d91de89f
import
'package:flutter/material.dart'
;
// import 'package:phone_auth_handler_demo/screens/authentication_screen.dart';
import
'package:chart/pages/login/authentication_screen.dart'
;
// import 'package:phone_auth_handler_demo/screens/home_screen.dart';
import
'package:chart/pages/login/login_page.dart'
;
// import 'package:phone_auth_handler_demo/utils/globals.dart';
// import 'package:phone_auth_handler_demo/widgets/custom_loader.dart';
import
'package:chart/widgets/custom_loader.dart'
;
import
'package:chart/utils/globals.dart'
;
// import 'package:chart/utils/helpers.dart';
class
SplashScreen
extends
StatefulWidget
{
static
const
id
=
'SplashScreen'
;
const
SplashScreen
({
Key
?
key
,
})
:
super
(
key:
key
);
@override
// ignore: library_private_types_in_public_api
_SplashScreenState
createState
()
=>
_SplashScreenState
();
}
class
_SplashScreenState
extends
State
<
SplashScreen
>
{
@override
void
initState
()
{
(()
async
{
await
Future
.
delayed
(
Duration
.
zero
);
final
isLoggedIn
=
Globals
.
firebaseUser
!=
null
;
if
(!
mounted
)
return
;
Navigator
.
pushReplacementNamed
(
context
,
isLoggedIn
?
LoginPage
.
id
:
AuthenticationScreen
.
id
,
);
})();
super
.
initState
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
const
SafeArea
(
child:
Scaffold
(
body:
CustomLoader
(),
),
);
}
}
lib/pages/login/verify_phone_number_screen.dart
deleted
100644 → 0
View file @
d91de89f
import
'package:firebase_phone_auth_handler/firebase_phone_auth_handler.dart'
;
import
'package:flutter/material.dart'
;
import
'package:chart/pages/login/login_page.dart'
;
// import 'package:phone_auth_handler_demo/utils/helpers.dart';
import
'package:chart/widgets/custom_loader.dart'
;
import
'package:chart/widgets/pin_input_field.dart'
;
// import 'package:chart/utils/globals.dart';
import
'package:chart/utils/helpers.dart'
;
// import 'package:phone_auth_handler_demo/utils/helpers.dart';
// import 'package:phone_auth_handler_demo/widgets/custom_loader.dart';
// import 'package:phone_auth_handler_demo/widgets/pin_input_field.dart';
class
VerifyPhoneNumberScreen
extends
StatefulWidget
{
static
const
id
=
'VerifyPhoneNumberScreen'
;
final
String
phoneNumber
;
const
VerifyPhoneNumberScreen
({
Key
?
key
,
required
this
.
phoneNumber
,
})
:
super
(
key:
key
);
@override
State
<
VerifyPhoneNumberScreen
>
createState
()
=>
_VerifyPhoneNumberScreenState
();
}
class
_VerifyPhoneNumberScreenState
extends
State
<
VerifyPhoneNumberScreen
>
with
WidgetsBindingObserver
{
bool
isKeyboardVisible
=
false
;
late
final
ScrollController
scrollController
;
@override
void
initState
()
{
scrollController
=
ScrollController
();
WidgetsBinding
.
instance
.
addObserver
(
this
);
super
.
initState
();
}
@override
void
dispose
()
{
WidgetsBinding
.
instance
.
removeObserver
(
this
);
scrollController
.
dispose
();
super
.
dispose
();
}
@override
void
didChangeMetrics
()
{
final
bottomViewInsets
=
WidgetsBinding
.
instance
.
window
.
viewInsets
.
bottom
;
isKeyboardVisible
=
bottomViewInsets
>
0
;
}
// scroll to bottom of screen, when pin input field is in focus.
Future
<
void
>
_scrollToBottomOnKeyboardOpen
()
async
{
while
(!
isKeyboardVisible
)
{
await
Future
.
delayed
(
const
Duration
(
milliseconds:
50
));
}
await
Future
.
delayed
(
const
Duration
(
milliseconds:
250
));
await
scrollController
.
animateTo
(
scrollController
.
position
.
maxScrollExtent
,
duration:
const
Duration
(
milliseconds:
250
),
curve:
Curves
.
easeIn
,
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
SafeArea
(
child:
FirebasePhoneAuthHandler
(
phoneNumber:
widget
.
phoneNumber
,
signOutOnSuccessfulVerification:
false
,
sendOtpOnInitialize:
true
,
linkWithExistingUser:
false
,
autoRetrievalTimeOutDuration:
const
Duration
(
seconds:
60
),
otpExpirationDuration:
const
Duration
(
seconds:
60
),
onCodeSent:
()
{
log
(
VerifyPhoneNumberScreen
.
id
,
msg:
'OTP sent!'
);
},
onLoginSuccess:
(
userCredential
,
autoVerified
)
async
{
log
(
VerifyPhoneNumberScreen
.
id
,
msg:
autoVerified
?
'OTP was fetched automatically!'
:
'OTP was verified manually!'
,
);
showSnackBar
(
'Phone number verified successfully!'
);
log
(
VerifyPhoneNumberScreen
.
id
,
msg:
'Login Success UID:
${userCredential.user?.uid}
'
,
);
Navigator
.
pushNamedAndRemoveUntil
(
context
,
LoginPage
.
id
,
(
route
)
=>
false
,
);
},
onLoginFailed:
(
authException
,
stackTrace
)
{
log
(
VerifyPhoneNumberScreen
.
id
,
msg:
authException
.
message
,
error:
authException
,
stackTrace:
stackTrace
,
);
switch
(
authException
.
code
)
{
case
'invalid-phone-number'
:
// invalid phone number
return
showSnackBar
(
'Invalid phone number!'
);
case
'invalid-verification-code'
:
// invalid otp entered
return
showSnackBar
(
'The entered OTP is invalid!'
);
// handle other error codes
default
:
showSnackBar
(
'Something went wrong!'
);
// handle error further if needed
}
},
onError:
(
error
,
stackTrace
)
{
log
(
VerifyPhoneNumberScreen
.
id
,
error:
error
,
stackTrace:
stackTrace
,
);
showSnackBar
(
'An error occurred!'
);
},
builder:
(
context
,
controller
)
{
return
Scaffold
(
appBar:
AppBar
(
leadingWidth:
0
,
leading:
const
SizedBox
.
shrink
(),
title:
const
Text
(
'Verify Phone Number'
),
actions:
[
if
(
controller
.
codeSent
)
TextButton
(
onPressed:
controller
.
isOtpExpired
?
()
async
{
log
(
VerifyPhoneNumberScreen
.
id
,
msg:
'Resend OTP'
);
await
controller
.
sendOTP
();
}
:
null
,
child:
Text
(
controller
.
isOtpExpired
?
'Resend'
:
'
${controller.otpExpirationTimeLeft.inSeconds}
s'
,
style:
const
TextStyle
(
color:
Colors
.
blue
,
fontSize:
18
),
),
),
const
SizedBox
(
width:
5
),
],
),
body:
controller
.
isSendingCode
?
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
const
[
CustomLoader
(),
SizedBox
(
height:
50
),
Center
(
child:
Text
(
'Sending OTP'
,
style:
TextStyle
(
fontSize:
25
),
),
),
],
)
:
ListView
(
padding:
const
EdgeInsets
.
all
(
20
),
controller:
scrollController
,
children:
[
Text
(
"We've sent an SMS with a verification code to
${widget.phoneNumber}
"
,
style:
const
TextStyle
(
fontSize:
25
),
),
const
SizedBox
(
height:
10
),
const
Divider
(),
if
(
controller
.
isListeningForOtpAutoRetrieve
)
Column
(
children:
const
[
CustomLoader
(),
SizedBox
(
height:
50
),
Text
(
'Listening for OTP'
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
fontSize:
25
,
fontWeight:
FontWeight
.
w600
,
),
),
SizedBox
(
height:
15
),
Divider
(),
Text
(
'OR'
,
textAlign:
TextAlign
.
center
),
Divider
(),
],
),
const
SizedBox
(
height:
15
),
const
Text
(
'Enter OTP'
,
style:
TextStyle
(
fontSize:
20
,
fontWeight:
FontWeight
.
w600
,
),
),
const
SizedBox
(
height:
15
),
PinInputField
(
length:
6
,
onFocusChange:
(
hasFocus
)
async
{
if
(
hasFocus
)
await
_scrollToBottomOnKeyboardOpen
();
},
onSubmit:
(
enteredOtp
)
async
{
final
verified
=
await
controller
.
verifyOtp
(
enteredOtp
);
if
(
verified
)
{
// number verify success
// will call onLoginSuccess handler
}
else
{
// phone verification failed
// will call onLoginFailed or onError callbacks with the error
}
},
),
],
),
);
},
),
);
}
}
lib/pages/user/user_page.dart
View file @
8fcf01e0
import
'package:flutter/material.dart'
;
import
'package:babstrap_settings_screen/babstrap_settings_screen.dart'
;
import
'package:provider/provider.dart'
;
import
'../../models/user_model.dart'
;
class
UserPage
extends
StatefulWidget
{
@override
...
...
@@ -20,92 +23,122 @@ class UserPageState extends State<UserPage> {
@override
Widget
build
(
BuildContext
context
)
{
UserModel
_userModel
=
Provider
.
of
<
UserModel
>(
context
);
// TODO: implement build
return
Padding
(
padding:
const
EdgeInsets
.
all
(
10
),
child:
ListView
(
children:
[
// User card
BigUserCard
(
// cardColor: Colors.red,
userName:
"Babacar Ndong"
,
userProfilePic:
AssetImage
(
"assets/images/logo.png"
),
cardActionWidget:
SettingsItem
(
icons:
Icons
.
edit
,
iconStyle:
IconStyle
(
withBackground:
true
,
borderRadius:
50
,
backgroundColor:
Colors
.
yellow
[
600
],
),
title:
"Modify"
,
subtitle:
"Tap to change your data"
,
onTap:
()
{
print
(
"OK"
);
},
),
),
SettingsGroup
(
items:
[
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
exit_to_app_rounded
,
iconStyle:
IconStyle
(),
title:
'Appearance'
,
subtitle:
"Make Ziar'App yours"
,
),
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
dark_mode_rounded
,
print
(
"
${_userModel.isLogin}
"
);
// appBar: AppBar(
// title: Text("GPT大师傅"),
// backgroundColor: Color.fromRGBO(41, 45, 62, 1.00),
// ),
// // SailAppBar(
// // appTitle: _appTitle,
// // // rgba(41, 45, 62, 1.00)
// // backgroundColor: Color.fromRGBO(41, 45, 62, 1.00),
// // textColor: Colors.white
// // //rgba(41, 45, 62, 1.00)
// // ),
// // extendBody: true,
// // backgroundColor: Colors.amber,
// // _appModel.isOn ? AppColors.yellowColor : AppColors.grayColor,
// body: Container(
// decoration: BoxDecoration(
// image: DecorationImage(
// image: Image.asset("assets/images/bg.png").image,
// fit: BoxFit.cover),
// ),
return
Container
(
decoration:
BoxDecoration
(
image:
DecorationImage
(
image:
Image
.
asset
(
"assets/images/bg.png"
).
image
,
fit:
BoxFit
.
cover
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
10
),
child:
ListView
(
children:
[
// User card
BigUserCard
(
// cardColor: Colors.red,
userName:
"Babacar Ndong"
,
userProfilePic:
AssetImage
(
"assets/images/logo.png"
),
cardActionWidget:
SettingsItem
(
icons:
Icons
.
edit
,
iconStyle:
IconStyle
(
iconsColor:
Colors
.
white
,
withBackground:
true
,
backgroundColor:
Colors
.
red
,
),
title:
'Dark mode'
,
subtitle:
"Automatic"
,
trailing:
Switch
.
adaptive
(
value:
false
,
onChanged:
(
value
)
{},
),
),
],
),
SettingsGroup
(
items:
[
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
info_rounded
,
iconStyle:
IconStyle
(
backgroundColor:
Colors
.
purple
,
borderRadius:
50
,
backgroundColor:
Colors
.
yellow
[
600
],
),
title:
'About'
,
subtitle:
"Learn more about Ziar'App"
,
),
],
),
// You can add a settings title
SettingsGroup
(
settingsGroupTitle:
"Account"
,
items:
[
SettingsItem
(
title:
"Modify"
,
subtitle:
"Tap to change your data"
,
onTap:
()
{
Navigator
.
of
(
context
).
pushNamed
(
'/login'
);
print
(
"OK"
);
},
icons:
Icons
.
exit_to_app_rounded
,
title:
"Sign Out"
,
),
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
exit_to_app_rounded
,
title:
"Delete account"
,
titleStyle:
TextStyle
(
color:
Colors
.
red
,
fontWeight:
FontWeight
.
bold
,
),
SettingsGroup
(
items:
[
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
exit_to_app_rounded
,
iconStyle:
IconStyle
(),
title:
'Appearance'
,
subtitle:
"Make Ziar'App yours"
,
),
),
],
),
],
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
dark_mode_rounded
,
iconStyle:
IconStyle
(
iconsColor:
Colors
.
white
,
withBackground:
true
,
backgroundColor:
Colors
.
red
,
),
title:
'Dark mode'
,
subtitle:
"Automatic"
,
trailing:
Switch
.
adaptive
(
value:
false
,
onChanged:
(
value
)
{},
),
),
],
),
SettingsGroup
(
items:
[
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
info_rounded
,
iconStyle:
IconStyle
(
backgroundColor:
Colors
.
purple
,
),
title:
'About'
,
subtitle:
"Learn more about Ziar'App"
,
),
],
),
// You can add a settings title
SettingsGroup
(
items:
[
SettingsItem
(
onTap:
()
{
Navigator
.
of
(
context
).
pushNamed
(
'/ms-code'
);
},
icons:
Icons
.
exit_to_app_rounded
,
title:
"Sign Out"
,
),
SettingsItem
(
onTap:
()
{},
icons:
Icons
.
exit_to_app_rounded
,
title:
"Delete account"
,
titleStyle:
TextStyle
(
color:
Colors
.
red
,
fontWeight:
FontWeight
.
bold
,
),
),
],
),
],
),
),
);
}
...
...
lib/router/router_handlers.dart
View file @
8fcf01e0
...
...
@@ -5,6 +5,7 @@ import 'package:chart/pages/home/home_page.dart';
import
'package:chart/pages/login/login_page.dart'
;
import
'package:chart/pages/chat/chat_page.dart'
;
import
'package:chart/pages/goods/goods_page.dart'
;
import
'package:chart/pages/login/msm_page.dart'
;
// import 'package:/chart/pages/goods/goods_page.dart';
// import 'package:sail/pages/plan/plan_page.dart';
// import 'package:sail/pages/server_list.dart';
...
...
@@ -18,6 +19,11 @@ import 'package:chart/pages/goods/goods_page.dart';
// return const MainPage();
// });
Handler
msgCodeHandler
=
Handler
(
handlerFunc:
(
BuildContext
?
context
,
Map
<
String
,
List
<
String
>>
parameters
)
{
return
const
MsmPage
();
});
/// 登录页
Handler
loginHandler
=
Handler
(
handlerFunc:
(
BuildContext
?
context
,
Map
<
String
,
List
<
String
>>
parameters
)
{
...
...
lib/router/routers.dart
View file @
8fcf01e0
...
...
@@ -10,6 +10,7 @@ class Routers {
static
String
webView
=
"/web-view"
;
static
String
chat
=
"/chat"
;
static
String
goods
=
"/goods"
;
static
String
msgCode
=
"/ms-code"
;
static
void
configureRoutes
(
FluroRouter
router
)
{
// router.notFoundHandler = notFindHandler;
...
...
@@ -21,6 +22,8 @@ class Routers {
router
.
define
(
chat
,
handler:
chatHandle
);
router
.
define
(
goods
,
handler:
goodsHandler
);
router
.
define
(
msgCode
,
handler:
msgCodeHandler
);
// router.define(serverList, handler: serverListHandler);
// router.define(webView, handler: webViewHandler);
...
...
lib/service/user_service.dart
View file @
8fcf01e0
...
...
@@ -54,7 +54,26 @@ class UserService {
return
ApplePayEntity
.
fromMap
(
result
[
'data'
]);
});
}
Future
<
MsmEntity
>?
sendSms
(
Map
<
String
,
dynamic
>
parameters
)
{
return
HttpUtil
.
instance
?.
get
(
AppUrls
.
sendSms
,
parameters:
parameters
)
.
then
((
result
)
{
return
MsmEntity
.
fromMap
(
result
);
});
}
Future
<
LoginEntity
>?
register
(
Map
<
String
,
dynamic
>
parameters
)
{
return
HttpUtil
.
instance
?.
post
(
AppUrls
.
register
,
parameters:
parameters
)
.
then
((
result
)
{
return
LoginEntity
.
fromMap
(
result
[
'data'
]);
});
}
}
// getGoodsList
\ No newline at end of file
// getGoodsList
lib/utils/http_util.dart
View file @
8fcf01e0
...
...
@@ -28,13 +28,15 @@ class HttpUtil {
print
(
"url=
${options.uri.toString()}
"
);
print
(
"headers=
${options.headers}
"
);
print
(
"params=
${options.data}
"
);
// options.headers["appVersionName"]="V 4.0.6";
//如果token存在在请求参数加上token
await
SharedPreferencesUtil
.
getInstance
()
?.
getString
(
AppStrings
.
token
)
.
then
((
token
)
{
if
(
token
!=
null
)
{
options
.
queryParameters
[
AppStrings
.
token
]
=
token
;
options
.
headers
[
'Authorization'
]
=
token
;
// ["Authorization"] = token;
print
(
"token=
$token
"
);
}
});
...
...
pubspec.lock
View file @
8fcf01e0
...
...
@@ -106,6 +106,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.4"
contact_picker_platform_interface:
dependency: transitive
description:
name: contact_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.7.0"
contact_picker_web:
dependency: transitive
description:
name: contact_picker_web
url: "https://pub.dartlang.org"
source: hosted
version: "4.7.0"
crisp:
dependency: "direct main"
description:
...
...
@@ -183,6 +197,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
extended_phone_number_input:
dependency: "direct main"
description:
name: extended_phone_number_input
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
fake_async:
dependency: transitive
description:
...
...
@@ -427,6 +448,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
fluttercontactpicker:
dependency: transitive
description:
name: fluttercontactpicker
url: "https://pub.dartlang.org"
source: hosted
version: "4.7.0"
fluttertoast:
dependency: "direct main"
description:
...
...
@@ -665,6 +693,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
phone_number_metadata:
dependency: transitive
description:
name: phone_number_metadata
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.2"
phone_numbers_parser:
dependency: transitive
description:
name: phone_numbers_parser
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.1"
photo_view:
dependency: transitive
description:
...
...
pubspec.yaml
View file @
8fcf01e0
...
...
@@ -92,6 +92,7 @@ dependencies:
firebase_phone_auth_handler
:
^1.0.8
easy_container
:
^1.0.4
intl_phone_field
:
^3.1.0
extended_phone_number_input
:
^1.0.2
# package:bubble/bubble.dart
dev_dependencies
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment