add pin login and add pin code
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"back.button_confirm":"Are you sure you want to continue without submitting changes?",
|
"back.button_confirm":"Are you sure you want to continue without submitting changes?",
|
||||||
"btn.clear":"Clear Filter",
|
"btn.clear":"Clear Filter",
|
||||||
"btn.filter":"Filter",
|
"btn.filter":"Filter",
|
||||||
|
"btn.exit_confirm":"Are you sure you want to exit?",
|
||||||
"Buttons End ================================================================":"",
|
"Buttons End ================================================================":"",
|
||||||
|
|
||||||
"Offline Start ================================================================":"",
|
"Offline Start ================================================================":"",
|
||||||
@@ -104,6 +105,7 @@
|
|||||||
"home.invitation.request.msg":"We are working on your invitation request!",
|
"home.invitation.request.msg":"We are working on your invitation request!",
|
||||||
"home.search":"Enter tracking number",
|
"home.search":"Enter tracking number",
|
||||||
"home.search.btn":"Search",
|
"home.search.btn":"Search",
|
||||||
|
"home.pin.logout.confirm":"Are you sure want to logout?",
|
||||||
"Home End ================================================================":"",
|
"Home End ================================================================":"",
|
||||||
|
|
||||||
"Invite Start ================================================================":"",
|
"Invite Start ================================================================":"",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"back.button_confirm":"Are you sure you want to continue without submitting changes?",
|
"back.button_confirm":"Are you sure you want to continue without submitting changes?",
|
||||||
"btn.clear":"Clear Filter",
|
"btn.clear":"Clear Filter",
|
||||||
"btn.filter":"Filter",
|
"btn.filter":"Filter",
|
||||||
|
"btn.exit_confirm":"Are you sure you want to exit?",
|
||||||
"Buttons End ================================================================":"",
|
"Buttons End ================================================================":"",
|
||||||
|
|
||||||
"Offline Start ================================================================":"",
|
"Offline Start ================================================================":"",
|
||||||
@@ -104,6 +105,7 @@
|
|||||||
"home.invitation.request.msg":"ဖိတ်ကြားမှု တောင်းဆိုသည်ကို လုပ်ဆောင်နေပါသည်!",
|
"home.invitation.request.msg":"ဖိတ်ကြားမှု တောင်းဆိုသည်ကို လုပ်ဆောင်နေပါသည်!",
|
||||||
"home.search":"Tracking number ရိုက်ထည့်ပါ",
|
"home.search":"Tracking number ရိုက်ထည့်ပါ",
|
||||||
"home.search.btn":"ရှာမည်",
|
"home.search.btn":"ရှာမည်",
|
||||||
|
"home.pin.logout.confirm":"အကောင့်ထွက်ရန်သေချာပြီလား?",
|
||||||
"Home End ================================================================":"",
|
"Home End ================================================================":"",
|
||||||
|
|
||||||
"Invite Start ================================================================":"",
|
"Invite Start ================================================================":"",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import 'pages/carton/model/package_selection_model.dart';
|
|||||||
import 'pages/carton/model/sender_selection_model.dart';
|
import 'pages/carton/model/sender_selection_model.dart';
|
||||||
import 'pages/carton/model/shipment_selection_model.dart';
|
import 'pages/carton/model/shipment_selection_model.dart';
|
||||||
import 'pages/delivery/model/delivery_model.dart';
|
import 'pages/delivery/model/delivery_model.dart';
|
||||||
|
import 'pages/signin/pinlogin_page.dart';
|
||||||
|
|
||||||
class App extends StatefulWidget {
|
class App extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
@@ -121,6 +122,7 @@ class _AppState extends State<App> {
|
|||||||
'/welcome': (_) => WelcomePage(),
|
'/welcome': (_) => WelcomePage(),
|
||||||
'/home': (_) => HomePage(),
|
'/home': (_) => HomePage(),
|
||||||
'/language_selection': (context) => InitialLanguageSelectionPage(),
|
'/language_selection': (context) => InitialLanguageSelectionPage(),
|
||||||
|
'/pin_login': (_) => PinLoginPage()
|
||||||
};
|
};
|
||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ const privilege_receiving = "rc";
|
|||||||
const privilege_pickup = "pku";
|
const privilege_pickup = "pku";
|
||||||
const privilege_collect = "col";
|
const privilege_collect = "col";
|
||||||
const privilege_report = "rpt";
|
const privilege_report = "rpt";
|
||||||
|
const privilege_pin ="pin";
|
||||||
|
|
||||||
// Pickup types
|
// Pickup types
|
||||||
const shipment_local_pickup = "Local pickup";
|
const shipment_local_pickup = "Local pickup";
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:fcs/helpers/firebase_helper.dart';
|
|||||||
import 'package:firebase_auth/firebase_auth.dart' as fb;
|
import 'package:firebase_auth/firebase_auth.dart' as fb;
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
import '../../helpers/shared_pref.dart';
|
||||||
import '../services/services.dart';
|
import '../services/services.dart';
|
||||||
|
|
||||||
class AuthFb {
|
class AuthFb {
|
||||||
@@ -108,13 +109,15 @@ class AuthFb {
|
|||||||
Future<void> signoutStart() async {
|
Future<void> signoutStart() async {
|
||||||
await userListener?.cancel();
|
await userListener?.cancel();
|
||||||
await userAuthListener?.cancel();
|
await userAuthListener?.cancel();
|
||||||
|
await _pinUserListener?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> signoutEnd() async {
|
Future<void> signoutEnd() async {
|
||||||
|
await SharedPref.setPinLockOn(false);
|
||||||
await _fb.signOut();
|
await _fb.signOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addUserToStream({bool refreshIdToken = false}) async {
|
Future<User?> _addUserToStream({bool refreshIdToken = false}) async {
|
||||||
fb.User? firebaseUser = _fb.currentUser;
|
fb.User? firebaseUser = _fb.currentUser;
|
||||||
if (firebaseUser == null) return null;
|
if (firebaseUser == null) return null;
|
||||||
Map<dynamic, dynamic>? claims =
|
Map<dynamic, dynamic>? claims =
|
||||||
@@ -128,15 +131,20 @@ class AuthFb {
|
|||||||
user = await _getUserFromFirestore(cid);
|
user = await _getUserFromFirestore(cid);
|
||||||
}
|
}
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
controller.add(null);
|
_addUser(null);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUserClaim(claims, user);
|
loadUserClaim(claims, user);
|
||||||
controller.add(user);
|
_addUser(user);
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUserClaim(Map claims, User user) {
|
loadUserClaim(Map claims, User user) {
|
||||||
|
if (pinLoginUser != null) {
|
||||||
|
user.fcsID = pinLoginUser?.fcsID;
|
||||||
|
}
|
||||||
|
|
||||||
// add privileges
|
// add privileges
|
||||||
String? privileges = claims["pr"];
|
String? privileges = claims["pr"];
|
||||||
if (privileges != null && privileges != "") {
|
if (privileges != null && privileges != "") {
|
||||||
@@ -252,9 +260,9 @@ class AuthFb {
|
|||||||
// get privilege from claim
|
// get privilege from claim
|
||||||
Map<dynamic, dynamic> claims = await getClaims(refreshIdToken: true);
|
Map<dynamic, dynamic> claims = await getClaims(refreshIdToken: true);
|
||||||
loadUserClaim(claims, user);
|
loadUserClaim(claims, user);
|
||||||
controller.add(user);
|
_addUser(user);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
controller.add(null);
|
_addUser(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -286,12 +294,23 @@ class AuthFb {
|
|||||||
|
|
||||||
log.info("_startAuthListener: $user");
|
log.info("_startAuthListener: $user");
|
||||||
if (_logIn) {
|
if (_logIn) {
|
||||||
controller.add(user);
|
_addUser(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_addUser(User? user) {
|
||||||
|
if (user == null) {
|
||||||
|
pinLoginUser = null;
|
||||||
|
}
|
||||||
|
if (pinLoginUser != null) {
|
||||||
|
controller.add(pinLoginUser);
|
||||||
|
} else {
|
||||||
|
controller.add(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Stream<User?> user() {
|
Stream<User?> user() {
|
||||||
// ignore: close_sinks
|
// ignore: close_sinks
|
||||||
StreamSubscription<fb.User?>? authListener;
|
StreamSubscription<fb.User?>? authListener;
|
||||||
@@ -301,7 +320,7 @@ class AuthFb {
|
|||||||
authListener = _fb.authStateChanges().listen((firebaseUser) async {
|
authListener = _fb.authStateChanges().listen((firebaseUser) async {
|
||||||
_logIn = firebaseUser != null;
|
_logIn = firebaseUser != null;
|
||||||
if (firebaseUser == null) {
|
if (firebaseUser == null) {
|
||||||
controller.add(null);
|
_addUser(null);
|
||||||
} else {
|
} else {
|
||||||
_addUserToStream(refreshIdToken: true);
|
_addUserToStream(refreshIdToken: true);
|
||||||
_startUserListener();
|
_startUserListener();
|
||||||
@@ -319,4 +338,51 @@ class AuthFb {
|
|||||||
|
|
||||||
return controller.stream;
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
User? pinLoginUser;
|
||||||
|
|
||||||
|
StreamSubscription<DocumentSnapshot>? _pinUserListener;
|
||||||
|
|
||||||
|
Future<void> pinLogin(
|
||||||
|
{required String currentUserId,
|
||||||
|
required String fcsID,
|
||||||
|
required String pin}) async {
|
||||||
|
var data = await requestAPI("/pin/login", "POST",
|
||||||
|
token: await getToken(), payload: {'fcs_id': fcsID, 'pin': pin});
|
||||||
|
|
||||||
|
var userId = data['user_id'] ?? '';
|
||||||
|
if (userId == currentUserId) {
|
||||||
|
//logout
|
||||||
|
logoutPinAccount();
|
||||||
|
await SharedPref.setPinLockOn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pinToken = data['pin_token'] ?? '';
|
||||||
|
|
||||||
|
// Get user for pin login
|
||||||
|
_listenPinUser(userId: userId, pinToken: pinToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _listenPinUser(
|
||||||
|
{required String userId, required String pinToken}) async {
|
||||||
|
Stream<DocumentSnapshot> snapshot = FirebaseFirestore.instance
|
||||||
|
.collection(user_collection)
|
||||||
|
.doc(userId)
|
||||||
|
.snapshots();
|
||||||
|
_pinUserListener?.cancel();
|
||||||
|
_pinUserListener = snapshot.listen((snap) async {
|
||||||
|
User user = User.fromMap(snap.data() as Map<String, dynamic>, snap.id);
|
||||||
|
pinLoginUser = user;
|
||||||
|
if (pinLoginUser != null) {
|
||||||
|
pinLoginUser!.pinToken = pinToken;
|
||||||
|
}
|
||||||
|
await _addUserToStream(refreshIdToken: true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> logoutPinAccount() async {
|
||||||
|
_pinUserListener?.cancel();
|
||||||
|
pinLoginUser = null;
|
||||||
|
await _addUserToStream(refreshIdToken: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,4 +74,23 @@ class AuthServiceImp implements AuthService {
|
|||||||
Future<void> deleteAccount() {
|
Future<void> deleteAccount() {
|
||||||
return authFb.deleteAccount();
|
return authFb.deleteAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> pinLogin(
|
||||||
|
{required String currentUserId,
|
||||||
|
required String fcsID,
|
||||||
|
required String pin}) {
|
||||||
|
return authFb.pinLogin(
|
||||||
|
currentUserId: currentUserId, fcsID: fcsID, pin: pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
User? getPinLoginUser() {
|
||||||
|
return authFb.pinLoginUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> logoutPinAccount() {
|
||||||
|
return authFb.logoutPinAccount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,4 +15,10 @@ abstract class AuthService {
|
|||||||
Stream<User?> getUserStream();
|
Stream<User?> getUserStream();
|
||||||
Stream<Setting> getSetting();
|
Stream<Setting> getSetting();
|
||||||
Future<void> deleteAccount();
|
Future<void> deleteAccount();
|
||||||
|
Future<void> pinLogin(
|
||||||
|
{required String currentUserId,
|
||||||
|
required String fcsID,
|
||||||
|
required String pin});
|
||||||
|
User? getPinLoginUser();
|
||||||
|
Future<void> logoutPinAccount();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class User {
|
|||||||
String? preferCurrency;
|
String? preferCurrency;
|
||||||
bool enablePinLogin;
|
bool enablePinLogin;
|
||||||
String? pinDigit;
|
String? pinDigit;
|
||||||
|
List<String> privileges = [];
|
||||||
|
|
||||||
String get initial =>
|
String get initial =>
|
||||||
name != null && name != "" ? name!.substring(0, 1) : "?";
|
name != null && name != "" ? name!.substring(0, 1) : "?";
|
||||||
@@ -48,7 +49,9 @@ class User {
|
|||||||
String get getFcsUnseenCount =>
|
String get getFcsUnseenCount =>
|
||||||
fcsUnseenCount > 100 ? "99+" : fcsUnseenCount.toString();
|
fcsUnseenCount > 100 ? "99+" : fcsUnseenCount.toString();
|
||||||
|
|
||||||
List<String> privileges = [];
|
// for pin login
|
||||||
|
String? pinToken;
|
||||||
|
bool get isPinLogin => pinToken!=null;
|
||||||
|
|
||||||
String get phone => phoneNumber != null && phoneNumber!.startsWith("959")
|
String get phone => phoneNumber != null && phoneNumber!.startsWith("959")
|
||||||
? "0${phoneNumber!.substring(2)}"
|
? "0${phoneNumber!.substring(2)}"
|
||||||
@@ -117,7 +120,9 @@ class User {
|
|||||||
userUnseenCount: map['user_unseen_count'] ?? 0,
|
userUnseenCount: map['user_unseen_count'] ?? 0,
|
||||||
fcsUnseenCount: map['fcs_unseen_count'] ?? 0,
|
fcsUnseenCount: map['fcs_unseen_count'] ?? 0,
|
||||||
preferCurrency: map['preferred_currency'],
|
preferCurrency: map['preferred_currency'],
|
||||||
lastMessageTime: _date == null ? null : _date.toDate());
|
lastMessageTime: _date == null ? null : _date.toDate(),
|
||||||
|
enablePinLogin: map['enable_pin_login'] ?? false,
|
||||||
|
pinDigit: map['pin'] ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool diffPrivileges(User another) {
|
bool diffPrivileges(User another) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart';
|
import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:flutter_vector_icons/flutter_vector_icons.dart' as vector;
|
||||||
|
|
||||||
class Privilege {
|
class Privilege {
|
||||||
String id;
|
String id;
|
||||||
@@ -49,6 +50,8 @@ class Privilege {
|
|||||||
iconData = MaterialCommunityIcons.layers;
|
iconData = MaterialCommunityIcons.layers;
|
||||||
} else if (this.id == privilege_report) {
|
} else if (this.id == privilege_report) {
|
||||||
iconData = Feather.file_text;
|
iconData = Feather.file_text;
|
||||||
|
} else if (this.id == privilege_pin) {
|
||||||
|
iconData = vector.MaterialCommunityIcons.account_lock_outline;
|
||||||
} else {
|
} else {
|
||||||
iconData = MaterialCommunityIcons.account_question;
|
iconData = MaterialCommunityIcons.account_question;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:fcs/data/services/services.dart';
|
||||||
|
import 'package:fcs/domain/entities/user.dart';
|
||||||
import 'package:fcs/domain/vo/status.dart';
|
import 'package:fcs/domain/vo/status.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
@@ -28,6 +30,10 @@ Future<dynamic> requestAPI(String path, method,
|
|||||||
if (token != null) {
|
if (token != null) {
|
||||||
headers["Token"] = token;
|
headers["Token"] = token;
|
||||||
}
|
}
|
||||||
|
User? pinLoginUser = Services.instance.authService.getPinLoginUser();
|
||||||
|
if (pinLoginUser != null) {
|
||||||
|
headers["pin_token"] = pinLoginUser.pinToken;
|
||||||
|
}
|
||||||
if (devInfo.deviceID != null) {
|
if (devInfo.deviceID != null) {
|
||||||
headers["Device"] = devInfo.deviceID ?? "" + ":" + deviceName;
|
headers["Device"] = devInfo.deviceID ?? "" + ":" + deviceName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,4 +108,14 @@ class SharedPref {
|
|||||||
static Future<void> clearRecentSearch(String key) async {
|
static Future<void> clearRecentSearch(String key) async {
|
||||||
return await _remove(key);
|
return await _remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<bool?> getPinLockOn() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
return prefs.getBool('pin_lock');
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> setPinLockOn(bool isLockOn) async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
prefs.setBool('pin_lock', isLockOn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,9 +203,27 @@ class _HomePageState extends State<HomePage> {
|
|||||||
super.dispose();
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
User? user = Provider.of<MainModel>(context).user;
|
var mainModel = context.watch<MainModel>();
|
||||||
|
User? user = mainModel.user;
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
Future.microtask(
|
Future.microtask(
|
||||||
@@ -213,7 +231,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
login = Provider.of<MainModel>(context).isLogin();
|
login = mainModel.isLogin();
|
||||||
LanguageModel languageModel = Provider.of<LanguageModel>(context);
|
LanguageModel languageModel = Provider.of<LanguageModel>(context);
|
||||||
|
|
||||||
final faqBtn = TaskButton("faq.btn",
|
final faqBtn = TaskButton("faq.btn",
|
||||||
@@ -357,7 +375,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
selectedColor: Colors.white,
|
selectedColor: Colors.white,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Icon(MaterialCommunityIcons.account_tie,size: 25),
|
Icon(MaterialCommunityIcons.account_tie, size: 25),
|
||||||
],
|
],
|
||||||
onPressed: (i) => this.setState(() {
|
onPressed: (i) => this.setState(() {
|
||||||
isFcs[0] = !isFcs[0];
|
isFcs[0] = !isFcs[0];
|
||||||
@@ -390,8 +408,11 @@ class _HomePageState extends State<HomePage> {
|
|||||||
|
|
||||||
final pinLoginBtn = IconButton(
|
final pinLoginBtn = IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context)
|
Navigator.pushAndRemoveUntil(
|
||||||
.push(CupertinoPageRoute(builder: (context) => PinLoginPage()));
|
context,
|
||||||
|
CupertinoPageRoute(
|
||||||
|
builder: (BuildContext context) => PinLoginPage()),
|
||||||
|
(r) => false);
|
||||||
},
|
},
|
||||||
iconSize: 25,
|
iconSize: 25,
|
||||||
icon: Icon(
|
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: [
|
var searchInput = Row(children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -478,7 +512,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
profileBtn,
|
profileBtn,
|
||||||
]
|
]
|
||||||
: <Widget>[
|
: <Widget>[
|
||||||
pinLoginBtn,
|
mainModel.isPinLogin ? pinLogoutBtn : pinLoginBtn,
|
||||||
fcsToggle,
|
fcsToggle,
|
||||||
profileBtn,
|
profileBtn,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class MainModel extends ChangeNotifier {
|
|||||||
|
|
||||||
String? messagingToken;
|
String? messagingToken;
|
||||||
User? user;
|
User? user;
|
||||||
|
User? _fbUser;
|
||||||
PackageInfo? packageInfo;
|
PackageInfo? packageInfo;
|
||||||
|
|
||||||
set setMessaginToken(token) {
|
set setMessaginToken(token) {
|
||||||
@@ -29,6 +30,9 @@ class MainModel extends ChangeNotifier {
|
|||||||
bool isLoaded = false;
|
bool isLoaded = false;
|
||||||
bool isOnline = false;
|
bool isOnline = false;
|
||||||
bool isFirstLaunch = false;
|
bool isFirstLaunch = false;
|
||||||
|
bool isLockOn = false;
|
||||||
|
|
||||||
|
bool get isPinLogin => user?.isPinLogin ?? false;
|
||||||
|
|
||||||
MainModel() {
|
MainModel() {
|
||||||
NetworkConnectivity.instance.statusStream.listen((data) {
|
NetworkConnectivity.instance.statusStream.listen((data) {
|
||||||
@@ -83,6 +87,7 @@ class MainModel extends ChangeNotifier {
|
|||||||
await _listenSetting();
|
await _listenSetting();
|
||||||
this.isFirstLaunch = await SharedPref.isFirstLaunch() ?? true;
|
this.isFirstLaunch = await SharedPref.isFirstLaunch() ?? true;
|
||||||
this.packageInfo = await PackageInfo.fromPlatform();
|
this.packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
this.isLockOn = await SharedPref.getPinLockOn() ?? false;
|
||||||
|
|
||||||
userListener?.cancel();
|
userListener?.cancel();
|
||||||
userListener =
|
userListener =
|
||||||
@@ -91,6 +96,17 @@ class MainModel extends ChangeNotifier {
|
|||||||
bool diffPrivilege =
|
bool diffPrivilege =
|
||||||
_user != null && (user == null || user!.diffPrivileges(_user));
|
_user != null && (user == null || user!.diffPrivileges(_user));
|
||||||
bool loggingOut = user != null && _user == null;
|
bool loggingOut = user != null && _user == null;
|
||||||
|
|
||||||
|
if (_user != null) {
|
||||||
|
if (!_user.isPinLogin) {
|
||||||
|
_fbUser = _user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_fbUser?.id == _user?.id)) {
|
||||||
|
_user?.pinToken = null;
|
||||||
|
}
|
||||||
|
|
||||||
user = _user;
|
user = _user;
|
||||||
|
|
||||||
if (_user != null) {
|
if (_user != null) {
|
||||||
@@ -101,6 +117,7 @@ class MainModel extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loggingOut) {
|
if (loggingOut) {
|
||||||
for (final m in models) {
|
for (final m in models) {
|
||||||
m.logout();
|
m.logout();
|
||||||
@@ -196,4 +213,13 @@ class MainModel extends ChangeNotifier {
|
|||||||
Future<void> deleteAccount() async {
|
Future<void> deleteAccount() async {
|
||||||
return await Services.instance.authService.deleteAccount();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ class _SplashScreenState extends State<SplashScreen> {
|
|||||||
if (mainModel.isFirstLaunch) {
|
if (mainModel.isFirstLaunch) {
|
||||||
page = "/language_selection";
|
page = "/language_selection";
|
||||||
} else if (mainModel.isLogin()) {
|
} else if (mainModel.isLogin()) {
|
||||||
page = "/home";
|
if (mainModel.isLockOn) {
|
||||||
|
page = "/pin_login";
|
||||||
|
} else {
|
||||||
|
page = "/home";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
page = "/welcome";
|
page = "/welcome";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,12 +129,17 @@ class _ProfileState extends State<Profile> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final logoutbutton = fcsButton(
|
final logoutbutton =
|
||||||
context, getLocalString(context, "profile.logout"), callack: () {
|
fcsButton(context, getLocalString(context, "profile.logout"),
|
||||||
showConfirmDialog(context, "profile.logout.confirm", () async {
|
callack: mainModel.isPinLogin
|
||||||
await _logout();
|
? null
|
||||||
});
|
: () {
|
||||||
}, iconData: Icons.exit_to_app);
|
showConfirmDialog(context, "profile.logout.confirm",
|
||||||
|
() async {
|
||||||
|
await _logout();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
iconData: Icons.exit_to_app);
|
||||||
|
|
||||||
return LocalProgress(
|
return LocalProgress(
|
||||||
inAsyncCall: _isLoading,
|
inAsyncCall: _isLoading,
|
||||||
@@ -355,8 +360,12 @@ class _ProfileState extends State<Profile> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_showToast(String title) {
|
_showToast(String title) {
|
||||||
final ScaffoldMessengerState scaffold =
|
ScaffoldMessengerState? scaffold = key.currentState;
|
||||||
key.currentState as ScaffoldMessengerState;
|
|
||||||
|
if (scaffold == null) {
|
||||||
|
scaffold = ScaffoldMessenger.of(context);
|
||||||
|
}
|
||||||
|
|
||||||
scaffold.showSnackBar(
|
scaffold.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('copied "$title" data to clipboard'),
|
content: Text('copied "$title" data to clipboard'),
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import 'package:fcs/helpers/theme.dart';
|
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/main/util.dart';
|
||||||
import 'package:fcs/pages/widgets/local_button.dart';
|
import 'package:fcs/pages/widgets/local_button.dart';
|
||||||
import 'package:fcs/pages/widgets/local_text.dart';
|
import 'package:fcs/pages/widgets/local_text.dart';
|
||||||
import 'package:fcs/pages/widgets/progress.dart';
|
import 'package:fcs/pages/widgets/progress.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pin_input_text_field/pin_input_text_field.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 {
|
class PinLoginPage extends StatefulWidget {
|
||||||
//final User user;
|
|
||||||
const PinLoginPage({super.key});
|
const PinLoginPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -18,10 +23,77 @@ class _PinLoginPageState extends State<PinLoginPage> {
|
|||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
String pin = "";
|
String pin = "";
|
||||||
String prefixText = "FCS-";
|
String prefixText = "FCS-";
|
||||||
//late User _user;
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
TextEditingController _fcsIdCtl = new TextEditingController();
|
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) {
|
Widget build(BuildContext context) {
|
||||||
final fcsIdBox = TextFormField(
|
final fcsIdBox = TextFormField(
|
||||||
controller: _fcsIdCtl,
|
controller: _fcsIdCtl,
|
||||||
@@ -48,7 +120,7 @@ class _PinLoginPageState extends State<PinLoginPage> {
|
|||||||
prefixText,
|
prefixText,
|
||||||
style: TextStyle(color: Colors.black),
|
style: TextStyle(color: Colors.black),
|
||||||
),
|
),
|
||||||
prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0),
|
prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0),
|
||||||
contentPadding: EdgeInsets.all(0),
|
contentPadding: EdgeInsets.all(0),
|
||||||
labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17),
|
labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17),
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
@@ -121,42 +193,47 @@ class _PinLoginPageState extends State<PinLoginPage> {
|
|||||||
callBack: _login,
|
callBack: _login,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return LocalProgress(
|
|
||||||
inAsyncCall: _isLoading,
|
// ignore: deprecated_member_use
|
||||||
child: new Scaffold(
|
return WillPopScope(
|
||||||
body: Form(
|
onWillPop: _onWillPop,
|
||||||
key: _formKey,
|
child: LocalProgress(
|
||||||
child: ListView(
|
inAsyncCall: _isLoading,
|
||||||
padding: EdgeInsets.only(top: 80, left: 15, right: 15, bottom: 20),
|
child: new Scaffold(
|
||||||
children: [
|
body: Form(
|
||||||
pinLoginLogo,
|
key: _formKey,
|
||||||
Padding(
|
child: ListView(
|
||||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
padding: EdgeInsets.only(top: 80, left: 15, right: 15, bottom: 20),
|
||||||
child: Center(
|
children: [
|
||||||
child: LocalText(context, "welcome.pinlogin",
|
pinLoginLogo,
|
||||||
color: Colors.black, fontSize: 18),
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||||
|
child: Center(
|
||||||
|
child: LocalText(context, "welcome.pinlogin",
|
||||||
|
color: Colors.black, fontSize: 18),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
LocalText(
|
||||||
LocalText(
|
context,
|
||||||
context,
|
"welcome.pinlogin.fcsid",
|
||||||
"welcome.pinlogin.fcsid",
|
color: Colors.black54,
|
||||||
color: Colors.black54,
|
fontSize: 15,
|
||||||
fontSize: 15,
|
),
|
||||||
),
|
fcsIdBox,
|
||||||
fcsIdBox,
|
Padding(
|
||||||
Padding(
|
padding: EdgeInsets.only(top: 25, bottom: 20),
|
||||||
padding: EdgeInsets.only(top: 25, bottom: 20),
|
child: LocalText(
|
||||||
child: LocalText(
|
context,
|
||||||
context,
|
"welcome.pinlogin.pin",
|
||||||
"welcome.pinlogin.pin",
|
color: Colors.black54,
|
||||||
color: Colors.black54,
|
fontSize: 15,
|
||||||
fontSize: 15,
|
)),
|
||||||
)),
|
pinInputBox,
|
||||||
pinInputBox,
|
loginBtn,
|
||||||
loginBtn,
|
],
|
||||||
],
|
),
|
||||||
),
|
)),
|
||||||
)),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,14 +248,14 @@ class _PinLoginPageState extends State<PinLoginPage> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String fcsId = "$prefixText${_fcsIdCtl.text}";
|
String fcsId = "$prefixText${_fcsIdCtl.text}";
|
||||||
print(fcsId);
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Navigator.pop(context, true);
|
await context.read<MainModel>().pinLogin(fcsID: fcsId, pin: pin);
|
||||||
|
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showMsgDialog(context, "Error", e.toString());
|
showMsgDialog(context, "Error", e.toString());
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class StaffModel extends BaseModel {
|
|||||||
Future<void> updatePin(
|
Future<void> updatePin(
|
||||||
{required String userID,
|
{required String userID,
|
||||||
required bool enablePin,
|
required bool enablePin,
|
||||||
required int? pin}) async {
|
required String? pin}) async {
|
||||||
await request("/employee/pin", "PUT",
|
await request("/employee/pin", "PUT",
|
||||||
payload: {"id": userID, "enable_pin_login": enablePin, "pin": pin},
|
payload: {"id": userID, "enable_pin_login": enablePin, "pin": pin},
|
||||||
token: await getToken());
|
token: await getToken());
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ class _StaffPinEditorState extends State<StaffPinEditor> {
|
|||||||
await context.read<StaffModel>().updatePin(
|
await context.read<StaffModel>().updatePin(
|
||||||
userID: _staff.id!,
|
userID: _staff.id!,
|
||||||
enablePin: _enablePinLogin,
|
enablePin: _enablePinLogin,
|
||||||
pin: _enablePinLogin ? int.parse(_confirmPin) : null);
|
pin: _enablePinLogin ? _confirmPin : null);
|
||||||
Navigator.pop(context, true);
|
Navigator.pop(context, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showMsgDialog(context, "Error", e.toString());
|
showMsgDialog(context, "Error", e.toString());
|
||||||
|
|||||||
Reference in New Issue
Block a user