updated packages
This commit is contained in:
parent
03a3c1e06c
commit
1279b0e00f
@ -1,4 +1,4 @@
|
|||||||
# On Field Work
|
# OnFieldWork.com
|
||||||
|
|
||||||
A new Flutter project.
|
A new Flutter project.
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,7 @@ android {
|
|||||||
// Specify your unique Application ID. This identifies your app on Google Play.
|
// Specify your unique Application ID. This identifies your app on Google Play.
|
||||||
applicationId = "com.marcoonfieldwork.aiot"
|
applicationId = "com.marcoonfieldwork.aiot"
|
||||||
// Set minimum and target SDK versions based on Flutter's configuration
|
// Set minimum and target SDK versions based on Flutter's configuration
|
||||||
minSdk = 23
|
minSdkVersion = flutter.minSdkVersion
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
// Set version code and name based on Flutter's configuration (from pubspec.yaml)
|
// Set version code and name based on Flutter's configuration (from pubspec.yaml)
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="On Field Work"
|
android:label="OnFieldWork.com"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
|
||||||
@ -18,7 +18,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "8.6.0" apply false
|
id "com.android.application" version "8.9.1" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "2.2.21" apply false
|
id "org.jetbrains.kotlin.android" version "2.2.21" apply false
|
||||||
id("com.google.gms.google-services") version "4.4.2" apply false
|
id("com.google.gms.google-services") version "4.4.2" apply false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ YELLOW='\033[1;33m'
|
|||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
# App info
|
# App info
|
||||||
APP_NAME="On Field Work"
|
APP_NAME="OnFieldWork.com"
|
||||||
BUILD_DIR="build/app/outputs"
|
BUILD_DIR="build/app/outputs"
|
||||||
|
|
||||||
echo -e "${CYAN}🚀 Starting Flutter build script for $APP_NAME...${NC}"
|
echo -e "${CYAN}🚀 Starting Flutter build script for $APP_NAME...${NC}"
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>On Field Work</string>
|
<string>OnFieldWork.com</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
|||||||
@ -8,5 +8,5 @@ class AppConstant {
|
|||||||
static int iOSAppVersion = 1;
|
static int iOSAppVersion = 1;
|
||||||
static String version = "1.0.0";
|
static String version = "1.0.0";
|
||||||
|
|
||||||
static String get appName => 'On Field Work';
|
static String get appName => 'OnFieldWork.com';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import 'package:on_field_work/helpers/services/storage/local_storage.dart';
|
|||||||
import 'package:on_field_work/controller/permission_controller.dart';
|
import 'package:on_field_work/controller/permission_controller.dart';
|
||||||
|
|
||||||
class TenantSelectionController extends GetxController {
|
class TenantSelectionController extends GetxController {
|
||||||
|
|
||||||
// Tenant list
|
// Tenant list
|
||||||
final tenants = <Tenant>[].obs;
|
final tenants = <Tenant>[].obs;
|
||||||
|
|
||||||
@ -35,6 +34,7 @@ class TenantSelectionController extends GetxController {
|
|||||||
if (data == null || data.isEmpty) {
|
if (data == null || data.isEmpty) {
|
||||||
tenants.clear();
|
tenants.clear();
|
||||||
logSafe("⚠️ No tenants found for the user.", level: LogLevel.warning);
|
logSafe("⚠️ No tenants found for the user.", level: LogLevel.warning);
|
||||||
|
await LocalStorage.logout();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,7 +181,8 @@ class AuthService {
|
|||||||
_wrapErrorHandling(
|
_wrapErrorHandling(
|
||||||
() async {
|
() async {
|
||||||
final employeeInfo = await LocalStorage.getEmployeeInfo();
|
final employeeInfo = await LocalStorage.getEmployeeInfo();
|
||||||
if (employeeInfo == null) return null; // Fails immediately if info is missing
|
if (employeeInfo == null)
|
||||||
|
return null; // Fails immediately if info is missing
|
||||||
final token = await LocalStorage.getJwtToken();
|
final token = await LocalStorage.getJwtToken();
|
||||||
|
|
||||||
final responseData = await _networkRequest(
|
final responseData = await _networkRequest(
|
||||||
@ -302,8 +303,7 @@ class AuthService {
|
|||||||
|
|
||||||
// Fallback on all other failures
|
// Fallback on all other failures
|
||||||
if (data != null && data['statusCode'] != 401) {
|
if (data != null && data['statusCode'] != 401) {
|
||||||
_handleApiError(
|
_handleApiError(data['statusCode'], data, "Fetching tenants");
|
||||||
data['statusCode'], data, "Fetching tenants");
|
|
||||||
} else if (data?['statusCode'] == 401 && hasRetried) {
|
} else if (data?['statusCode'] == 401 && hasRetried) {
|
||||||
await _handleUnauthorized();
|
await _handleUnauthorized();
|
||||||
}
|
}
|
||||||
@ -385,33 +385,37 @@ class AuthService {
|
|||||||
authToken: token,
|
authToken: token,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (data != null && data['success'] == true && data['data'] is Map<String, dynamic>) {
|
if (data != null &&
|
||||||
final responseData = data['data'] as Map<String, dynamic>;
|
data['success'] == true &&
|
||||||
|
data['data'] is Map<String, dynamic>) {
|
||||||
|
final responseData = data['data'] as Map<String, dynamic>;
|
||||||
|
|
||||||
final result = {
|
final result = {
|
||||||
'permissions': _parsePermissions(responseData['featurePermissions']),
|
'permissions': _parsePermissions(responseData['featurePermissions']),
|
||||||
'employeeInfo': await _parseEmployeeInfo(responseData['employeeInfo']),
|
'employeeInfo': await _parseEmployeeInfo(responseData['employeeInfo']),
|
||||||
'projects': _parseProjectsInfo(responseData['projects']),
|
'projects': _parseProjectsInfo(responseData['projects']),
|
||||||
};
|
};
|
||||||
|
|
||||||
_userDataCache[token] = result;
|
_userDataCache[token] = result;
|
||||||
logSafe("User data fetched and decrypted successfully.");
|
logSafe("User data fetched and decrypted successfully.");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle 401 Unauthorized via refreshToken/retry logic
|
// Handle 401 Unauthorized via refreshToken/retry logic
|
||||||
if (data?['statusCode'] == 401 && !hasRetried) {
|
if (data?['statusCode'] == 401 && !hasRetried) {
|
||||||
final refreshed = await refreshToken();
|
final refreshed = await refreshToken();
|
||||||
final newToken = await LocalStorage.getJwtToken();
|
final newToken = await LocalStorage.getJwtToken();
|
||||||
if (refreshed && newToken != null) {
|
if (refreshed && newToken != null) {
|
||||||
return fetchAllUserData(newToken, hasRetried: true);
|
return fetchAllUserData(newToken, hasRetried: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle failure and unauthorized
|
// Handle failure and unauthorized
|
||||||
if (data?['statusCode'] == 401 || data?['statusCode'] == 403 || data == null) {
|
if (data?['statusCode'] == 401 ||
|
||||||
await _handleUnauthorized();
|
data?['statusCode'] == 403 ||
|
||||||
throw Exception('Unauthorized or Network Error. Token refresh failed.');
|
data == null) {
|
||||||
|
await _handleUnauthorized();
|
||||||
|
throw Exception('Unauthorized or Network Error. Token refresh failed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final errorMsg = data['message'] ?? 'Unknown error';
|
final errorMsg = data['message'] ?? 'Unknown error';
|
||||||
@ -469,7 +473,6 @@ class AuthService {
|
|||||||
logSafe("❌ $context failed: $message [Status: $statusCode]", level: level);
|
logSafe("❌ $context failed: $message [Status: $statusCode]", level: level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// General network request handler for both GET and POST.
|
/// General network request handler for both GET and POST.
|
||||||
static Future<Map<String, dynamic>?> _networkRequest({
|
static Future<Map<String, dynamic>?> _networkRequest({
|
||||||
required String path,
|
required String path,
|
||||||
@ -490,8 +493,10 @@ class AuthService {
|
|||||||
level: LogLevel.info);
|
level: LogLevel.info);
|
||||||
|
|
||||||
if (method == _HttpMethod.post) {
|
if (method == _HttpMethod.post) {
|
||||||
response = await http.post(uri, headers: headers, body: jsonEncode(body));
|
response =
|
||||||
} else { // GET
|
await http.post(uri, headers: headers, body: jsonEncode(body));
|
||||||
|
} else {
|
||||||
|
// GET
|
||||||
response = await http.get(uri, headers: headers);
|
response = await http.get(uri, headers: headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,14 +506,23 @@ class AuthService {
|
|||||||
if (response.statusCode == 401) {
|
if (response.statusCode == 401) {
|
||||||
await _handleUnauthorized();
|
await _handleUnauthorized();
|
||||||
}
|
}
|
||||||
return {"statusCode": response.statusCode, "success": false, "message": "Empty response body"};
|
return {
|
||||||
|
"statusCode": response.statusCode,
|
||||||
|
"success": false,
|
||||||
|
"message": "Empty response body"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
final decrypted = decryptResponse(response.body);
|
final decrypted = decryptResponse(response.body);
|
||||||
|
|
||||||
if (decrypted == null) {
|
if (decrypted == null) {
|
||||||
logSafe("❌ Response decryption failed for $path", level: LogLevel.error);
|
logSafe("❌ Response decryption failed for $path",
|
||||||
return {"statusCode": response.statusCode, "success": false, "message": "Failed to decrypt response"};
|
level: LogLevel.error);
|
||||||
|
return {
|
||||||
|
"statusCode": response.statusCode,
|
||||||
|
"success": false,
|
||||||
|
"message": "Failed to decrypt response"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, dynamic> result = decrypted is Map<String, dynamic>
|
final Map<String, dynamic> result = decrypted is Map<String, dynamic>
|
||||||
@ -520,7 +534,6 @@ class AuthService {
|
|||||||
level: LogLevel.info);
|
level: LogLevel.info);
|
||||||
|
|
||||||
return {"statusCode": response.statusCode, ...result};
|
return {"statusCode": response.statusCode, ...result};
|
||||||
|
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
_handleError("$path ${method.name.toUpperCase()} error", e, st);
|
_handleError("$path ${method.name.toUpperCase()} error", e, st);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -25,7 +25,8 @@ int get flexColumns => MyScreenMedia.flexColumns;
|
|||||||
class MaterialRadius {
|
class MaterialRadius {
|
||||||
double xs, small, medium, large;
|
double xs, small, medium, large;
|
||||||
|
|
||||||
MaterialRadius({this.xs = 2, this.small = 4, this.medium = 6, this.large = 8});
|
MaterialRadius(
|
||||||
|
{this.xs = 2, this.small = 4, this.medium = 6, this.large = 8});
|
||||||
}
|
}
|
||||||
|
|
||||||
class ColorGroup {
|
class ColorGroup {
|
||||||
@ -41,10 +42,12 @@ class AppTheme {
|
|||||||
static Color primaryColor = Color(0xff663399);
|
static Color primaryColor = Color(0xff663399);
|
||||||
|
|
||||||
static ThemeData getThemeFromThemeMode() {
|
static ThemeData getThemeFromThemeMode() {
|
||||||
return ThemeCustomizer.instance.theme == ThemeMode.light ? lightTheme : darkTheme;
|
return ThemeCustomizer.instance.theme == ThemeMode.light
|
||||||
|
? lightTheme
|
||||||
|
: darkTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// -------------------------- Light Theme -------------------------------------------- ///
|
/// -------------------------- Light Theme -------------------------------------------- ///
|
||||||
|
|
||||||
static final ThemeData lightTheme = ThemeData(
|
static final ThemeData lightTheme = ThemeData(
|
||||||
/// Brightness
|
/// Brightness
|
||||||
@ -60,14 +63,18 @@ class AppTheme {
|
|||||||
|
|
||||||
/// AppBar Theme
|
/// AppBar Theme
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
backgroundColor: Color(0xffF5F5F5), iconTheme: IconThemeData(color: Color(0xff495057)), actionsIconTheme: IconThemeData(color: Color(0xff495057))),
|
backgroundColor: Color(0xffF5F5F5),
|
||||||
|
iconTheme: IconThemeData(color: Color(0xff495057)),
|
||||||
|
actionsIconTheme: IconThemeData(color: Color(0xff495057))),
|
||||||
|
|
||||||
/// Card Theme
|
/// Card Theme
|
||||||
cardTheme: CardTheme(color: Color(0xffffffff)),
|
// FIX: Use CardThemeData
|
||||||
|
cardTheme: CardThemeData(color: Color(0xffffffff)),
|
||||||
cardColor: Color(0xffffffff),
|
cardColor: Color(0xffffffff),
|
||||||
|
|
||||||
/// Colorscheme
|
/// Colorscheme
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Color(0xff663399), brightness: Brightness.light),
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: Color(0xff663399), brightness: Brightness.light),
|
||||||
|
|
||||||
snackBarTheme: SnackBarThemeData(actionTextColor: Colors.white),
|
snackBarTheme: SnackBarThemeData(actionTextColor: Colors.white),
|
||||||
|
|
||||||
@ -86,10 +93,12 @@ class AppTheme {
|
|||||||
dividerColor: Color(0xffdddddd),
|
dividerColor: Color(0xffdddddd),
|
||||||
|
|
||||||
/// Bottom AppBar Theme
|
/// Bottom AppBar Theme
|
||||||
bottomAppBarTheme: BottomAppBarTheme(color: Color(0xffeeeeee), elevation: 2),
|
// FIX: Use BottomAppBarThemeData
|
||||||
|
bottomAppBarTheme:
|
||||||
|
BottomAppBarThemeData(color: Color(0xffeeeeee), elevation: 2),
|
||||||
|
|
||||||
/// Tab bar Theme
|
/// Tab bar Theme
|
||||||
tabBarTheme: TabBarTheme(
|
tabBarTheme: TabBarThemeData(
|
||||||
unselectedLabelColor: Color(0xff495057),
|
unselectedLabelColor: Color(0xff495057),
|
||||||
labelColor: AppTheme.primaryColor,
|
labelColor: AppTheme.primaryColor,
|
||||||
indicatorSize: TabBarIndicatorSize.label,
|
indicatorSize: TabBarIndicatorSize.label,
|
||||||
@ -123,8 +132,11 @@ class AppTheme {
|
|||||||
checkColor: WidgetStateProperty.all(Color(0xffffffff)),
|
checkColor: WidgetStateProperty.all(Color(0xffffffff)),
|
||||||
fillColor: WidgetStateProperty.all(AppTheme.primaryColor),
|
fillColor: WidgetStateProperty.all(AppTheme.primaryColor),
|
||||||
),
|
),
|
||||||
switchTheme:
|
switchTheme: SwitchThemeData(
|
||||||
SwitchThemeData(thumbColor: WidgetStateProperty.resolveWith((states) => states.contains(WidgetState.selected) ? AppTheme.primaryColor : Colors.white)),
|
thumbColor: WidgetStateProperty.resolveWith((states) =>
|
||||||
|
states.contains(WidgetState.selected)
|
||||||
|
? AppTheme.primaryColor
|
||||||
|
: Colors.white)),
|
||||||
|
|
||||||
/// Other Colors
|
/// Other Colors
|
||||||
splashColor: Colors.white.withAlpha(100),
|
splashColor: Colors.white.withAlpha(100),
|
||||||
@ -132,8 +144,9 @@ class AppTheme {
|
|||||||
highlightColor: Color(0xffeeeeee),
|
highlightColor: Color(0xffeeeeee),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// -------------------------- Dark Theme -------------------------------------------- ///
|
/// -------------------------- Dark Theme -------------------------------------------- ///
|
||||||
static final ThemeData darkTheme = ThemeData.dark(useMaterial3: false).copyWith(
|
static final ThemeData darkTheme =
|
||||||
|
ThemeData.dark(useMaterial3: false).copyWith(
|
||||||
/// Brightness
|
/// Brightness
|
||||||
|
|
||||||
/// Scaffold and Background color
|
/// Scaffold and Background color
|
||||||
@ -146,7 +159,8 @@ class AppTheme {
|
|||||||
appBarTheme: AppBarTheme(backgroundColor: Color(0xff262729)),
|
appBarTheme: AppBarTheme(backgroundColor: Color(0xff262729)),
|
||||||
|
|
||||||
/// Card Theme
|
/// Card Theme
|
||||||
cardTheme: CardTheme(color: Color(0xff1b1b1c)),
|
// FIX: Use CardThemeData
|
||||||
|
cardTheme: CardThemeData(color: Color(0xff1b1b1c)),
|
||||||
cardColor: Color(0xff1b1b1c),
|
cardColor: Color(0xff1b1b1c),
|
||||||
|
|
||||||
/// Colorscheme
|
/// Colorscheme
|
||||||
@ -175,10 +189,13 @@ class AppTheme {
|
|||||||
foregroundColor: Colors.white),
|
foregroundColor: Colors.white),
|
||||||
|
|
||||||
/// Bottom AppBar Theme
|
/// Bottom AppBar Theme
|
||||||
bottomAppBarTheme: BottomAppBarTheme(color: Color(0xff464c52), elevation: 2),
|
// FIX: Use BottomAppBarThemeData
|
||||||
|
bottomAppBarTheme:
|
||||||
|
BottomAppBarThemeData(color: Color(0xff464c52), elevation: 2),
|
||||||
|
|
||||||
/// Tab bar Theme
|
/// Tab bar Theme
|
||||||
tabBarTheme: TabBarTheme(
|
// FIX: Use TabBarThemeData
|
||||||
|
tabBarTheme: TabBarThemeData(
|
||||||
unselectedLabelColor: Color(0xff495057),
|
unselectedLabelColor: Color(0xff495057),
|
||||||
labelColor: AppTheme.primaryColor,
|
labelColor: AppTheme.primaryColor,
|
||||||
indicatorSize: TabBarIndicatorSize.label,
|
indicatorSize: TabBarIndicatorSize.label,
|
||||||
@ -230,7 +247,8 @@ class AppStyle {
|
|||||||
containerRadius: AppStyle.containerRadius.medium,
|
containerRadius: AppStyle.containerRadius.medium,
|
||||||
cardRadius: AppStyle.cardRadius.medium,
|
cardRadius: AppStyle.cardRadius.medium,
|
||||||
buttonRadius: AppStyle.buttonRadius.medium,
|
buttonRadius: AppStyle.buttonRadius.medium,
|
||||||
defaultBreadCrumbItem: MyBreadcrumbItem(name: 'On Field Work', route: '/client/dashboard'),
|
defaultBreadCrumbItem:
|
||||||
|
MyBreadcrumbItem(name: 'OnFieldWork.com', route: '/client/dashboard'),
|
||||||
));
|
));
|
||||||
bool isMobile = true;
|
bool isMobile = true;
|
||||||
try {
|
try {
|
||||||
@ -241,12 +259,16 @@ class AppStyle {
|
|||||||
My.setFlexSpacing(isMobile ? 16 : 24);
|
My.setFlexSpacing(isMobile ? 16 : 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// -------------------------- Styles -------------------------------------------- ///
|
/// -------------------------- Styles -------------------------------------------- ///
|
||||||
|
|
||||||
static MaterialRadius buttonRadius = MaterialRadius(small: 2, medium: 4, large: 8);
|
static MaterialRadius buttonRadius =
|
||||||
static MaterialRadius cardRadius = MaterialRadius(xs: 2, small: 4, medium: 4, large: 8);
|
MaterialRadius(small: 2, medium: 4, large: 8);
|
||||||
static MaterialRadius containerRadius = MaterialRadius(xs: 2, small: 4, medium: 4, large: 8);
|
static MaterialRadius cardRadius =
|
||||||
static MaterialRadius imageRadius = MaterialRadius(xs: 2, small: 4, medium: 4, large: 8);
|
MaterialRadius(xs: 2, small: 4, medium: 4, large: 8);
|
||||||
|
static MaterialRadius containerRadius =
|
||||||
|
MaterialRadius(xs: 2, small: 4, medium: 4, large: 8);
|
||||||
|
static MaterialRadius imageRadius =
|
||||||
|
MaterialRadius(xs: 2, small: 4, medium: 4, large: 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppColors {
|
class AppColors {
|
||||||
@ -262,13 +284,16 @@ class AppColors {
|
|||||||
static ColorGroup orange = ColorGroup(Color(0xffFFCEC2), Color(0xffFF3B0A));
|
static ColorGroup orange = ColorGroup(Color(0xffFFCEC2), Color(0xffFF3B0A));
|
||||||
static ColorGroup skyBlue = ColorGroup(Color(0xffC2F0FF), Color(0xff0099CC));
|
static ColorGroup skyBlue = ColorGroup(Color(0xffC2F0FF), Color(0xff0099CC));
|
||||||
static ColorGroup lavender = ColorGroup(Color(0xffEAE2F3), Color(0xff7748AD));
|
static ColorGroup lavender = ColorGroup(Color(0xffEAE2F3), Color(0xff7748AD));
|
||||||
static ColorGroup queenPink = ColorGroup(Color(0xffE8D9DC), Color(0xff804D57));
|
static ColorGroup queenPink =
|
||||||
static ColorGroup blueViolet = ColorGroup(Color(0xffC5C6E7), Color(0xff3B3E91));
|
ColorGroup(Color(0xffE8D9DC), Color(0xff804D57));
|
||||||
|
static ColorGroup blueViolet =
|
||||||
|
ColorGroup(Color(0xffC5C6E7), Color(0xff3B3E91));
|
||||||
static ColorGroup rosePink = ColorGroup(Color(0xffFCB1E0), Color(0xffEC0999));
|
static ColorGroup rosePink = ColorGroup(Color(0xffFCB1E0), Color(0xffEC0999));
|
||||||
|
|
||||||
static ColorGroup rubinRed = ColorGroup(Color(0x98f6a8bd), Color(0xffd03760));
|
static ColorGroup rubinRed = ColorGroup(Color(0x98f6a8bd), Color(0xffd03760));
|
||||||
static ColorGroup favorite = rubinRed;
|
static ColorGroup favorite = rubinRed;
|
||||||
static ColorGroup redOrange = ColorGroup(Color(0xffFFAD99), Color(0xffF53100));
|
static ColorGroup redOrange =
|
||||||
|
ColorGroup(Color(0xffFFAD99), Color(0xffF53100));
|
||||||
|
|
||||||
static Color notificationSuccessBGColor = Color(0xff117E68);
|
static Color notificationSuccessBGColor = Color(0xff117E68);
|
||||||
static Color notificationSuccessTextColor = Color(0xffffffff);
|
static Color notificationSuccessTextColor = Color(0xffffffff);
|
||||||
@ -278,7 +303,16 @@ class AppColors {
|
|||||||
static Color notificationErrorTextColor = Color(0xffFF3B0A);
|
static Color notificationErrorTextColor = Color(0xffFF3B0A);
|
||||||
static Color notificationErrorActionColor = Color(0xff006784);
|
static Color notificationErrorActionColor = Color(0xff006784);
|
||||||
|
|
||||||
static List<ColorGroup> list = [redOrange, violet, blue, green, orange, skyBlue, lavender, blueViolet];
|
static List<ColorGroup> list = [
|
||||||
|
redOrange,
|
||||||
|
violet,
|
||||||
|
blue,
|
||||||
|
green,
|
||||||
|
orange,
|
||||||
|
skyBlue,
|
||||||
|
lavender,
|
||||||
|
blueViolet
|
||||||
|
];
|
||||||
|
|
||||||
static ColorGroup get random => list[Random().nextInt(list.length)];
|
static ColorGroup get random => list[Random().nextInt(list.length)];
|
||||||
|
|
||||||
@ -287,7 +321,13 @@ class AppColors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Color getColorByRating(int rating) {
|
static Color getColorByRating(int rating) {
|
||||||
var colors = {1: Color(0xfff0323c), 2: Color(0xcdf0323c), 3: star, 4: Color(0xcd3cd278), 5: Color(0xff3cd278)};
|
var colors = {
|
||||||
|
1: Color(0xfff0323c),
|
||||||
|
2: Color(0xcdf0323c),
|
||||||
|
3: star,
|
||||||
|
4: Color(0xcd3cd278),
|
||||||
|
5: Color(0xff3cd278)
|
||||||
|
};
|
||||||
|
|
||||||
return colors[rating] ?? colors[1]!;
|
return colors[rating] ?? colors[1]!;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,8 @@ import 'package:on_field_work/helpers/utils/permission_constants.dart';
|
|||||||
import 'package:on_field_work/helpers/widgets/avatar.dart';
|
import 'package:on_field_work/helpers/widgets/avatar.dart';
|
||||||
import 'package:on_field_work/helpers/widgets/dashbaord/expense_breakdown_chart.dart';
|
import 'package:on_field_work/helpers/widgets/dashbaord/expense_breakdown_chart.dart';
|
||||||
import 'package:on_field_work/helpers/widgets/dashbaord/expense_by_status_widget.dart';
|
import 'package:on_field_work/helpers/widgets/dashbaord/expense_by_status_widget.dart';
|
||||||
import 'package:on_field_work/helpers/widgets/dashbaord/collection_dashboard_card.dart';
|
// import 'package:on_field_work/helpers/widgets/dashbaord/collection_dashboard_card.dart'; // Unused
|
||||||
import 'package:on_field_work/helpers/widgets/dashbaord/purchase_invoice_dashboard.dart';
|
// import 'package:on_field_work/helpers/widgets/dashbaord/purchase_invoice_dashboard.dart'; // Unused
|
||||||
import 'package:on_field_work/helpers/widgets/dashbaord/monthly_expense_dashboard_chart.dart';
|
import 'package:on_field_work/helpers/widgets/dashbaord/monthly_expense_dashboard_chart.dart';
|
||||||
import 'package:on_field_work/helpers/widgets/my_custom_skeleton.dart';
|
import 'package:on_field_work/helpers/widgets/my_custom_skeleton.dart';
|
||||||
import 'package:on_field_work/helpers/widgets/my_spacing.dart';
|
import 'package:on_field_work/helpers/widgets/my_spacing.dart';
|
||||||
@ -80,7 +80,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
Widget _sectionTitle(String title) {
|
Widget _sectionTitle(String title) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 4, bottom: 8),
|
padding: const EdgeInsets.only(left: 4, bottom: 8),
|
||||||
// OPTIMIZATION: Use MyText for consistent styling
|
|
||||||
child: MyText.titleMedium(
|
child: MyText.titleMedium(
|
||||||
title,
|
title,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
@ -127,12 +126,13 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.info_outline, size: 30, color: Colors.white),
|
const Icon(Icons.info_outline,
|
||||||
|
size: 30, color: Colors.white),
|
||||||
MySpacing.width(10),
|
MySpacing.width(10),
|
||||||
Expanded(
|
const Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"No attendance data available yet.",
|
"No attendance data available yet.",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -142,9 +142,9 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
MySpacing.height(12),
|
MySpacing.height(12),
|
||||||
Text(
|
const Text(
|
||||||
"You are not added to this project or attendance data is not available.",
|
"You are not added to this project or attendance data is not available.",
|
||||||
style: const TextStyle(color: Colors.white70, fontSize: 13),
|
style: TextStyle(color: Colors.white70, fontSize: 13),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -215,7 +215,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
MySpacing.height(12), // OPTIMIZED
|
MySpacing.height(12),
|
||||||
Text(
|
Text(
|
||||||
infoText,
|
infoText,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@ -223,7 +223,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
MySpacing.height(12), // OPTIMIZED
|
MySpacing.height(12),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
@ -262,7 +262,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
|
|
||||||
final bool projectSelected = projectController.selectedProject != null;
|
final bool projectSelected = projectController.selectedProject != null;
|
||||||
|
|
||||||
// These are String constants from permission_constants.dart (kept outside of Obx)
|
|
||||||
const List<String> cardOrder = [
|
const List<String> cardOrder = [
|
||||||
MenuItems.attendance,
|
MenuItems.attendance,
|
||||||
MenuItems.employees,
|
MenuItems.employees,
|
||||||
@ -273,7 +272,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
MenuItems.infraProjects,
|
MenuItems.infraProjects,
|
||||||
];
|
];
|
||||||
|
|
||||||
// OPTIMIZATION: Using a static map for meta data
|
|
||||||
final Map<String, _DashboardCardMeta> meta = {
|
final Map<String, _DashboardCardMeta> meta = {
|
||||||
MenuItems.attendance:
|
MenuItems.attendance:
|
||||||
_DashboardCardMeta(LucideIcons.scan_face, contentTheme.success),
|
_DashboardCardMeta(LucideIcons.scan_face, contentTheme.success),
|
||||||
@ -291,7 +289,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
_DashboardCardMeta(LucideIcons.building_2, contentTheme.primary),
|
_DashboardCardMeta(LucideIcons.building_2, contentTheme.primary),
|
||||||
};
|
};
|
||||||
|
|
||||||
// OPTIMIZATION: Use map for faster lookup, then filter the preferred order
|
|
||||||
final Map<String, dynamic> allowed = {
|
final Map<String, dynamic> allowed = {
|
||||||
for (final m in menuController.menuItems)
|
for (final m in menuController.menuItems)
|
||||||
if (m.available && meta.containsKey(m.id)) m.id: m,
|
if (m.available && meta.containsKey(m.id)) m.id: m,
|
||||||
@ -308,8 +305,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
_sectionTitle(
|
_sectionTitle('Modules'),
|
||||||
'Modules'), // OPTIMIZATION: Reused section title helper
|
|
||||||
if (!projectSelected)
|
if (!projectSelected)
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@ -334,7 +330,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
),
|
),
|
||||||
GridView.builder(
|
GridView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(), // Important!
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 2),
|
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 2),
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
@ -394,7 +390,7 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
color:
|
color:
|
||||||
isEnabled ? cardMeta.color : Colors.grey.shade300,
|
isEnabled ? cardMeta.color : Colors.grey.shade300,
|
||||||
),
|
),
|
||||||
MySpacing.height(6), // OPTIMIZED
|
MySpacing.height(6),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -521,7 +517,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const TextField(
|
const TextField(
|
||||||
// OPTIMIZED: Added const
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Search project...',
|
hintText: 'Search project...',
|
||||||
isDense: true,
|
isDense: true,
|
||||||
@ -557,8 +552,9 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Build
|
// Build (MODIFIED FOR FIXED HEADER)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -566,34 +562,39 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xfff5f6fa),
|
backgroundColor: const Color(0xfff5f6fa),
|
||||||
body: Layout(
|
body: Layout(
|
||||||
child: SingleChildScrollView(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_projectSelector(),
|
_projectSelector(),
|
||||||
MySpacing.height(20),
|
MySpacing.height(20),
|
||||||
_quickActions(),
|
Expanded(
|
||||||
MySpacing.height(20),
|
child: SingleChildScrollView(
|
||||||
_dashboardModules(),
|
child: Column(
|
||||||
MySpacing.height(20),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
_sectionTitle('Reports & Analytics'),
|
children: [
|
||||||
const CompactPurchaseInvoiceDashboard(),
|
_quickActions(),
|
||||||
MySpacing.height(20),
|
MySpacing.height(20),
|
||||||
CollectionsHealthWidget(),
|
_dashboardModules(),
|
||||||
MySpacing.height(20),
|
MySpacing.height(20),
|
||||||
_cardWrapper(
|
_sectionTitle('Reports & Analytics'),
|
||||||
child: ExpenseTypeReportChart(),
|
_cardWrapper(
|
||||||
),
|
child: ExpenseTypeReportChart(),
|
||||||
_cardWrapper(
|
),
|
||||||
child: ExpenseByStatusWidget(
|
_cardWrapper(
|
||||||
controller: dashboardController,
|
child: ExpenseByStatusWidget(
|
||||||
|
controller: dashboardController,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_cardWrapper(
|
||||||
|
child: MonthlyExpenseDashboardChart(),
|
||||||
|
),
|
||||||
|
MySpacing.height(20),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_cardWrapper(
|
|
||||||
child: MonthlyExpenseDashboardChart(),
|
|
||||||
),
|
|
||||||
MySpacing.height(20),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -24,7 +24,6 @@ class Layout extends StatefulWidget {
|
|||||||
class _LayoutState extends State<Layout> with UIMixin {
|
class _LayoutState extends State<Layout> with UIMixin {
|
||||||
final LayoutController controller = LayoutController();
|
final LayoutController controller = LayoutController();
|
||||||
final EmployeeInfo? employeeInfo = LocalStorage.getEmployeeInfo();
|
final EmployeeInfo? employeeInfo = LocalStorage.getEmployeeInfo();
|
||||||
final bool isBetaEnvironment = ApiEndpoints.baseUrl.contains("stage");
|
|
||||||
|
|
||||||
bool hasMpin = true;
|
bool hasMpin = true;
|
||||||
|
|
||||||
@ -46,72 +45,69 @@ class _LayoutState extends State<Layout> with UIMixin {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MyResponsive(builder: (context, _, screenMT) {
|
return MyResponsive(builder: (context, _, screenMT) {
|
||||||
return GetBuilder(
|
return GetBuilder<LayoutController>(
|
||||||
init: controller,
|
init: controller,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return (screenMT.isMobile || screenMT.isTablet)
|
return _buildScaffold(context);
|
||||||
? _buildScaffold(context, isMobile: true)
|
|
||||||
: _buildScaffold(context);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildScaffold(BuildContext context, {bool isMobile = false}) {
|
Widget _buildScaffold(BuildContext context) {
|
||||||
final primaryColor = contentTheme.primary;
|
final primaryColor = contentTheme.primary;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
key: controller.scaffoldKey,
|
key: controller.scaffoldKey,
|
||||||
endDrawer: const UserProfileBar(),
|
endDrawer: const UserProfileBar(),
|
||||||
floatingActionButton: widget.floatingActionButton,
|
floatingActionButton: widget.floatingActionButton,
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
// Solid primary background area
|
Container(
|
||||||
Container(
|
width: double.infinity,
|
||||||
|
color: primaryColor,
|
||||||
|
child: _buildHeaderContent(),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
color: primaryColor,
|
decoration: BoxDecoration(
|
||||||
child: _buildHeaderContent(isMobile),
|
gradient: LinearGradient(
|
||||||
),
|
begin: Alignment.topCenter,
|
||||||
Expanded(
|
end: Alignment.bottomCenter,
|
||||||
child: Container(
|
colors: [
|
||||||
width: double.infinity,
|
primaryColor,
|
||||||
decoration: BoxDecoration(
|
primaryColor.withOpacity(0.7),
|
||||||
gradient: LinearGradient(
|
primaryColor.withOpacity(0.0),
|
||||||
begin: Alignment.topCenter,
|
],
|
||||||
end: Alignment.bottomCenter,
|
stops: const [0.0, 0.1, 0.3],
|
||||||
colors: [
|
|
||||||
primaryColor,
|
|
||||||
primaryColor.withOpacity(0.7),
|
|
||||||
primaryColor.withOpacity(0.0),
|
|
||||||
],
|
|
||||||
stops: const [0.0, 0.1, 0.3],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
),
|
||||||
top: false,
|
child: SafeArea(
|
||||||
child: GestureDetector(
|
top: false,
|
||||||
behavior: HitTestBehavior.translucent,
|
child: GestureDetector(
|
||||||
onTap: () {},
|
behavior: HitTestBehavior.translucent,
|
||||||
child: SingleChildScrollView(
|
onTap: () =>
|
||||||
key: controller.scrollKey,
|
FocusScope.of(context).unfocus(),
|
||||||
padding: EdgeInsets.zero,
|
child: widget.child ??
|
||||||
child: widget.child,
|
const SizedBox.shrink(),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
));
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHeaderContent(bool isMobile) {
|
Widget _buildHeaderContent() {
|
||||||
final selectedTenant = AuthService.currentTenant;
|
final selectedTenant = AuthService.currentTenant;
|
||||||
|
final bool isBeta = ApiEndpoints.baseUrl.contains("stage");
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 45, 10, 0),
|
padding: const EdgeInsets.fromLTRB(10, 45, 10, 0),
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.only(bottom: 18),
|
margin: const EdgeInsets.only(bottom: 10),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -139,7 +135,7 @@ class _LayoutState extends State<Layout> with UIMixin {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Beta badge
|
// Beta badge
|
||||||
if (ApiEndpoints.baseUrl.contains("stage"))
|
if (isBeta)
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|||||||
23
pubspec.yaml
23
pubspec.yaml
@ -46,15 +46,15 @@ dependencies:
|
|||||||
carousel_slider: ^5.0.0
|
carousel_slider: ^5.0.0
|
||||||
reorderable_grid: ^1.0.10
|
reorderable_grid: ^1.0.10
|
||||||
loading_animation_widget: ^1.3.0
|
loading_animation_widget: ^1.3.0
|
||||||
intl: ^0.19.0
|
intl: ^0.20.2
|
||||||
syncfusion_flutter_core: ^29.1.40
|
syncfusion_flutter_core: ^31.2.18
|
||||||
syncfusion_flutter_sliders: ^29.1.40
|
syncfusion_flutter_sliders: ^31.2.18
|
||||||
file_picker: ^10.3.2
|
file_picker: ^10.3.2
|
||||||
timelines_plus: ^1.0.4
|
timelines_plus: ^1.0.4
|
||||||
syncfusion_flutter_charts: ^29.1.40
|
syncfusion_flutter_charts: ^31.2.18
|
||||||
appflowy_board: ^0.1.2
|
appflowy_board: ^0.1.2
|
||||||
syncfusion_flutter_calendar: ^29.1.40
|
syncfusion_flutter_calendar: ^31.2.18
|
||||||
syncfusion_flutter_maps: ^29.1.40
|
syncfusion_flutter_maps: ^31.2.18
|
||||||
http: ^1.6.0
|
http: ^1.6.0
|
||||||
geolocator: ^14.0.2
|
geolocator: ^14.0.2
|
||||||
permission_handler: ^12.0.1
|
permission_handler: ^12.0.1
|
||||||
@ -71,13 +71,13 @@ dependencies:
|
|||||||
font_awesome_flutter: ^10.8.0
|
font_awesome_flutter: ^10.8.0
|
||||||
flutter_html: ^3.0.0
|
flutter_html: ^3.0.0
|
||||||
tab_indicator_styler: ^2.0.0
|
tab_indicator_styler: ^2.0.0
|
||||||
connectivity_plus: ^6.1.4
|
connectivity_plus: ^7.0.0
|
||||||
geocoding: ^4.0.0
|
geocoding: ^4.0.0
|
||||||
firebase_core: ^4.0.0
|
firebase_core: ^4.0.0
|
||||||
firebase_messaging: ^16.0.0
|
firebase_messaging: ^16.0.0
|
||||||
googleapis_auth: ^2.0.0
|
googleapis_auth: ^2.0.0
|
||||||
device_info_plus: ^11.3.0
|
device_info_plus: ^12.3.0
|
||||||
flutter_local_notifications: 19.4.0
|
flutter_local_notifications: ^19.5.0
|
||||||
equatable: ^2.0.7
|
equatable: ^2.0.7
|
||||||
mime: ^2.0.0
|
mime: ^2.0.0
|
||||||
timeago: ^3.7.1
|
timeago: ^3.7.1
|
||||||
@ -97,7 +97,7 @@ dev_dependencies:
|
|||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^5.0.0
|
flutter_lints: ^6.0.0
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
@ -150,6 +150,3 @@ flutter:
|
|||||||
#
|
#
|
||||||
# For details regarding fonts from package dependencies,
|
# For details regarding fonts from package dependencies,
|
||||||
# see https://flutter.dev/to/font-from-package
|
# see https://flutter.dev/to/font-from-package
|
||||||
|
|
||||||
dependency_overrides:
|
|
||||||
http: ^1.6.0
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user