add pin login and add pin code

This commit is contained in:
tzw
2024-10-04 13:55:59 +06:30
parent b5023a4171
commit 81dfeb037d
18 changed files with 340 additions and 68 deletions

View File

@@ -203,9 +203,27 @@ class _HomePageState extends State<HomePage> {
super.dispose();
}
_logoutPinAccount() async {
setState(() {
_isLoading = true;
});
try {
await context.read<MainModel>().logoutPinAccount();
Navigator.pushNamedAndRemoveUntil(context, "/pin_login", (r) => false);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
User? user = Provider.of<MainModel>(context).user;
var mainModel = context.watch<MainModel>();
User? user = mainModel.user;
if (user == null) {
Future.microtask(
@@ -213,7 +231,7 @@ class _HomePageState extends State<HomePage> {
return Container();
}
login = Provider.of<MainModel>(context).isLogin();
login = mainModel.isLogin();
LanguageModel languageModel = Provider.of<LanguageModel>(context);
final faqBtn = TaskButton("faq.btn",
@@ -357,7 +375,7 @@ class _HomePageState extends State<HomePage> {
selectedColor: Colors.white,
color: Colors.blue,
children: <Widget>[
Icon(MaterialCommunityIcons.account_tie,size: 25),
Icon(MaterialCommunityIcons.account_tie, size: 25),
],
onPressed: (i) => this.setState(() {
isFcs[0] = !isFcs[0];
@@ -387,11 +405,14 @@ class _HomePageState extends State<HomePage> {
color: buttonColor,
),
);
final pinLoginBtn = IconButton(
onPressed: () {
Navigator.of(context)
.push(CupertinoPageRoute(builder: (context) => PinLoginPage()));
Navigator.pushAndRemoveUntil(
context,
CupertinoPageRoute(
builder: (BuildContext context) => PinLoginPage()),
(r) => false);
},
iconSize: 25,
icon: Icon(
@@ -400,6 +421,19 @@ class _HomePageState extends State<HomePage> {
),
);
final pinLogoutBtn = IconButton(
onPressed: () {
showConfirmDialog(context, "home.pin.logout.confirm", () async {
await _logoutPinAccount();
});
},
iconSize: 25,
icon: Icon(
MaterialCommunityIcons.lock_open_variant_outline,
color: buttonColor,
),
);
var searchInput = Row(children: [
Expanded(
child: Padding(
@@ -478,7 +512,7 @@ class _HomePageState extends State<HomePage> {
profileBtn,
]
: <Widget>[
pinLoginBtn,
mainModel.isPinLogin ? pinLogoutBtn : pinLoginBtn,
fcsToggle,
profileBtn,
]

View File

@@ -17,6 +17,7 @@ class MainModel extends ChangeNotifier {
String? messagingToken;
User? user;
User? _fbUser;
PackageInfo? packageInfo;
set setMessaginToken(token) {
@@ -29,6 +30,9 @@ class MainModel extends ChangeNotifier {
bool isLoaded = false;
bool isOnline = false;
bool isFirstLaunch = false;
bool isLockOn = false;
bool get isPinLogin => user?.isPinLogin ?? false;
MainModel() {
NetworkConnectivity.instance.statusStream.listen((data) {
@@ -83,6 +87,7 @@ class MainModel extends ChangeNotifier {
await _listenSetting();
this.isFirstLaunch = await SharedPref.isFirstLaunch() ?? true;
this.packageInfo = await PackageInfo.fromPlatform();
this.isLockOn = await SharedPref.getPinLockOn() ?? false;
userListener?.cancel();
userListener =
@@ -91,6 +96,17 @@ class MainModel extends ChangeNotifier {
bool diffPrivilege =
_user != null && (user == null || user!.diffPrivileges(_user));
bool loggingOut = user != null && _user == null;
if (_user != null) {
if (!_user.isPinLogin) {
_fbUser = _user;
}
}
if ((_fbUser?.id == _user?.id)) {
_user?.pinToken = null;
}
user = _user;
if (_user != null) {
@@ -101,6 +117,7 @@ class MainModel extends ChangeNotifier {
}
}
}
if (loggingOut) {
for (final m in models) {
m.logout();
@@ -196,4 +213,13 @@ class MainModel extends ChangeNotifier {
Future<void> deleteAccount() async {
return await Services.instance.authService.deleteAccount();
}
Future<void> pinLogin({required String fcsID, required String pin}) async {
await Services.instance.authService
.pinLogin(fcsID: fcsID, pin: pin, currentUserId: _fbUser?.id ?? '');
}
Future<void> logoutPinAccount() async {
await Services.instance.authService.logoutPinAccount();
}
}

View File

@@ -53,7 +53,11 @@ class _SplashScreenState extends State<SplashScreen> {
if (mainModel.isFirstLaunch) {
page = "/language_selection";
} else if (mainModel.isLogin()) {
page = "/home";
if (mainModel.isLockOn) {
page = "/pin_login";
} else {
page = "/home";
}
} else {
page = "/welcome";
}

View File

@@ -129,12 +129,17 @@ class _ProfileState extends State<Profile> {
],
);
final logoutbutton = fcsButton(
context, getLocalString(context, "profile.logout"), callack: () {
showConfirmDialog(context, "profile.logout.confirm", () async {
await _logout();
});
}, iconData: Icons.exit_to_app);
final logoutbutton =
fcsButton(context, getLocalString(context, "profile.logout"),
callack: mainModel.isPinLogin
? null
: () {
showConfirmDialog(context, "profile.logout.confirm",
() async {
await _logout();
});
},
iconData: Icons.exit_to_app);
return LocalProgress(
inAsyncCall: _isLoading,
@@ -355,8 +360,12 @@ class _ProfileState extends State<Profile> {
}
_showToast(String title) {
final ScaffoldMessengerState scaffold =
key.currentState as ScaffoldMessengerState;
ScaffoldMessengerState? scaffold = key.currentState;
if (scaffold == null) {
scaffold = ScaffoldMessenger.of(context);
}
scaffold.showSnackBar(
SnackBar(
content: Text('copied "$title" data to clipboard'),

View File

@@ -1,13 +1,18 @@
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/main/model/language_model.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/local_button.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/material.dart';
import 'package:pin_input_text_field/pin_input_text_field.dart';
import 'package:provider/provider.dart';
import '../../helpers/shared_pref.dart';
import '../../localization/app_translations.dart';
class PinLoginPage extends StatefulWidget {
//final User user;
const PinLoginPage({super.key});
@override
@@ -18,10 +23,77 @@ class _PinLoginPageState extends State<PinLoginPage> {
bool _isLoading = false;
String pin = "";
String prefixText = "FCS-";
//late User _user;
final _formKey = GlobalKey<FormState>();
TextEditingController _fcsIdCtl = new TextEditingController();
@override
void initState() {
_init();
super.initState();
}
_init() async {
await SharedPref.setPinLockOn(true);
}
Future<bool> _onWillPop() async {
// Show the confirmation dialog
return (await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Center(
child:
LocalText(context, 'btn.exit_confirm', color: primaryColor),
),
content: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.grey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0))),
child: Text(
AppTranslations.of(context)!.text('btn.cancel'),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(color: primaryColor)
: TextStyle(
fontFamily: 'Myanmar3', color: primaryColor),
),
onPressed: () {
Navigator.of(context).pop(false);
}),
SizedBox(
width: 0,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0))),
child: Text(AppTranslations.of(context)!.text('btn.ok'),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold)
: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'Myanmar3')),
onPressed: () {
Navigator.of(context).pop(true);
})
],
),
),
),
)) ??
false;
}
Widget build(BuildContext context) {
final fcsIdBox = TextFormField(
controller: _fcsIdCtl,
@@ -48,7 +120,7 @@ class _PinLoginPageState extends State<PinLoginPage> {
prefixText,
style: TextStyle(color: Colors.black),
),
prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0),
prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0),
contentPadding: EdgeInsets.all(0),
labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17),
enabledBorder: UnderlineInputBorder(
@@ -121,42 +193,47 @@ class _PinLoginPageState extends State<PinLoginPage> {
callBack: _login,
),
);
return LocalProgress(
inAsyncCall: _isLoading,
child: new Scaffold(
body: Form(
key: _formKey,
child: ListView(
padding: EdgeInsets.only(top: 80, left: 15, right: 15, bottom: 20),
children: [
pinLoginLogo,
Padding(
padding: EdgeInsets.only(top: 20, bottom: 20),
child: Center(
child: LocalText(context, "welcome.pinlogin",
color: Colors.black, fontSize: 18),
// ignore: deprecated_member_use
return WillPopScope(
onWillPop: _onWillPop,
child: LocalProgress(
inAsyncCall: _isLoading,
child: new Scaffold(
body: Form(
key: _formKey,
child: ListView(
padding: EdgeInsets.only(top: 80, left: 15, right: 15, bottom: 20),
children: [
pinLoginLogo,
Padding(
padding: EdgeInsets.only(top: 20, bottom: 20),
child: Center(
child: LocalText(context, "welcome.pinlogin",
color: Colors.black, fontSize: 18),
),
),
),
LocalText(
context,
"welcome.pinlogin.fcsid",
color: Colors.black54,
fontSize: 15,
),
fcsIdBox,
Padding(
padding: EdgeInsets.only(top: 25, bottom: 20),
child: LocalText(
context,
"welcome.pinlogin.pin",
color: Colors.black54,
fontSize: 15,
)),
pinInputBox,
loginBtn,
],
),
)),
LocalText(
context,
"welcome.pinlogin.fcsid",
color: Colors.black54,
fontSize: 15,
),
fcsIdBox,
Padding(
padding: EdgeInsets.only(top: 25, bottom: 20),
child: LocalText(
context,
"welcome.pinlogin.pin",
color: Colors.black54,
fontSize: 15,
)),
pinInputBox,
loginBtn,
],
),
)),
),
);
}
@@ -171,14 +248,14 @@ class _PinLoginPageState extends State<PinLoginPage> {
return;
}
String fcsId = "$prefixText${_fcsIdCtl.text}";
print(fcsId);
setState(() {
_isLoading = true;
});
try {
Navigator.pop(context, true);
await context.read<MainModel>().pinLogin(fcsID: fcsId, pin: pin);
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {

View File

@@ -81,7 +81,7 @@ class StaffModel extends BaseModel {
Future<void> updatePin(
{required String userID,
required bool enablePin,
required int? pin}) async {
required String? pin}) async {
await request("/employee/pin", "PUT",
payload: {"id": userID, "enable_pin_login": enablePin, "pin": pin},
token: await getToken());

View File

@@ -310,7 +310,7 @@ class _StaffPinEditorState extends State<StaffPinEditor> {
await context.read<StaffModel>().updatePin(
userID: _staff.id!,
enablePin: _enablePinLogin,
pin: _enablePinLogin ? int.parse(_confirmPin) : null);
pin: _enablePinLogin ? _confirmPin : null);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());