organise components in subfolders

This commit is contained in:
2024-08-13 10:15:39 +02:00
parent 7a6ba04220
commit 187e4fb604
34 changed files with 77 additions and 77 deletions

View File

@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
class MIHButton extends StatelessWidget {
final void Function() onTap;
final String buttonText;
final Color buttonColor;
final Color textColor;
const MIHButton({
super.key,
required this.onTap,
required this.buttonText,
required this.buttonColor,
required this.textColor,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 25.0),
child: ElevatedButton(
onPressed: onTap,
style: ElevatedButton.styleFrom(
backgroundColor: buttonColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
child: Text(
buttonText,
style: TextStyle(
//fontWeight: FontWeight.bold,
fontSize: 20,
color: textColor,
fontWeight: FontWeight.bold,
),
),
),
);
}
}

View File

@@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHDateField extends StatefulWidget {
final controller;
final String LableText;
final bool required;
const MIHDateField({
super.key,
required this.controller,
required this.LableText,
required this.required,
});
@override
State<MIHDateField> createState() => _MIHDateFieldState();
}
class _MIHDateFieldState extends State<MIHDateField> {
FocusNode _focus = FocusNode();
bool startup = true;
// bool makeEditable() {
Future<void> _selectDate(BuildContext context) async {
DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
if (picked != null) {
setState(() {
widget.controller.text = picked.toString().split(" ")[0];
});
}
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.LableText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.LableText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
String? get _errorText {
final text = widget.controller.text;
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.LableText} is required";
}
return null;
}
@override
void initState() {
_focus.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
controller: widget.controller,
readOnly: true,
obscureText: false,
focusNode: _focus,
onChanged: (_) => setState(() {
startup = false;
}),
decoration: InputDecoration(
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
label: setRequiredText(),
//labelText: widget.LableText,
//labelStyle: const TextStyle(color: Colors.blueAccent),
prefixIcon: Icon(
Icons.calendar_today,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
filled: true,
//hintText: hintText,
//hintStyle: TextStyle(color: Colors.blueGrey[400]),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
),
onTap: () {
_selectDate(context);
},
);
}
}

View File

@@ -0,0 +1,207 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHDropdownField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final bool required;
final List<String> dropdownOptions;
final void Function(String?)? onSelect;
final bool editable;
const MIHDropdownField({
super.key,
required this.controller,
required this.hintText,
required this.dropdownOptions,
required this.required,
required this.editable,
this.onSelect,
});
@override
State<MIHDropdownField> createState() => _MIHDropdownFieldState();
}
class _MIHDropdownFieldState extends State<MIHDropdownField> {
//var dropbownItems = ["Dr.", "Assistant"];
bool startup = true;
final FocusNode _focus = FocusNode();
late var menu;
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.hintText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
String? get _errorText {
final text = widget.controller.text;
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.hintText} is required";
}
return null;
}
List<DropdownMenuEntry<String>> buidMenueOptions(List<String> options) {
List<DropdownMenuEntry<String>> menueList = [];
for (final i in options) {
menueList.add(DropdownMenuEntry(
value: i,
label: i,
style: ButtonStyle(
foregroundColor: WidgetStatePropertyAll(
MzanziInnovationHub.of(context)!.theme.secondaryColor()))));
}
return menueList;
}
@override
void initState() {
menu = buidMenueOptions(widget.dropdownOptions);
_focus.addListener(_onFocusChange);
super.initState();
}
// bool makeEditable() {
@override
Widget build(BuildContext context) {
return DropdownMenu(
enabled: widget.editable,
trailingIcon: Icon(
Icons.arrow_drop_down,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
selectedTrailingIcon: Icon(
Icons.arrow_drop_up,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
textStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
menuHeight: 300,
controller: widget.controller,
expandedInsets: EdgeInsets.zero,
label: setRequiredText(),
errorText: _errorText,
focusNode: _focus,
onSelected: (_) {
setState(() {
startup = false;
});
// if (widget.editable == false) {
// return false;
// }
},
leadingIcon: IconButton(
onPressed: () {
setState(() {
startup = false;
});
widget.controller.clear();
},
icon: Icon(
Icons.delete_outline_rounded,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
menuStyle: MenuStyle(
backgroundColor: WidgetStatePropertyAll(
MzanziInnovationHub.of(context)!.theme.primaryColor()),
side: WidgetStatePropertyAll(
BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
outlineBorder: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
dropdownMenuEntries: menu,
// const <DropdownMenuEntry<String>>[
// DropdownMenuEntry(value: "Dr.", label: "Dr."),
// DropdownMenuEntry(value: "Assistant", label: "Assistant"),
// ],
);
}
}
// filled: true,
// hintText: hintText,
// hintStyle: TextStyle(color: Colors.blueGrey[400]),
// enabledBorder: const OutlineInputBorder(
// borderSide: BorderSide(
// color: Colors.blueAccent,
// width: 2.0,
// ),
// ),
// focusedBorder: const OutlineInputBorder(
// borderSide: BorderSide(color: Colors.blue),

View File

@@ -0,0 +1,171 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHFileField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final bool editable;
final bool required;
final void Function() onPressed;
const MIHFileField({
super.key,
required this.controller,
required this.hintText,
required this.editable,
required this.required,
required this.onPressed,
});
@override
State<MIHFileField> createState() => _MIHFileFieldState();
}
class _MIHFileFieldState extends State<MIHFileField> {
bool startup = true;
FocusNode _focus = FocusNode();
bool makeEditable() {
if (widget.editable) {
return false;
} else {
return true;
}
}
String? get _errorText {
final text = widget.controller.text;
String _errorMessage = '';
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.hintText} is required";
}
if (widget.hintText == "Email" && !isEmailValid(text)) {
_errorMessage += "Enter a valid email address\n";
}
if (widget.hintText == "Username" && text.length < 8) {
_errorMessage += "• Username must contain at least 8 characters.\n";
}
if (widget.hintText == "Username" && !isUsernameValid(text)) {
_errorMessage += "• Username can only contain '_' special Chracters.\n";
}
if (_errorMessage.isEmpty) {
return null;
}
// If there are no error messages, the password is valid
return _errorMessage;
}
bool isUsernameValid(String Username) {
return RegExp(r'^(?=[a-zA-Z0-9._]{8,20}$)(?!.*[_.]{2})[^_.].*[^_.]$')
.hasMatch(Username);
}
bool isEmailValid(String email) {
return RegExp(r'^[\w-\.]+@[a-zA-Z]+\.[a-zA-Z]{2,}$').hasMatch(email);
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.hintText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
@override
void initState() {
_focus.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
controller: widget.controller,
focusNode: _focus,
readOnly: makeEditable(),
//enabled: !makeEditable(),
obscureText: false,
onChanged: (_) => setState(() {
startup = false;
}),
decoration: InputDecoration(
suffixIcon: IconButton(
icon: const Icon(Icons.attach_file),
onPressed: widget.onPressed,
),
label: setRequiredText(),
//labelStyle: TextStyle(color: MzanziInnovationHub.of(context)!.theme.primaryColor()),
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
filled: true,
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
//errorBorder: const InputBorder(),
//hintText: hintText,
//hintStyle: TextStyle(color: Colors.blueGrey[400]),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
),
);
}
}

View File

@@ -0,0 +1,140 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHMLTextField extends StatefulWidget {
final controller;
final String hintText;
final bool editable;
final bool required;
const MIHMLTextField({
super.key,
required this.controller,
required this.hintText,
required this.editable,
required this.required,
});
@override
State<MIHMLTextField> createState() => _MIHMLTextFieldState();
}
class _MIHMLTextFieldState extends State<MIHMLTextField> {
bool startup = true;
FocusNode _focus = FocusNode();
bool makeEditable() {
if (widget.editable) {
return false;
} else {
return true;
}
}
String? get _errorText {
final text = widget.controller.text;
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.hintText} is required";
}
return null;
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.hintText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
@override
void initState() {
_focus.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
textAlign: TextAlign.start,
textAlignVertical: TextAlignVertical.top,
expands: true,
maxLines: null,
controller: widget.controller,
readOnly: makeEditable(),
obscureText: false,
focusNode: _focus,
onChanged: (_) => setState(() {
startup = false;
}),
decoration: InputDecoration(
label: setRequiredText(),
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
labelStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
alignLabelWithHint: true,
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
filled: true,
//hintText: hintText,
//hintStyle: TextStyle(color: Colors.blueGrey[400]),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
),
);
}
}

View File

@@ -0,0 +1,182 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHPassField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final bool required;
final bool signIn;
const MIHPassField({
super.key,
required this.controller,
required this.hintText,
required this.required,
required this.signIn,
});
@override
State<MIHPassField> createState() => _MIHPassFieldState();
}
class _MIHPassFieldState extends State<MIHPassField> {
bool startup = true;
final textFieldFocusNode = FocusNode();
bool _obscured = true;
//bool valid = false;
void _toggleObscured() {
setState(() {
_obscured = !_obscured;
if (textFieldFocusNode.hasPrimaryFocus) {
return; // If focus is on text field, dont unfocus
}
textFieldFocusNode.canRequestFocus =
false; // Prevents focus if tap on eye
});
}
String? get _errorText {
final text = widget.controller.text;
String _errorMessage = '';
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.hintText} is required";
}
// Password length greater than 8
if (text.length <= 8 && !widget.signIn) {
_errorMessage += '• Password must contain at least 8 characters.\n';
}
// Contains at least one uppercase letter
if (!text.contains(RegExp(r'[A-Z]')) && !widget.signIn) {
_errorMessage += '• Uppercase letter is missing.\n';
}
// Contains at least one lowercase letter
if (!text.contains(RegExp(r'[a-z]')) && !widget.signIn) {
_errorMessage += '• Lowercase letter is missing.\n';
}
// Contains at least one digit
if (!text.contains(RegExp(r'[0-9]')) && !widget.signIn) {
_errorMessage += '• number is missing.\n';
}
// Contains at least one special character
if (!text.contains(RegExp(r'[!@#$%^&*]')) && !widget.signIn) {
_errorMessage += '• Special character is missing - !@#\$%^&*\n';
}
// Contains no errors
if (_errorMessage.isEmpty) {
return null;
}
// If there are no error messages, the password is valid
return _errorMessage;
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.hintText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
@override
void initState() {
textFieldFocusNode.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: widget.controller,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
obscureText: _obscured,
focusNode: textFieldFocusNode,
onChanged: (_) => setState(() {
startup = false;
}),
decoration: InputDecoration(
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
filled: true,
label: setRequiredText(),
//labelStyle: const TextStyle(color: Colors.blueAccent),
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
//hintText: widget.hintText,
//hintStyle: TextStyle(color: Colors.blueGrey[400]),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
suffixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
child: GestureDetector(
onTap: _toggleObscured,
child: Icon(
_obscured
? Icons.visibility_rounded
: Icons.visibility_off_rounded,
size: 24,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,152 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHSearchField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final bool required;
final bool editable;
final void Function() onTap;
const MIHSearchField({
super.key,
required this.controller,
required this.hintText,
required this.required,
required this.editable,
required this.onTap,
});
@override
State<MIHSearchField> createState() => _MIHSearchFieldState();
}
class _MIHSearchFieldState extends State<MIHSearchField> {
bool startup = true;
FocusNode _focus = FocusNode();
bool makeEditable() {
if (widget.editable) {
return false;
} else {
return true;
}
}
String? get _errorText {
final text = widget.controller.text;
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.hintText} is required";
}
return null;
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(
widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
],
);
} else {
return Text(widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
@override
void initState() {
_focus.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
onChanged: (_) {
setState(() {
startup = false;
});
},
controller: widget.controller,
//style: TextStyle(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
readOnly: makeEditable(),
focusNode: _focus,
obscureText: false,
decoration: InputDecoration(
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
suffixIcon: IconButton(
icon: Icon(
Icons.search,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
onPressed: () {
setState(() {
startup = false;
});
if (widget.controller.text != "") {
widget.onTap();
}
},
),
filled: true,
label: setRequiredText(),
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
),
);
}
}

View File

@@ -0,0 +1,166 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHTextField extends StatefulWidget {
final TextEditingController controller;
final String hintText;
final bool editable;
final bool required;
const MIHTextField({
super.key,
required this.controller,
required this.hintText,
required this.editable,
required this.required,
});
@override
State<MIHTextField> createState() => _MIHTextFieldState();
}
class _MIHTextFieldState extends State<MIHTextField> {
bool startup = true;
FocusNode _focus = FocusNode();
bool makeEditable() {
if (widget.editable) {
return false;
} else {
return true;
}
}
String? get _errorText {
final text = widget.controller.text;
String _errorMessage = '';
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.hintText} is required";
}
if (widget.hintText == "Email" && !isEmailValid(text)) {
_errorMessage += "Enter a valid email address\n";
}
if (widget.hintText == "Username" && text.length < 8) {
_errorMessage += "• Username must contain at least 8 characters.\n";
}
if (widget.hintText == "Username" && !isUsernameValid(text)) {
_errorMessage += "• Username can only contain '_' special Chracters.\n";
}
if (_errorMessage.isEmpty) {
return null;
}
// If there are no error messages, the password is valid
return _errorMessage;
}
bool isUsernameValid(String Username) {
return RegExp(r'^(?=[a-zA-Z0-9._]{8,20}$)(?!.*[_.]{2})[^_.].*[^_.]$')
.hasMatch(Username);
}
bool isEmailValid(String email) {
return RegExp(r'^[\w-\.]+@[a-zA-Z]+\.[a-zA-Z]{2,}$').hasMatch(email);
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.hintText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.hintText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
@override
void initState() {
_focus.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
controller: widget.controller,
focusNode: _focus,
readOnly: makeEditable(),
//enabled: !makeEditable(),
obscureText: false,
onChanged: (_) => setState(() {
startup = false;
}),
decoration: InputDecoration(
label: setRequiredText(),
//labelStyle: TextStyle(color: MzanziInnovationHub.of(context)!.theme.primaryColor()),
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
filled: true,
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
//errorBorder: const InputBorder(),
//hintText: hintText,
//hintStyle: TextStyle(color: Colors.blueGrey[400]),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
),
);
}
}

View File

@@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import 'package:patient_manager/main.dart';
class MIHDateField extends StatefulWidget {
final controller;
final String LableText;
final bool required;
const MIHDateField({
super.key,
required this.controller,
required this.LableText,
required this.required,
});
@override
State<MIHDateField> createState() => _MIHDateFieldState();
}
class _MIHDateFieldState extends State<MIHDateField> {
FocusNode _focus = FocusNode();
bool startup = true;
// bool makeEditable() {
Future<void> _selectDate(BuildContext context) async {
DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
if (picked != null) {
setState(() {
widget.controller.text = picked.toString().split(" ")[0];
});
}
}
Widget setRequiredText() {
if (widget.required) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"*",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
),
const SizedBox(
width: 8.0,
),
Text(widget.LableText,
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor())),
],
);
} else {
return Text(widget.LableText,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()));
}
}
void _onFocusChange() {
setState(() {
startup = false;
});
}
String? get _errorText {
final text = widget.controller.text;
if (startup) {
return null;
}
if (!widget.required) {
return null;
}
if (text.isEmpty) {
return "${widget.LableText} is required";
}
return null;
}
@override
void initState() {
_focus.addListener(_onFocusChange);
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
controller: widget.controller,
readOnly: true,
obscureText: false,
focusNode: _focus,
onChanged: (_) => setState(() {
startup = false;
}),
decoration: InputDecoration(
errorText: _errorText,
errorStyle: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
fontWeight: FontWeight.bold),
label: setRequiredText(),
//labelText: widget.LableText,
//labelStyle: const TextStyle(color: Colors.blueAccent),
prefixIcon: Icon(
Icons.calendar_today,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
fillColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
filled: true,
//hintText: hintText,
//hintStyle: TextStyle(color: Colors.blueGrey[400]),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
width: 2.0,
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
),
),
onTap: () {
_selectDate(context);
},
);
}
}