import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/widgets/local_app_bar.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 '../main/util.dart'; import '../widgets/local_text.dart'; import 'model/staff_model.dart'; class StaffPinEditor extends StatefulWidget { final User staff; const StaffPinEditor({required this.staff}); @override _StaffPinEditorState createState() => _StaffPinEditorState(); } class _StaffPinEditorState extends State { final _formKey = GlobalKey(); bool _isLoading = false; late User _staff; bool _enablePinLogin = false; String _newPin = ""; String _confirmPin = ""; FocusNode _newPinFocus = FocusNode(); FocusNode _confirmPinFocus = FocusNode(); TextEditingController _newPinCtl = TextEditingController(); TextEditingController _confirmPinCtl = TextEditingController(); @override void initState() { _init(); super.initState(); } _init() { _staff = widget.staff; _enablePinLogin = _staff.enablePinLogin; _newPin = _staff.pinDigit ?? ""; _confirmPin = _staff.pinDigit ?? ""; _newPinCtl.text = _newPin; _confirmPinCtl.text = _confirmPin; _checkFocusNode(); if (mounted) { setState(() {}); } } @override void dispose() { _newPinFocus.dispose(); _confirmPinFocus.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final enablePinBox = InkWell( onTap: () { setState(() { _enablePinLogin = !_enablePinLogin; }); _checkFocusNode(); }, child: Row( children: [ Checkbox( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity( horizontal: VisualDensity.minimumDensity, ), activeColor: primaryColor, side: BorderSide(color: Colors.black38, width: 2), value: _enablePinLogin, onChanged: (value) { setState(() { _enablePinLogin = value ?? false; }); _checkFocusNode(); }, ), const SizedBox(width: 15), LocalText(context, 'staff.enable_pin', fontSize: 15, color: Colors.black) ], ), ); final newPinBox = Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ LocalText(context, 'staff.new_pin', color: Colors.black54, fontSize: 15), const SizedBox(height: 8), PinInputTextField( controller: _newPinCtl, enabled: _enablePinLogin, cursor: Cursor( color: primaryColor, enabled: true, width: 2, height: 23), pinLength: 6, decoration: BoxLooseDecoration( strokeColorBuilder: PinListenColorBuilder( _enablePinLogin ? primaryColor : Colors.grey.shade400, Colors.grey.shade400)), textInputAction: TextInputAction.done, focusNode: _newPinFocus, onChanged: _newPinChange), ], ); final confirmPinBox = Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ LocalText(context, 'staff.confirm_pin', color: Colors.black54, fontSize: 15), const SizedBox(height: 8), PinInputTextField( controller: _confirmPinCtl, enabled: _enablePinLogin, pinLength: 6, cursor: Cursor( color: primaryColor, enabled: true, width: 2, height: 23), decoration: BoxLooseDecoration( strokeColorBuilder: PinListenColorBuilder( _enablePinLogin ? primaryColor : Colors.grey.shade400, Colors.grey.shade400)), textInputAction: TextInputAction.done, focusNode: _confirmPinFocus, onChanged: _confirmPinChange), ], ); final saveButton = Padding( padding: const EdgeInsets.symmetric(horizontal: 30), child: fcsButton( context, getLocalString(context, 'btn.save'), callack: _save, ), ); return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( appBar: LocalAppBar( labelKey: "staff.pin.title", backgroundColor: Colors.white, labelColor: primaryColor, arrowColor: primaryColor), body: Form( key: _formKey, child: Padding( padding: const EdgeInsets.only(left: 15.0, right: 15), child: ListView( children: [ Column( children: [ Text(_staff.name ?? "", style: TextStyle(color: Colors.black, fontSize: 18)), Text(_staff.fcsID ?? "", style: TextStyle(color: Colors.black, fontSize: 15)), ], ), const SizedBox(height: 10), enablePinBox, const SizedBox(height: 20), FormField( builder: (FormFieldState state) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ newPinBox, Padding( padding: const EdgeInsets.only(top: 8.0), child: _newPin == '' || _newPin.length < 6 ? SizedBox( height: 20, child: Text( state.errorText ?? '', style: const TextStyle( color: dangerColor, fontSize: 12), ), ) : const SizedBox(height: 20), ), ], ); }, validator: (value) { if (_newPin == "") { return 'Enter new PIN'; } if (_newPin.length < 6) { return 'New PIN must be 6 digits'; } return null; }, ), SizedBox(height: 10), FormField( builder: (FormFieldState state) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ confirmPinBox, Padding( padding: const EdgeInsets.only(top: 8.0), child: _confirmPin == '' || _confirmPin.length < 6 || _confirmPin != _newPin ? SizedBox( height: 20, child: Text( state.errorText ?? '', style: const TextStyle( color: dangerColor, fontSize: 12), ), ) : const SizedBox(height: 20)), ], ); }, validator: (value) { if (_confirmPin == "") { return 'Enter confirm PIN'; } if (_confirmPin.length < 6) { return 'Confirm PIN must be 6 digits'; } if (_confirmPin != _newPin) { return "Those pins didn’t match. Try again."; } return null; }, ), SizedBox(height: 20), saveButton, SizedBox(height: 30) ], ), ), ), )); } _checkFocusNode() { if (_enablePinLogin) { _onChangeFocusNode(); } else { _cancelFoucsNode(); } if (mounted) { setState(() {}); } } _onChangeFocusNode() { if (this._newPin.length == 6) { _newPinFocus.unfocus(); Future.delayed(const Duration(milliseconds: 300), () { _confirmPinFocus.requestFocus(); }); } else { _confirmPinFocus.unfocus(); Future.delayed(const Duration(milliseconds: 300), () { _newPinFocus.requestFocus(); }); } } _cancelFoucsNode() { _newPinFocus.unfocus(); Future.delayed(const Duration(milliseconds: 300), () { _confirmPinFocus.unfocus(); }); } _newPinChange(pin) { setState(() { this._newPin = pin; if (this._newPin.length == 6) { _confirmPinFocus.requestFocus(); } }); } _confirmPinChange(pin) { setState(() { this._confirmPin = pin; }); } _save() async { if (_enablePinLogin) { if (!_formKey.currentState!.validate()) return; } setState(() { _isLoading = true; }); try { await context.read().updatePin( userID: _staff.id!, enablePin: _enablePinLogin, pin: _enablePinLogin ? _confirmPin : null); Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString()); } finally { setState(() { _isLoading = false; }); } } }