Appearance
Overview
- File:
lib/views/settings_page.dart
The SettingsPage is a Flutter widget that provides a comprehensive settings interface for the HVC Mobile application. It allows users to manage their contact information, default page settings, notification preferences, security settings, and PIN changes. The page is organized into expandable sections for better organization and user experience.
Class Structure
Class Definition
dart
class SettingsPage extends StatelessWidget {
static const String routeName = '/SettingsPage';
SettingsPage({Key? key}) : super(key: key);
final TextEditingController phoneNumberCtrl = TextEditingController();
final TextEditingController emailCtrl = TextEditingController();
final TextEditingController departmentCtrl = TextEditingController();
final TextEditingController specialtyCtrl = TextEditingController();
final TextEditingController webDefaultPageCtrl = TextEditingController();
final TextEditingController mobileDefaultPageCtrl = TextEditingController();
final TextEditingController headsetDefaultPageCtrl = TextEditingController();
TextEditingController pin1Ctrl = TextEditingController();
TextEditingController pin2Ctrl = TextEditingController();
final SettingsController settingsController = Get.find();
final AuthController authController = Get.find();
final ContactsController contactsController = Get.find();
final RxString pin1 = ''.obs;
final RxString pin2 = ''.obs;
final FocusNode focusNode = FocusNode();
final List<String> webOptions = [
"Dashboard",
"Contacts",
"Calendar",
"Ledger"
];
final List<String> mobileOptions = ["Home", "Events", "Contacts", "Messages"];
final List<String> headSetOptions = ["Home", "Contacts", "Events", "Camera"];
RxString localImagePath = ''.obs;
RxString imgFileName = ''.obs;
Uint8List? byteArray;
@override
Widget build(BuildContext context) {
// Implementation...
}
}Dependencies
Required Packages
flutter/material.dart- Core Flutter UI componentsget/get.dart- State management and routingget_storage/get_storage.dart- Local storagepin_code_fields/pin_code_fields.dart- PIN input field
Internal Dependencies
controllers/auth_controller.dart- Authentication managementcontrollers/contacts_controller.dart- Contact managementcontrollers/settings_controller.dart- Settings managementhlk_helpers/hlk_extension_methods.dart- Extension methodshlk_helpers/hlk_models.dart- Helper modelshlk_helpers/hlk_utils.dart- Utility functionshlk_helpers/hlk_widget.dart- Custom widgetsmodels/core_models.dart- Core data modelsshared/common.dart- Common utilitiesshared/constants.dart- Constantswidgets/hlk_widgets.dart- Custom widgets
State Management
Controller Initialization
dart
final SettingsController settingsController = Get.find();
final AuthController authController = Get.find();
final ContactsController contactsController = Get.find();Reactive State Variables
dart
final RxString pin1 = ''.obs;
final RxString pin2 = ''.obs;
RxString localImagePath = ''.obs;
RxString imgFileName = ''.obs;Text Controllers
dart
final TextEditingController phoneNumberCtrl = TextEditingController();
final TextEditingController emailCtrl = TextEditingController();
final TextEditingController departmentCtrl = TextEditingController();
final TextEditingController specialtyCtrl = TextEditingController();
final TextEditingController webDefaultPageCtrl = TextEditingController();
final TextEditingController mobileDefaultPageCtrl = TextEditingController();
final TextEditingController headsetDefaultPageCtrl = TextEditingController();
TextEditingController pin1Ctrl = TextEditingController();
TextEditingController pin2Ctrl = TextEditingController();UI Components
Main Layout
dart
Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: SingleChildScrollView(
child: Column(
children: [
// Expansion tiles for different settings sections
],
),
),
)Expansion Tiles
dart
ExpansionTile(
iconColor: kAppColorBlue,
initiallyExpanded: true,
maintainState: true,
childrenPadding: const EdgeInsets.all(20),
expandedCrossAxisAlignment: CrossAxisAlignment.start,
tilePadding: const EdgeInsets.all(20),
title: const Text('Contact Information', style: blueBoldTextStyle),
children: [
// Contact information fields
],
)Profile Image
dart
GestureDetector(
onTap: () {
// Image selection dialog
},
child: Row(
children: [
Obx(
() => localImagePath.value.isEmpty &&
GetUtils.isNullOrBlank(user.photoUrl)! &&
(contactsController.byteArrayList.isEmpty ||
byteArray == null)
? RoundedText(
text: user.name.toInitials().substring(0, 1),
radius: radius,
width: radius,
height: radius,
backgroundColor: kAppColorLightBlue,
textStyle: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 20,
color: kAppColorGrey,
),
)
: CircleAvatar(
radius: radius / 2,
child: ClipRRect(
borderRadius: BorderRadius.circular(radius * 2),
child: contactsController.byteArrayList.isNotEmpty
? Image.memory(Uint8List.fromList(
contactsController.byteArrayList))
: Image.network(user.photoUrl!),
),
),
),
horizontalSpace(0.02),
Text(
user.name,
style: normalStyle,
),
],
),
)Text Fields
dart
TextField(
controller: phoneNumberCtrl,
decoration: getInputDecorationNoBorder('Enter Phone Number', true),
maxLines: 1,
)Dropdown Fields
dart
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Web Default Page',
labelStyle: const TextStyle(
color: kAppColorBlue,
fontSize: 16,
),
border: const OutlineInputBorder(
borderSide: BorderSide(
color: kAppColorBlue,
),
),
),
value: webDefaultPageCtrl.text.isEmpty
? webOptions.first
: webDefaultPageCtrl.text,
onChanged: (newValue) {
webDefaultPageCtrl.text = newValue!;
},
items: webOptions.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)PIN Input Fields
dart
PinCodeTextField(
controller: pin1Ctrl,
appContext: context,
autoDismissKeyboard: true,
keyboardType: TextInputType.number,
length: 4,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: pinTheme,
cursorColor: kAppColorBlack,
animationDuration: const Duration(milliseconds: 300),
enableActiveFill: true,
beforeTextPaste: (x) {
return true;
},
onCompleted: (value) {
pin1.value = value;
logInfo(pin1.value);
focusNode.requestFocus();
},
onChanged: (value) {},
)Action Buttons
dart
projectActionButton(
action: () async {
// Update action
},
load: contactsController.loading,
btnText: 'UPDATE',
)Settings Management
Contact Information
dart
projectActionButton(
action: () async {
if (phoneNumberCtrl.text.isNotEmpty ||
emailCtrl.text.isNotEmpty ||
departmentCtrl.text.isNotEmpty ||
specialtyCtrl.text.isNotEmpty) {
final phoneNumber = phoneNumberCtrl.text.isNotEmpty
? phoneNumberCtrl.text.trim()
: getString(user.phoneNumber);
final email = emailCtrl.text.isNotEmpty
? emailCtrl.text.trim()
: getString(user.email);
final department = departmentCtrl.text.isNotEmpty
? departmentCtrl.text.trim()
: getString(user.department);
final specialty = specialtyCtrl.text.isNotEmpty
? specialtyCtrl.text.trim()
: getString(user.specialty);
await contactsController.updateUser(
phoneNumber: phoneNumber,
email: email,
department: department,
specialty: specialty,
headsetDefaultPage: headsetDefaultPageCtrl.text,
webDefaultPage: webDefaultPageCtrl.text,
mobileDefaultPage: mobileDefaultPageCtrl.text,
timeOffset: 0,
filename: imgFileName.value,
fileByteArray: byteArray,
);
}
},
load: contactsController.loading,
btnText: 'UPDATE',
)Notification Settings
dart
Obx(
() => SwitchListTile(
title: const Text('Enable Notifications'),
value: settingsController.enableNotification.value,
onChanged: (bool value) {
settingsController.enableNotification.value = value;
},
),
)Security Settings
dart
Obx(
() => SwitchListTile(
title: const Text('Keep Me Logged In'),
value: settingsController.keepMeLoggedIn.value,
onChanged: (bool value) {
HlkDialog.showMessageInAlertDialog(
title: 'Security Warning',
message:
'This will disable auto logout on this device and should only be used on a personal device for security purposes. If this is a personal device, click OK. If not, click Cancel.',
dialogContent: [
AlertDialogContent(
'OK',
(otherContext) {
settingsController.keepMeLoggedIn.value = value;
if (value) {
settingsController.enableBiometric.value =
!settingsController.keepMeLoggedIn.value;
}
Get.back();
},
),
AlertDialogContent(
'CANCEL', (otherContext) => Get.back()),
],
);
},
),
)PIN Change
dart
projectActionButton(
action: () async {
if (pin1.value == pin2.value && pin1.isNotEmpty) {
await authController.resetPin(pin1.value);
}
pin1.value = '';
pin2.value = '';
pin1Ctrl.clear();
pin2Ctrl.clear();
},
load: authController.loading,
btnText: 'UPDATE',
)Security Features
Biometric Authentication
dart
if (settingsController.canAuthenticate)
Obx(
() => SwitchListTile(
title: const Text('Enable Biometric Log In'),
value: settingsController.enableBiometric.value,
onChanged: (bool value) async {
HlkDialog.showMessageInAlertDialog(
title: 'Biometrics Authentication',
message:
'Use biometric log in for faster and easier access to your account. You can turn this feature on or off at any time under settings.',
dialogContent: [
AlertDialogContent(
settingsController.enableBiometric.value
? 'DISABLE'
: 'ENABLE',
(otherContext) async {
if (value) {
settingsController.enableBiometric.value =
await authController.getBioToken();
if (settingsController.enableBiometric.value) {
settingsController.keepMeLoggedIn.value = false;
}
settingsController.keepMeLoggedIn.value =
!settingsController.enableBiometric.value;
} else {
settingsController.enableBiometric.value = value;
}
Get.back();
if (authController.biometricErrorMessage.isNotEmpty) {
HlkDialog.showErrorSnackBar(
authController.biometricErrorMessage.value);
throw Exception(
authController.biometricErrorMessage.value);
}
},
),
AlertDialogContent(
'NOT NOW',
(otherContext) => Get.back(),
),
],
);
},
),
)PIN Validation
dart
validator: (v) {
return pin1.value == pin2.value ? null : 'Pin mismatched';
},