base_project
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorConstant {
|
||||
static Color gray5001 = fromHex('#f6f7fb');
|
||||
|
||||
static Color purple211 = const Color.fromARGB(255, 93, 63, 211);
|
||||
|
||||
static Color gray5002 = fromHex('#f8f9fa');
|
||||
|
||||
static Color black900B2 = fromHex('#b2000000');
|
||||
|
||||
static Color gray5003 = fromHex('#fafcff');
|
||||
|
||||
static Color lightBlue100 = fromHex('#b0e5fc');
|
||||
|
||||
static Color gray80049 = fromHex('#493c3c43');
|
||||
|
||||
static Color yellow9003f = fromHex('#3feb9612');
|
||||
|
||||
static Color iris = fromHex('5D3FD3');
|
||||
|
||||
static Color red200 = fromHex('#fa9a9a');
|
||||
|
||||
static Color gray4004c = fromHex('#4cc4c4c4');
|
||||
|
||||
static Color blueA200 = fromHex('#468ee5');
|
||||
|
||||
static Color greenA100 = fromHex('#b5eacd');
|
||||
|
||||
static Color black9003f = fromHex('#3f000000');
|
||||
|
||||
static Color gray30099 = fromHex('#99e4e4e4');
|
||||
|
||||
static Color black90087 = fromHex('#87000000');
|
||||
|
||||
static Color whiteA70099 = fromHex('#99ffffff');
|
||||
|
||||
static Color black90001 = fromHex('#000000');
|
||||
|
||||
static Color blueGray90002 = fromHex('#24363c');
|
||||
|
||||
static Color blueGray90001 = fromHex('#2e3637');
|
||||
|
||||
static Color blueGray700 = fromHex('#535763');
|
||||
|
||||
static Color blueGray900 = fromHex('#262b35');
|
||||
|
||||
static Color black90003 = fromHex('#0b0a0a');
|
||||
|
||||
static Color black90002 = fromHex('#090b0d');
|
||||
|
||||
static Color redA700 = fromHex('#d80027');
|
||||
|
||||
static Color black90004 = fromHex('#000000');
|
||||
|
||||
static Color gray400 = fromHex('#c4c4c4');
|
||||
|
||||
static Color blue900 = fromHex('#003399');
|
||||
|
||||
static Color blueGray100 = fromHex('#d6dae2');
|
||||
|
||||
static Color blue700 = fromHex('#1976d2');
|
||||
|
||||
static Color blueGray300 = fromHex('#9ea8ba');
|
||||
|
||||
static Color amber500 = fromHex('#feb909');
|
||||
|
||||
static Color redA200 = fromHex('#fe555d');
|
||||
|
||||
static Color gray80099 = fromHex('#993c3c43');
|
||||
|
||||
static Color black9000c = fromHex('#0c000000');
|
||||
|
||||
static Color gray200 = fromHex('#efefef');
|
||||
|
||||
static Color gray60026 = fromHex('#266d6d6d');
|
||||
|
||||
static Color blue50 = fromHex('#e0ebff');
|
||||
|
||||
static Color indigo400 = fromHex('#4168d7');
|
||||
|
||||
static Color blueGray1006c = fromHex('#6cd1d3d4');
|
||||
|
||||
static Color black90011 = fromHex('#11000000');
|
||||
|
||||
static Color gray40001 = fromHex('#b3b3b3');
|
||||
|
||||
static Color whiteA70067 = fromHex('#67ffffff');
|
||||
|
||||
static Color gray10001 = fromHex('#fbf1f2');
|
||||
|
||||
static Color black90019 = fromHex('#19000000');
|
||||
|
||||
static Color blueGray40001 = fromHex('#888888');
|
||||
|
||||
static Color whiteA700 = fromHex('#ffffff');
|
||||
|
||||
static Color blueGray50 = fromHex('#eaecf0');
|
||||
|
||||
static Color red700 = fromHex('#d03329');
|
||||
|
||||
static Color blueA700 = fromHex('#0061ff');
|
||||
|
||||
static Color blueGray10001 = fromHex('#d6d6d6');
|
||||
|
||||
static Color gray60019 = fromHex('#197e7e7e');
|
||||
|
||||
static Color green600 = fromHex('#349765');
|
||||
|
||||
static Color blueA70001 = fromHex('#0068ff');
|
||||
|
||||
static Color gray50 = fromHex('#f9fbff');
|
||||
|
||||
static Color red100 = fromHex('#f6d6d4');
|
||||
|
||||
static Color blueGray20001 = fromHex('#adb5bd');
|
||||
|
||||
static Color black900 = fromHex('#000919');
|
||||
|
||||
static Color blueGray800 = fromHex('#37334d');
|
||||
|
||||
static Color blue5001 = fromHex('#eef4ff');
|
||||
|
||||
static Color deepOrange400 = fromHex('#d58c48');
|
||||
|
||||
static Color deepOrangeA400 = fromHex('#ff4b00');
|
||||
|
||||
static Color gray70011 = fromHex('#11555555');
|
||||
|
||||
static Color indigoA20033 = fromHex('#334871e3');
|
||||
|
||||
static Color gray90002 = fromHex('#0d062d');
|
||||
|
||||
static Color gray700 = fromHex('#666666');
|
||||
|
||||
static Color blueGray200 = fromHex('#bac1ce');
|
||||
|
||||
static Color blueGray400 = fromHex('#74839d');
|
||||
|
||||
static Color blue800 = fromHex('#2953c7');
|
||||
|
||||
static Color blueGray600 = fromHex('#5f6c86');
|
||||
|
||||
static Color gray900 = fromHex('#2a2a2a');
|
||||
|
||||
static Color gray90001 = fromHex('#212529');
|
||||
|
||||
static Color gray300 = fromHex('#d2efe0');
|
||||
|
||||
static Color gray30001 = fromHex('#e3e4e5');
|
||||
|
||||
static Color gray100 = fromHex('#f3f4f5');
|
||||
|
||||
static Color black90075 = fromHex('#75000000');
|
||||
|
||||
static Color deepOrangeA10033 = fromHex('#33dfa874');
|
||||
|
||||
static Color gray70026 = fromHex('#26555555');
|
||||
|
||||
static Color black90033 = fromHex('#33000000');
|
||||
|
||||
static Color blue200 = fromHex('#a6c8ff');
|
||||
|
||||
static Color purple900 = Colors.purple.shade900;
|
||||
|
||||
static Color fromHex(String hexString) {
|
||||
final buffer = StringBuffer();
|
||||
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
|
||||
buffer.write(hexString.replaceFirst('#', ''));
|
||||
return Color(int.parse(buffer.toString(), radix: 16));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
import 'package:another_flushbar/flushbar.dart';
|
||||
import 'package:base_project/resources/app_colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class FlushBarMessageUtil {
|
||||
|
||||
static void showFlushBar({
|
||||
required BuildContext context,
|
||||
required String message,
|
||||
FlushBarType flushBarType = FlushBarType.info,
|
||||
int durationInSeconds = 3,
|
||||
}) {
|
||||
Flushbar(
|
||||
message: message,
|
||||
duration: Duration(seconds: durationInSeconds),
|
||||
backgroundColor: _getBackgroundColor(flushBarType),
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
flushbarPosition: FlushbarPosition.BOTTOM,
|
||||
icon: _getIcon(flushBarType),
|
||||
leftBarIndicatorColor: _getBackgroundColor(flushBarType),
|
||||
).show(context);
|
||||
}
|
||||
|
||||
static Color _getBackgroundColor(FlushBarType flushBarType) {
|
||||
switch (flushBarType) {
|
||||
case FlushBarType.success:
|
||||
return AppColors.success;
|
||||
case FlushBarType.error:
|
||||
return AppColors.error;
|
||||
case FlushBarType.warning:
|
||||
return AppColors.warning;
|
||||
case FlushBarType.info:
|
||||
return AppColors.info;
|
||||
case FlushBarType.general:
|
||||
return AppColors.darkGrey;
|
||||
default:
|
||||
return AppColors.info;
|
||||
}
|
||||
}
|
||||
|
||||
static Icon _getIcon(FlushBarType flushBarType) {
|
||||
switch (flushBarType) {
|
||||
case FlushBarType.success:
|
||||
return const Icon(Icons.check_circle, color: Colors.white);
|
||||
case FlushBarType.error:
|
||||
return const Icon(Icons.error, color: Colors.white);
|
||||
case FlushBarType.warning:
|
||||
return const Icon(Icons.warning, color: Colors.white);
|
||||
case FlushBarType.info:
|
||||
return const Icon(Icons.info, color: Colors.white);
|
||||
case FlushBarType.general:
|
||||
return const Icon(Icons.notifications, color: Colors.white);
|
||||
default:
|
||||
return const Icon(Icons.info, color: Colors.white);
|
||||
}
|
||||
}
|
||||
}
|
||||
enum FlushBarType { success, error, warning, info, general }
|
||||
@@ -0,0 +1,35 @@
|
||||
class FormValidators {
|
||||
// Validator for non-empty fields
|
||||
static String? validateNotEmpty(String? value) {
|
||||
return value == null || value.isEmpty ? 'This field cannot be empty' : null;
|
||||
}
|
||||
|
||||
// Validator for email format
|
||||
static String? validateEmail(String? value) {
|
||||
const emailPattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
|
||||
final regex = RegExp(emailPattern);
|
||||
return value == null || !regex.hasMatch(value) ? 'Enter a valid email address' : null;
|
||||
}
|
||||
|
||||
// Validator for phone number format
|
||||
static String? validatePhoneNumber(String? value) {
|
||||
const phonePattern = r'^\+?[1-9]\d{1,14}$'; // E.164 format
|
||||
final regex = RegExp(phonePattern);
|
||||
return value == null || !regex.hasMatch(value) ? 'Enter a valid phone number' : null;
|
||||
}
|
||||
|
||||
// Validator for min length
|
||||
static String? validateMinLength(String? value, int minLength) {
|
||||
return value == null || value.length < minLength ? 'Must be at least $minLength characters long' : null;
|
||||
}
|
||||
|
||||
// Validator for max length
|
||||
static String? validateMaxLength(String? value, int maxLength) {
|
||||
return value != null && value.length > maxLength ? 'Must be no more than $maxLength characters long' : null;
|
||||
}
|
||||
|
||||
// Validator for matching passwords
|
||||
static String? validatePasswordMatch(String? value, String password) {
|
||||
return value != password ? 'Passwords do not match' : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
class ImageConstant {
|
||||
// Image folder path
|
||||
static String imagePath = 'assets/images';
|
||||
|
||||
// All images
|
||||
|
||||
static String imgArrowleft = '$imagePath/img_arrowleft.svg';
|
||||
|
||||
static String userProfileImg = "$imagePath/user-line.svg";
|
||||
static String imgFire = '$imagePath/img_fire.svg';
|
||||
|
||||
static String imgSearchWhiteA70020x20 =
|
||||
'$imagePath/img_search_white_a700_20x20.svg';
|
||||
|
||||
static String imgMenu = '$imagePath/img_menu.svg';
|
||||
|
||||
static String imgOverflowmenuWhiteA700 =
|
||||
'$imagePath/img_overflowmenu_white_a700.svg';
|
||||
|
||||
static String imgArrowleftBlueGray900 =
|
||||
'$imagePath/img_arrowleft_blue_gray_900.svg';
|
||||
static String bubbles = 'assets/icon/bubbles.svg';
|
||||
|
||||
static String close = 'assets/icon/close.svg';
|
||||
static String fail = 'assets/icon/fail.svg';
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import 'dart:convert';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class UserManager {
|
||||
static const String _userKey = 'user';
|
||||
static const String _accountKey = 'sys_account';
|
||||
static UserManager? _instance;
|
||||
static Map<String, dynamic>? _cachedUser;
|
||||
static Map<String, dynamic>? _cachedAccount;
|
||||
|
||||
// Private constructor for singleton
|
||||
UserManager._privateConstructor();
|
||||
|
||||
// Factory constructor to get the singleton instance
|
||||
factory UserManager() {
|
||||
_instance ??= UserManager._privateConstructor();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
// Initialize and load user data
|
||||
Future<void> initialize() async {
|
||||
if (_cachedUser == null) {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final userData = prefs.getString(_userKey);
|
||||
if (userData != null) {
|
||||
_cachedUser = jsonDecode(userData) as Map<String, dynamic>;
|
||||
}
|
||||
}
|
||||
if (_cachedAccount == null) {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final accountData = prefs.getString(_accountKey);
|
||||
if (accountData != null) {
|
||||
_cachedAccount = jsonDecode(accountData) as Map<String, dynamic>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accessor for user token
|
||||
String? get token {
|
||||
return _cachedUser?['token'];
|
||||
}
|
||||
|
||||
// Accessor for user name
|
||||
String? get userName {
|
||||
return _cachedUser?['fullname'];
|
||||
}
|
||||
|
||||
// Accessor for user email
|
||||
String? get email {
|
||||
return _cachedUser?['email'];
|
||||
}
|
||||
|
||||
// Accessor for user id
|
||||
int? get userId {
|
||||
return _cachedUser?['userId'];
|
||||
}
|
||||
|
||||
// Accessor for user roles (Assuming it's a list of roles in the user data)
|
||||
List<String>? get roles {
|
||||
if (_cachedUser?['roles'] != null) {
|
||||
return List<String>.from(_cachedUser!['roles']);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Save user data and cache it
|
||||
Future<void> setUser(Map<String, dynamic> user) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final userData = jsonEncode(user);
|
||||
await prefs.setString(_userKey, userData);
|
||||
_cachedUser = user; // Update cache
|
||||
}
|
||||
|
||||
// Save account data and cache it
|
||||
Future<void> setAccount(Map<String, dynamic> account) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final accountData = jsonEncode(account);
|
||||
await prefs.setString(_accountKey, accountData);
|
||||
_cachedAccount = account;
|
||||
}
|
||||
|
||||
Map<String, dynamic>? get account => _cachedAccount;
|
||||
|
||||
String? get accountId {
|
||||
final id = _cachedAccount?['account_id'] ?? _cachedAccount?['id'];
|
||||
return id?.toString();
|
||||
}
|
||||
|
||||
// Clear user data and cache
|
||||
Future<void> clearUser() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
await prefs.remove(_userKey);
|
||||
await prefs.remove(_accountKey);
|
||||
await prefs.remove('isLoggedIn');
|
||||
await prefs.clear();
|
||||
_cachedUser = null; // Clear cache
|
||||
_cachedAccount = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// This is where the magic happens.
|
||||
// This functions are responsible to make UI responsive across all the mobile devices.
|
||||
|
||||
Size size = WidgetsBinding.instance.window.physicalSize /
|
||||
WidgetsBinding.instance.window.devicePixelRatio;
|
||||
|
||||
// Caution! If you think these are static values and are used to build a static UI, you mustn’t.
|
||||
// These are the Viewport values of your Figma Design.
|
||||
// These are used in the code as a reference to create your UI Responsively.
|
||||
const num FIGMA_DESIGN_WIDTH = 428;
|
||||
const num FIGMA_DESIGN_HEIGHT = 926;
|
||||
const num FIGMA_DESIGN_STATUS_BAR = 47;
|
||||
|
||||
///This method is used to get device viewport width.
|
||||
get width {
|
||||
return size.width;
|
||||
}
|
||||
|
||||
///This method is used to get device viewport height.
|
||||
get height {
|
||||
num statusBar =
|
||||
MediaQueryData.fromView(WidgetsBinding.instance.window).viewPadding.top;
|
||||
num bottomBar = MediaQueryData.fromView(WidgetsBinding.instance.window)
|
||||
.viewPadding
|
||||
.bottom;
|
||||
num screenHeight = size.height - statusBar - bottomBar;
|
||||
return screenHeight;
|
||||
}
|
||||
|
||||
///This method is used to set padding/margin (for the left and Right side) & width of the screen or widget according to the Viewport width.
|
||||
double getHorizontalSize(double px) {
|
||||
return ((px * width) / FIGMA_DESIGN_WIDTH);
|
||||
}
|
||||
|
||||
///This method is used to set padding/margin (for the top and bottom side) & height of the screen or widget according to the Viewport height.
|
||||
double getVerticalSize(double px) {
|
||||
return ((px * height) / (FIGMA_DESIGN_HEIGHT - FIGMA_DESIGN_STATUS_BAR));
|
||||
}
|
||||
|
||||
///This method is used to set smallest px in image height and width
|
||||
double getSize(double px) {
|
||||
var height = getVerticalSize(px);
|
||||
var width = getHorizontalSize(px);
|
||||
if (height < width) {
|
||||
return height.toInt().toDouble();
|
||||
} else {
|
||||
return width.toInt().toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
///This method is used to set text font size according to Viewport
|
||||
double getFontSize(double px) {
|
||||
return getSize(px);
|
||||
}
|
||||
|
||||
///This method is used to set padding responsively
|
||||
EdgeInsetsGeometry getPadding({
|
||||
double? all,
|
||||
double? left,
|
||||
double? top,
|
||||
double? right,
|
||||
double? bottom,
|
||||
}) {
|
||||
return getMarginOrPadding(
|
||||
all: all,
|
||||
left: left,
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
);
|
||||
}
|
||||
|
||||
///This method is used to set margin responsively
|
||||
EdgeInsetsGeometry getMargin({
|
||||
double? all,
|
||||
double? left,
|
||||
double? top,
|
||||
double? right,
|
||||
double? bottom,
|
||||
}) {
|
||||
return getMarginOrPadding(
|
||||
all: all,
|
||||
left: left,
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
);
|
||||
}
|
||||
|
||||
///This method is used to get padding or margin responsively
|
||||
EdgeInsetsGeometry getMarginOrPadding({
|
||||
double? all,
|
||||
double? left,
|
||||
double? top,
|
||||
double? right,
|
||||
double? bottom,
|
||||
}) {
|
||||
if (all != null) {
|
||||
left = all;
|
||||
top = all;
|
||||
right = all;
|
||||
bottom = all;
|
||||
}
|
||||
return EdgeInsets.only(
|
||||
left: getHorizontalSize(
|
||||
left ?? 0,
|
||||
),
|
||||
top: getVerticalSize(
|
||||
top ?? 0,
|
||||
),
|
||||
right: getHorizontalSize(
|
||||
right ?? 0,
|
||||
),
|
||||
bottom: getVerticalSize(
|
||||
bottom ?? 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import 'package:base_project/resources/app_colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
class ToastMessageUtil {
|
||||
static void showToast({
|
||||
required String message,
|
||||
ToastType toastType = ToastType.info,
|
||||
ToastGravity gravity = ToastGravity.TOP,
|
||||
int durationInSeconds = 2,
|
||||
}) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: gravity,
|
||||
timeInSecForIosWeb: durationInSeconds,
|
||||
backgroundColor: _getBackgroundColor(toastType),
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
static Color? _getBackgroundColor(ToastType toastType) {
|
||||
switch (toastType) {
|
||||
case ToastType.success:
|
||||
return AppColors.success;
|
||||
case ToastType.error:
|
||||
return AppColors.error;
|
||||
case ToastType.warning:
|
||||
return AppColors.warning;
|
||||
case ToastType.info:
|
||||
return AppColors.info;
|
||||
case ToastType.general:
|
||||
return Colors.grey[900];
|
||||
default:
|
||||
return AppColors.info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ToastType { success, error, warning, info, general }
|
||||
@@ -0,0 +1,54 @@
|
||||
class TextFieldValidator {
|
||||
// Email validation using RegExp for strict validation
|
||||
static String? validateEmail(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Email is required';
|
||||
}
|
||||
|
||||
// Strict email pattern
|
||||
String pattern =
|
||||
r"^[a-zA-Z0-9]+([._-]?[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([._-]?[a-zA-Z0-9]+)*\.[a-zA-Z]{2,7}$";
|
||||
RegExp regex = RegExp(pattern);
|
||||
|
||||
if (!regex.hasMatch(value)) {
|
||||
return 'Enter a valid email address';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Simple field validation (non-empty check)
|
||||
static String? validateField(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'This field is required';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Password validation (simple length check, can be expanded for complexity)
|
||||
static String? validatePassword(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Password is required';
|
||||
}
|
||||
|
||||
// Minimum 8 characters check
|
||||
// if (value.length < 8) {
|
||||
// return 'Password must be at least 8 characters long';
|
||||
// }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Confirm password validation
|
||||
static String? validateConfirmPassword(String? value, String? password) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Confirm password is required';
|
||||
}
|
||||
|
||||
if (value != password) {
|
||||
return 'Passwords do not match';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user