Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
Pulse Application
Commits
f96fa9c8
Commit
f96fa9c8
authored
Oct 13, 2025
by
Sai Srinivas
Committed by
Sai Srinivas
Oct 13, 2025
Browse files
Firebase and Haptic
parent
7f695622
Changes
17
Hide whitespace changes
Inline
Side-by-side
android/app/build.gradle.kts
View file @
f96fa9c8
...
@@ -6,6 +6,7 @@ plugins {
...
@@ -6,6 +6,7 @@ plugins {
id
(
"kotlin-android"
)
id
(
"kotlin-android"
)
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id
(
"dev.flutter.flutter-gradle-plugin"
)
id
(
"dev.flutter.flutter-gradle-plugin"
)
id
(
"com.google.gms.google-services"
)
}
}
val
localProperties
=
Properties
()
val
localProperties
=
Properties
()
val
localPropertiesFile
=
rootProject
.
file
(
"local.properties"
)
val
localPropertiesFile
=
rootProject
.
file
(
"local.properties"
)
...
@@ -31,6 +32,8 @@ android {
...
@@ -31,6 +32,8 @@ android {
compileOptions
{
compileOptions
{
sourceCompatibility
=
JavaVersion
.
VERSION_11
sourceCompatibility
=
JavaVersion
.
VERSION_11
targetCompatibility
=
JavaVersion
.
VERSION_11
targetCompatibility
=
JavaVersion
.
VERSION_11
isCoreLibraryDesugaringEnabled
=
true
}
}
kotlinOptions
{
kotlinOptions
{
...
@@ -38,16 +41,15 @@ android {
...
@@ -38,16 +41,15 @@ android {
}
}
defaultConfig
{
defaultConfig
{
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId
=
"in.webgrid.pulse"
applicationId
=
"in.webgrid.pulse"
// You can update the following values to match your application needs.
// Firebase Messaging requires minSdk >= 23
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk
=
maxOf
(
flutter
.
minSdkVersion
,
23
)
minSdk
=
flutter
.
minSdkVersion
targetSdk
=
flutter
.
targetSdkVersion
targetSdk
=
flutter
.
targetSdkVersion
versionCode
=
flutter
.
versionCode
versionCode
=
flutter
.
versionCode
versionName
=
flutter
.
versionName
versionName
=
flutter
.
versionName
}
}
signingConfigs
{
signingConfigs
{
create
(
"release"
)
{
create
(
"release"
)
{
keyAlias
=
keystoreProperties
[
"keyAlias"
]
?.
toString
()
keyAlias
=
keystoreProperties
[
"keyAlias"
]
?.
toString
()
...
@@ -64,8 +66,15 @@ android {
...
@@ -64,8 +66,15 @@ android {
signingConfig
=
signingConfigs
.
getByName
(
"release"
)
signingConfig
=
signingConfigs
.
getByName
(
"release"
)
}
}
}
}
}
}
flutter
{
flutter
{
source
=
"../.."
source
=
"../.."
}
}
dependencies
{
implementation
(
"org.jetbrains.kotlin:kotlin-stdlib-jdk8"
)
coreLibraryDesugaring
(
"com.android.tools:desugar_jdk_libs:2.0.4"
)
}
android/app/google-services.json
0 → 100644
View file @
f96fa9c8
{
"project_info"
:
{
"project_number"
:
"207322820833"
,
"project_id"
:
"pulse-5cf9a"
,
"storage_bucket"
:
"pulse-5cf9a.firebasestorage.app"
},
"client"
:
[
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:207322820833:android:22a997a4a1d64fb04447a0"
,
"android_client_info"
:
{
"package_name"
:
"com.webgrid.pulse"
}
},
"oauth_client"
:
[],
"api_key"
:
[
{
"current_key"
:
"AIzaSyCKS1W1HGZsOEbkTM0tmW-Qgo4VA4KoO2c"
}
],
"services"
:
{
"appinvite_service"
:
{
"other_platform_oauth_client"
:
[]
}
}
},
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:207322820833:android:82516ed462f6ae6e4447a0"
,
"android_client_info"
:
{
"package_name"
:
"in.webgrid.pulse"
}
},
"oauth_client"
:
[],
"api_key"
:
[
{
"current_key"
:
"AIzaSyCKS1W1HGZsOEbkTM0tmW-Qgo4VA4KoO2c"
}
],
"services"
:
{
"appinvite_service"
:
{
"other_platform_oauth_client"
:
[]
}
}
}
],
"configuration_version"
:
"1"
}
\ No newline at end of file
android/app/src/main/AndroidManifest.xml
View file @
f96fa9c8
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.ACCESS_NETWORK_STATE"
/>
<uses-permission
android:name=
"android.permission.ACCESS_NETWORK_STATE"
/>
<uses-permission
android:name=
"android.permission.POST_NOTIFICATIONS"
/>
<uses-permission
android:name=
"android.permission.WAKE_LOCK"
/>
<uses-permission
android:name=
"android.permission.VIBRATE"
/>
<application
<application
android:label=
"Web Grid Pulse"
android:label=
"Web Grid Pulse"
...
@@ -34,6 +37,27 @@
...
@@ -34,6 +37,27 @@
<meta-data
<meta-data
android:name=
"flutterEmbedding"
android:name=
"flutterEmbedding"
android:value=
"2"
/>
android:value=
"2"
/>
<!-- Firebase Messaging service -->
<service
android:name=
"io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService"
android:exported=
"false"
>
<intent-filter>
<action
android:name=
"com.google.firebase.MESSAGING_EVENT"
/>
</intent-filter>
</service>
<!-- Handle background messaging -->
<service
android:name=
"io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingBackgroundService"
android:exported=
"false"
/>
<!-- Needed for notifications to display correctly on Android 12+ -->
<meta-data
android:name=
"com.google.firebase.messaging.default_notification_channel_id"
android:value=
"default_channel_id"
/>
</application>
</application>
<!-- Required to query activities that can process text, see:
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/training/package-visibility and
...
...
lib/Notifier/ProfileProvider.dart
View file @
f96fa9c8
import
'package:firebase_messaging/firebase_messaging.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:pulse/Models/profileResponse.dart'
;
import
'package:pulse/Models/profileResponse.dart'
;
...
@@ -38,11 +39,12 @@ class ProfileProvider extends ChangeNotifier {
...
@@ -38,11 +39,12 @@ class ProfileProvider extends ChangeNotifier {
_errorMessage
=
null
;
_errorMessage
=
null
;
_profileResponse
=
null
;
_profileResponse
=
null
;
notifyListeners
();
notifyListeners
();
String
?
fcmToken
=
await
FirebaseMessaging
.
instance
.
getToken
();
final
data
=
await
ApiService
.
fetchProfile
(
final
data
=
await
ApiService
.
fetchProfile
(
csrfToken:
csrfToken
,
csrfToken:
csrfToken
,
sessionId:
sessionId
,
sessionId:
sessionId
,
staffId:
staffId
,
staffId:
staffId
,
token:
fcmToken
.
toString
()
??
""
,
isApp:
isApp
,
isApp:
isApp
,
);
);
...
...
lib/Notifier/notification_provider.dart
0 → 100644
View file @
f96fa9c8
import
'package:flutter/material.dart'
;
import
'package:firebase_messaging/firebase_messaging.dart'
;
class
NotificationProvider
with
ChangeNotifier
{
List
<
Map
<
String
,
dynamic
>>
_notifications
=
[];
int
_unreadCount
=
0
;
List
<
Map
<
String
,
dynamic
>>
get
notifications
=>
_notifications
;
int
get
unreadCount
=>
_unreadCount
;
// Add new notification
void
addNotification
(
Map
<
String
,
dynamic
>
notification
)
{
_notifications
.
insert
(
0
,
notification
);
_unreadCount
++;
notifyListeners
();
}
// Mark as read
void
markAsRead
(
int
index
)
{
if
(
index
<
_notifications
.
length
)
{
_notifications
[
index
][
'isRead'
]
=
true
;
_unreadCount
--;
notifyListeners
();
}
}
// Mark all as read
void
markAllAsRead
()
{
for
(
var
notification
in
_notifications
)
{
notification
[
'isRead'
]
=
true
;
}
_unreadCount
=
0
;
notifyListeners
();
}
// Clear all notifications
void
clearAll
()
{
_notifications
.
clear
();
_unreadCount
=
0
;
notifyListeners
();
}
}
\ No newline at end of file
lib/Screens/WebErpScreen.dart
deleted
100644 → 0
View file @
7f695622
// import 'package:flutter/material.dart';
// import 'package:pulse/Screens/home_screen.dart';
// import 'package:webview_flutter/webview_flutter.dart';
//
//
// class WebErpScreen extends StatefulWidget {
// final String staffId;
// final String sessionId;
//
// const WebErpScreen({
// super.key,
// required this.staffId,
// required this.sessionId,
// });
//
// @override
// State<WebErpScreen> createState() => _WebErpScreenState();
// }
//
// class _WebErpScreenState extends State<WebErpScreen> {
// late final WebViewController _controller;
//
// @override
// void initState() {
// super.initState();
//
// _controller = WebViewController()
// ..setJavaScriptMode(JavaScriptMode.unrestricted)
// ..setNavigationDelegate(
// NavigationDelegate(
// onPageStarted: (url) {
// debugPrint("Loading: $url");
// },
// onPageFinished: (url) {
// debugPrint("Finished: $url");
// },
// ),
// )
// ..loadRequest(
// Uri.parse(
// "https://pulse.webgrid.in/app/authentication/web_erp?staff_id=${widget.staffId}&session_id=${widget.sessionId}",
// ),
// headers: {
// "Cookie": "session_id=${widget.sessionId}",
// },
// );
// }
//
// Future<bool> _handleWillPop() async {
// if (await _controller.canGoBack()) {
// _controller.goBack();
// return false; // don’t pop screen
// }
// return true; // pop screen
// }
//
// @override
// Widget build(BuildContext context) {
// return WillPopScope(
// onWillPop: _handleWillPop,
// child: Scaffold(
// appBar: AppBar(
// automaticallyImplyLeading: false,
// backgroundColor: AppColors.backgroundGradient2,
// title: Row(
// children: [
// InkResponse(
// onTap: () async {
// if (await _controller.canGoBack()) {
// _controller.goBack();
// } else {
// Navigator.pop(context, true);
// }
// },
// child: const Icon(
// Icons.arrow_back,
// color: Colors.white,
// size: 30,
// ),
// ),
// const SizedBox(width: 15),
// Text(
// "Web ERP",
// style: TextStyle(
// fontSize: 20,
// fontWeight: FontWeight.bold,
// color: AppColors.textPrimary,
// ),
// ),
// ],
// ),
// ),
// backgroundColor: const Color(0xFF1e293b),
// body: SafeArea(
// top: true,
// child: WebViewWidget(controller: _controller),
// ),
// ),
// );
// }
// }
lib/Screens/home_screen.dart
View file @
f96fa9c8
...
@@ -17,8 +17,14 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
...
@@ -17,8 +17,14 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class
HomeScreen
extends
StatefulWidget
{
class
HomeScreen
extends
StatefulWidget
{
final
String
sessionId
;
final
String
sessionId
;
final
String
staffId
;
final
String
staffId
;
final
String
?
notificationUrl
;
//
const
HomeScreen
({
super
.
key
,
required
this
.
sessionId
,
required
this
.
staffId
});
const
HomeScreen
({
super
.
key
,
required
this
.
sessionId
,
required
this
.
staffId
,
this
.
notificationUrl
,
//
});
@override
@override
State
<
HomeScreen
>
createState
()
=>
_HomeScreenState
();
State
<
HomeScreen
>
createState
()
=>
_HomeScreenState
();
...
@@ -49,6 +55,7 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -49,6 +55,7 @@ class _HomeScreenState extends State<HomeScreen> {
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
HapticFeedback
.
lightImpact
();
_initConnectivity
();
_initConnectivity
();
_initializePullToRefresh
();
_initializePullToRefresh
();
...
@@ -369,6 +376,7 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -369,6 +376,7 @@ class _HomeScreenState extends State<HomeScreen> {
builder:
(
context
,
profileProvider
,
child
)
{
builder:
(
context
,
profileProvider
,
child
)
{
return
InkWell
(
return
InkWell
(
onTap:
()
{
onTap:
()
{
HapticFeedback
.
lightImpact
();
Navigator
.
push
(
Navigator
.
push
(
context
,
context
,
MaterialPageRoute
(
MaterialPageRoute
(
...
@@ -476,13 +484,16 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -476,13 +484,16 @@ class _HomeScreenState extends State<HomeScreen> {
key:
webViewKey
,
key:
webViewKey
,
initialUrlRequest:
URLRequest
(
initialUrlRequest:
URLRequest
(
url:
WebUri
(
url:
WebUri
(
"https://pulse.webgrid.in/app/authentication/web_erp?staff_id=
${widget.staffId}
&session_id=
${widget.sessionId}
"
,
widget
.
notificationUrl
!=
null
&&
widget
.
notificationUrl
!.
isNotEmpty
?
widget
.
notificationUrl
!
:
"https://pulse.webgrid.in/app/authentication/web_erp?staff_id=
${widget.staffId}
&session_id=
${widget.sessionId}
"
,
),
),
headers:
{
"Cookie"
:
"session_id=
${widget.sessionId}
"
},
headers:
{
"Cookie"
:
"session_id=
${widget.sessionId}
"
},
allowsCellularAccess:
true
,
allowsCellularAccess:
true
,
allowsConstrainedNetworkAccess:
true
,
allowsConstrainedNetworkAccess:
true
,
allowsExpensiveNetworkAccess:
true
,
allowsExpensiveNetworkAccess:
true
,
),
),
initialOptions:
InAppWebViewGroupOptions
(
initialOptions:
InAppWebViewGroupOptions
(
android:
AndroidInAppWebViewOptions
(
android:
AndroidInAppWebViewOptions
(
useWideViewPort:
true
,
useWideViewPort:
true
,
...
@@ -530,12 +541,14 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -530,12 +541,14 @@ class _HomeScreenState extends State<HomeScreen> {
},
},
onLoadStart:
(
controller
,
url
)
{
onLoadStart:
(
controller
,
url
)
{
setState
(()
{
setState
(()
{
HapticFeedback
.
lightImpact
();
_isLoading
=
true
;
_isLoading
=
true
;
_isRefreshing
=
true
;
_isRefreshing
=
true
;
});
});
},
},
onLoadStop:
(
controller
,
url
)
async
{
onLoadStop:
(
controller
,
url
)
async
{
setState
(()
{
setState
(()
{
HapticFeedback
.
lightImpact
();
_isLoading
=
false
;
_isLoading
=
false
;
_isRefreshing
=
false
;
_isRefreshing
=
false
;
});
});
...
@@ -545,6 +558,7 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -545,6 +558,7 @@ class _HomeScreenState extends State<HomeScreen> {
},
},
onLoadError:
(
controller
,
url
,
code
,
message
)
{
onLoadError:
(
controller
,
url
,
code
,
message
)
{
setState
(()
{
setState
(()
{
HapticFeedback
.
lightImpact
();
_isLoading
=
false
;
_isLoading
=
false
;
_isRefreshing
=
false
;
_isRefreshing
=
false
;
});
});
...
@@ -552,6 +566,7 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -552,6 +566,7 @@ class _HomeScreenState extends State<HomeScreen> {
},
},
onProgressChanged:
(
controller
,
progress
)
{
onProgressChanged:
(
controller
,
progress
)
{
if
(
progress
==
100
)
{
if
(
progress
==
100
)
{
HapticFeedback
.
lightImpact
();
_pullToRefreshController
?.
endRefreshing
();
_pullToRefreshController
?.
endRefreshing
();
setState
(()
{
setState
(()
{
_isRefreshing
=
false
;
_isRefreshing
=
false
;
...
@@ -559,6 +574,7 @@ class _HomeScreenState extends State<HomeScreen> {
...
@@ -559,6 +574,7 @@ class _HomeScreenState extends State<HomeScreen> {
}
}
},
},
onReceivedError:
(
controller
,
request
,
error
)
{
onReceivedError:
(
controller
,
request
,
error
)
{
HapticFeedback
.
lightImpact
();
setState
(()
{
setState
(()
{
_isLoading
=
false
;
_isLoading
=
false
;
_isRefreshing
=
false
;
_isRefreshing
=
false
;
...
...
lib/Screens/profileScreen.dart
View file @
f96fa9c8
import
'package:cached_network_image/cached_network_image.dart'
;
import
'package:cached_network_image/cached_network_image.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'package:pulse/Screens/authScreen/LoginScreen.dart'
;
import
'package:pulse/Screens/authScreen/LoginScreen.dart'
;
import
'package:pulse/Screens/home_screen.dart'
;
import
'package:pulse/Screens/home_screen.dart'
;
...
@@ -86,7 +87,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
...
@@ -86,7 +87,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
),
child:
IconButton
(
child:
IconButton
(
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
white
),
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
white
),
onPressed:
()
=>
Navigator
.
pop
(
context
),
onPressed:
()
{
HapticFeedback
.
lightImpact
();
Navigator
.
pop
(
context
,
true
);
},
),
),
),
),
const
SizedBox
(
width:
16
),
const
SizedBox
(
width:
16
),
...
@@ -356,6 +360,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
...
@@ -356,6 +360,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
),
child:
ElevatedButton
(
child:
ElevatedButton
(
onPressed:
()
{
onPressed:
()
{
HapticFeedback
.
lightImpact
();
_showLogoutConfirmationDialog
();
_showLogoutConfirmationDialog
();
},
},
style:
ElevatedButton
.
styleFrom
(
style:
ElevatedButton
.
styleFrom
(
...
@@ -454,7 +459,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
...
@@ -454,7 +459,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
children:
[
children:
[
Expanded
(
Expanded
(
child:
OutlinedButton
(
child:
OutlinedButton
(
onPressed:
()
=>
Navigator
.
pop
(
context
),
onPressed:
()
{
HapticFeedback
.
lightImpact
();
Navigator
.
pop
(
context
);
},
style:
OutlinedButton
.
styleFrom
(
style:
OutlinedButton
.
styleFrom
(
foregroundColor:
Colors
.
grey
.
shade700
,
foregroundColor:
Colors
.
grey
.
shade700
,
side:
BorderSide
(
color:
Colors
.
grey
.
shade400
),
side:
BorderSide
(
color:
Colors
.
grey
.
shade400
),
...
@@ -470,6 +478,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
...
@@ -470,6 +478,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
Expanded
(
Expanded
(
child:
ElevatedButton
(
child:
ElevatedButton
(
onPressed:
()
async
{
onPressed:
()
async
{
HapticFeedback
.
lightImpact
();
Navigator
.
pop
(
context
);
// Close dialog first
Navigator
.
pop
(
context
);
// Close dialog first
await
_performLogout
();
await
_performLogout
();
},
},
...
...
lib/Services/api_calling.dart
View file @
f96fa9c8
...
@@ -100,13 +100,16 @@ class ApiService {
...
@@ -100,13 +100,16 @@ class ApiService {
required
String
csrfToken
,
required
String
csrfToken
,
required
String
sessionId
,
required
String
sessionId
,
required
String
staffId
,
required
String
staffId
,
required
token
,
String
isApp
=
"1"
,
String
isApp
=
"1"
,
})
async
{
})
async
{
try
{
try
{
debugPrint
(
"⚠️ FCM Device token:
$token
"
);
Map
<
String
,
String
>
data
=
{
Map
<
String
,
String
>
data
=
{
"csrf_token_name"
:
csrfToken
,
"csrf_token_name"
:
csrfToken
,
"session_id"
:
sessionId
,
"session_id"
:
sessionId
,
"staff_id"
:
staffId
,
"staff_id"
:
staffId
,
'token_id'
:
(
token
).
toString
(),
"is_app"
:
isApp
,
"is_app"
:
isApp
,
};
};
...
...
lib/SplashScreen.dart
View file @
f96fa9c8
...
@@ -2,6 +2,8 @@ import 'dart:async';
...
@@ -2,6 +2,8 @@ import 'dart:async';
import
'dart:io'
;
import
'dart:io'
;
import
'package:connectivity_plus/connectivity_plus.dart'
;
import
'package:connectivity_plus/connectivity_plus.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:package_info_plus/package_info_plus.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'package:pulse/Notifier/auth_provider.dart'
;
import
'package:pulse/Notifier/auth_provider.dart'
;
import
'package:pulse/Screens/authScreen/LoginScreen.dart'
;
import
'package:pulse/Screens/authScreen/LoginScreen.dart'
;
...
@@ -19,6 +21,7 @@ class SplashScreen extends StatefulWidget {
...
@@ -19,6 +21,7 @@ class SplashScreen extends StatefulWidget {
class
_SplashScreenState
extends
State
<
SplashScreen
>
with
SingleTickerProviderStateMixin
{
class
_SplashScreenState
extends
State
<
SplashScreen
>
with
SingleTickerProviderStateMixin
{
final
_prefs
=
SharedPreferencesService
.
instance
;
final
_prefs
=
SharedPreferencesService
.
instance
;
String
_appVersion
=
""
;
double
_opacity
=
0.0
;
double
_opacity
=
0.0
;
double
_scale
=
0.8
;
double
_scale
=
0.8
;
double
_progressValue
=
0.0
;
double
_progressValue
=
0.0
;
...
@@ -31,7 +34,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -31,7 +34,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
_loadAppVersion
();
// Initialize connectivity check
// Initialize connectivity check
_initConnectivity
();
_initConnectivity
();
...
@@ -57,6 +60,13 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -57,6 +60,13 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
_simulateProgress
();
_simulateProgress
();
}
}
Future
<
void
>
_loadAppVersion
()
async
{
final
info
=
await
PackageInfo
.
fromPlatform
();
setState
(()
{
_appVersion
=
"
${info.version}
+
${info.buildNumber}
"
;
});
}
Future
<
void
>
_initConnectivity
()
async
{
Future
<
void
>
_initConnectivity
()
async
{
try
{
try
{
// Initial connectivity check
// Initial connectivity check
...
@@ -122,6 +132,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -122,6 +132,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
// Hide any existing snackbar
// Hide any existing snackbar
ScaffoldMessenger
.
of
(
context
).
hideCurrentSnackBar
();
ScaffoldMessenger
.
of
(
context
).
hideCurrentSnackBar
();
// Show custom snackbar with all required params
// Show custom snackbar with all required params
CustomSnackBar
.
show
(
CustomSnackBar
.
show
(
context:
context
,
context:
context
,
...
@@ -141,6 +152,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -141,6 +152,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
void
_simulateProgress
()
{
void
_simulateProgress
()
{
Timer
.
periodic
(
const
Duration
(
milliseconds:
30
),
(
timer
)
{
Timer
.
periodic
(
const
Duration
(
milliseconds:
30
),
(
timer
)
{
if
(
_progressValue
<
1.0
)
{
if
(
_progressValue
<
1.0
)
{
//HapticFeedback.lightImpact();
setState
(()
{
setState
(()
{
_progressValue
+=
0.02
;
_progressValue
+=
0.02
;
});
});
...
@@ -195,6 +207,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -195,6 +207,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
);
);
if
(
loginProvider
.
isLoggedIn
)
{
if
(
loginProvider
.
isLoggedIn
)
{
HapticFeedback
.
lightImpact
();
Navigator
.
pushReplacement
(
Navigator
.
pushReplacement
(
context
,
context
,
MaterialPageRoute
(
MaterialPageRoute
(
...
@@ -209,13 +222,13 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -209,13 +222,13 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
}
}
// Default → Login screen
// Default → Login screen
HapticFeedback
.
lightImpact
();
Navigator
.
pushReplacement
(
Navigator
.
pushReplacement
(
context
,
context
,
MaterialPageRoute
(
builder:
(
_
)
=>
const
LoginScreen
()),
MaterialPageRoute
(
builder:
(
_
)
=>
const
LoginScreen
()),
);
);
}
}
@override
@override
void
dispose
()
{
void
dispose
()
{
_controller
.
dispose
();
_controller
.
dispose
();
...
@@ -418,7 +431,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -418,7 +431,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
// Version info
// Version info
Text
(
Text
(
"Version
1.0.0
"
,
"Version
$_appVersion
"
,
style:
TextStyle
(
style:
TextStyle
(
color:
Colors
.
white
.
withOpacity
(
0.5
),
color:
Colors
.
white
.
withOpacity
(
0.5
),
fontSize:
12
,
fontSize:
12
,
...
...
lib/main.dart
View file @
f96fa9c8
import
'dart:io'
;
import
'dart:convert'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_inappwebview/flutter_inappwebview.dart'
;
import
'package:flutter/services.dart'
;
import
'package:firebase_core/firebase_core.dart'
;
import
'package:firebase_messaging/firebase_messaging.dart'
;
import
'package:flutter_local_notifications/flutter_local_notifications.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'package:pulse/SplashScreen.dart'
;
import
'package:pulse/Notifier/auth_provider.dart'
;
import
'package:pulse/Notifier/theme_provider.dart'
;
import
'package:pulse/Notifier/ProfileProvider.dart'
;
import
'package:pulse/Notifier/ProfileProvider.dart'
;
import
'package:pulse/Notifier/webProvider.dart'
;
import
'package:pulse/Notifier/webProvider.dart'
;
import
'package:
pulse/SplashScreen
.dart'
;
import
'package:
flutter_inappwebview/flutter_inappwebview
.dart'
;
import
'Notifier/auth_provider.dart'
;
import
'Screens/home_screen.dart'
;
import
'Notifier/theme_provider.dart'
;
import
'Screens/authScreen/LoginScreen.dart'
;
// Needed to navigate outside BuildContext
final
GlobalKey
<
NavigatorState
>
navigatorKey
=
GlobalKey
<
NavigatorState
>();
// Initialize the notification plugin
final
FlutterLocalNotificationsPlugin
flutterLocalNotificationsPlugin
=
FlutterLocalNotificationsPlugin
();
// Handle background notifications
Future
<
void
>
_firebaseMessagingBackgroundHandler
(
RemoteMessage
message
)
async
{
if
(
Firebase
.
apps
.
isEmpty
)
{
await
Firebase
.
initializeApp
();
}
print
(
"📬 Background message:
${message.messageId}
"
);
}
void
main
(
)
{
Future
<
void
>
main
()
async
{
WidgetsFlutterBinding
.
ensureInitialized
();
WidgetsFlutterBinding
.
ensureInitialized
();
// Initialize Firebase safely
try
{
if
(
Firebase
.
apps
.
isEmpty
)
{
await
Firebase
.
initializeApp
(
options:
const
FirebaseOptions
(
apiKey:
"2f663c764bb77355c82d30b2068b15427363ccfd"
,
appId:
"1:207322820833:android:82516ed462f6ae6e4447a0"
,
messagingSenderId:
"207322820833"
,
projectId:
"pulse-5cf9a"
,
),
);
debugPrint
(
" Firebase initialized."
);
}
else
{
Firebase
.
app
();
// existing instance
debugPrint
(
"⚡ Firebase already initialized, reusing instance."
);
}
}
catch
(
e
)
{
debugPrint
(
"❌ Firebase init error:
$e
"
);
}
// Setup local notifications
const
AndroidInitializationSettings
initializationSettingsAndroid
=
AndroidInitializationSettings
(
'@mipmap/ic_launcher'
);
const
InitializationSettings
initializationSettings
=
InitializationSettings
(
android:
initializationSettingsAndroid
);
await
flutterLocalNotificationsPlugin
.
initialize
(
initializationSettings
);
// Local notifications setup
const
AndroidInitializationSettings
initSettingsAndroid
=
AndroidInitializationSettings
(
'@mipmap/ic_launcher'
);
const
InitializationSettings
initSettings
=
InitializationSettings
(
android:
initSettingsAndroid
);
await
flutterLocalNotificationsPlugin
.
initialize
(
initSettings
,
onDidReceiveNotificationResponse:
(
NotificationResponse
response
)
{
if
(
response
.
payload
!=
null
)
{
final
data
=
jsonDecode
(
response
.
payload
!);
NotificationHandler
.
handle
(
data
);
}
},
);
// Setup FCM
FirebaseMessaging
messaging
=
FirebaseMessaging
.
instance
;
await
messaging
.
requestPermission
(
alert:
true
,
badge:
true
,
sound:
true
);
// String? token = await messaging.getToken();
// print("🔥 FCM Token: $token");
// Background handler
FirebaseMessaging
.
onBackgroundMessage
(
_firebaseMessagingBackgroundHandler
);
// Foreground notification
FirebaseMessaging
.
onMessage
.
listen
((
RemoteMessage
message
)
async
{
print
(
"💬 Foreground message:
${message.notification?.title}
"
);
RemoteNotification
?
notification
=
message
.
notification
;
AndroidNotification
?
android
=
message
.
notification
?.
android
;
if
(
notification
!=
null
&&
android
!=
null
)
{
flutterLocalNotificationsPlugin
.
show
(
notification
.
hashCode
,
notification
.
title
,
notification
.
body
,
const
NotificationDetails
(
android:
AndroidNotificationDetails
(
'pulse_channel'
,
// channel id
'Pulse Notifications'
,
// channel name
importance:
Importance
.
max
,
priority:
Priority
.
high
,
),
),
payload:
jsonEncode
(
message
.
data
),
);
}
});
// notification while app is in background
FirebaseMessaging
.
onMessageOpenedApp
.
listen
((
RemoteMessage
message
)
{
print
(
" Notification clicked:
${message.data}
"
);
});
InAppWebViewController
.
setWebContentsDebuggingEnabled
(
true
);
InAppWebViewController
.
setWebContentsDebuggingEnabled
(
true
);
runApp
(
const
MyApp
());
runApp
(
const
MyApp
());
}
}
...
@@ -23,10 +127,10 @@ class MyApp extends StatelessWidget {
...
@@ -23,10 +127,10 @@ class MyApp extends StatelessWidget {
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
MultiProvider
(
return
MultiProvider
(
providers:
[
providers:
[
ChangeNotifierProvider
<
AuthProvider
>(
create:
(
_
)
=>
AuthProvider
()
,
),
ChangeNotifierProvider
<
AuthProvider
>(
create:
(
_
)
=>
AuthProvider
()),
ChangeNotifierProvider
<
ThemeProvider
>(
create:
(
_
)
=>
ThemeProvider
()
,
),
ChangeNotifierProvider
<
ThemeProvider
>(
create:
(
_
)
=>
ThemeProvider
()),
ChangeNotifierProvider
<
ProfileProvider
>(
create:
(
_
)
=>
ProfileProvider
()
,
),
ChangeNotifierProvider
<
ProfileProvider
>(
create:
(
_
)
=>
ProfileProvider
()),
ChangeNotifierProvider
<
WebErpProvider
>(
create:
(
_
)
=>
WebErpProvider
()
,
),
ChangeNotifierProvider
<
WebErpProvider
>(
create:
(
_
)
=>
WebErpProvider
()),
],
],
child:
Consumer
<
ThemeProvider
>(
child:
Consumer
<
ThemeProvider
>(
builder:
(
context
,
themeProvider
,
child
)
{
builder:
(
context
,
themeProvider
,
child
)
{
...
@@ -45,3 +149,29 @@ class MyApp extends StatelessWidget {
...
@@ -45,3 +149,29 @@ class MyApp extends StatelessWidget {
);
);
}
}
}
}
class
NotificationHandler
{
static
void
handle
(
Map
<
String
,
dynamic
>
data
)
{
final
type
=
data
[
'type'
];
final
value
=
data
[
'type_value'
];
final
notifId
=
data
[
'notification_id'
];
debugPrint
(
"🔗 Handling Notification:"
);
debugPrint
(
"type=
$type
, value=
$value
, id=
$notifId
"
);
// Decide what to do based on the type
if
(
type
==
'web'
&&
value
!=
null
)
{
navigatorKey
.
currentState
?.
push
(
MaterialPageRoute
(
builder:
(
_
)
=>
HomeScreen
(
sessionId:
''
,
staffId:
''
,
notificationUrl:
value
,
),
),
);
}
}
}
lib/utils/customSnackBar.dart
View file @
f96fa9c8
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
class
CustomSnackBar
{
class
CustomSnackBar
{
static
void
show
({
static
void
show
({
...
@@ -9,6 +10,7 @@ class CustomSnackBar {
...
@@ -9,6 +10,7 @@ class CustomSnackBar {
Color
backgroundColor
=
const
Color
(
0xFF324563
),
Color
backgroundColor
=
const
Color
(
0xFF324563
),
Duration
duration
=
const
Duration
(
seconds:
4
),
Duration
duration
=
const
Duration
(
seconds:
4
),
})
{
})
{
HapticFeedback
.
lightImpact
();
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
SnackBar
(
backgroundColor:
Colors
.
transparent
,
backgroundColor:
Colors
.
transparent
,
...
...
macos/Flutter/GeneratedPluginRegistrant.swift
View file @
f96fa9c8
...
@@ -6,7 +6,10 @@ import FlutterMacOS
...
@@ -6,7 +6,10 @@ import FlutterMacOS
import
Foundation
import
Foundation
import
connectivity_plus
import
connectivity_plus
import
firebase_core
import
firebase_messaging
import
flutter_inappwebview_macos
import
flutter_inappwebview_macos
import
flutter_local_notifications
import
package_info_plus
import
package_info_plus
import
path_provider_foundation
import
path_provider_foundation
import
shared_preferences_foundation
import
shared_preferences_foundation
...
@@ -15,7 +18,10 @@ import webview_flutter_wkwebview
...
@@ -15,7 +18,10 @@ import webview_flutter_wkwebview
func
RegisterGeneratedPlugins
(
registry
:
FlutterPluginRegistry
)
{
func
RegisterGeneratedPlugins
(
registry
:
FlutterPluginRegistry
)
{
ConnectivityPlusPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"ConnectivityPlusPlugin"
))
ConnectivityPlusPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"ConnectivityPlusPlugin"
))
FLTFirebaseCorePlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FLTFirebaseCorePlugin"
))
FLTFirebaseMessagingPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FLTFirebaseMessagingPlugin"
))
InAppWebViewFlutterPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"InAppWebViewFlutterPlugin"
))
InAppWebViewFlutterPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"InAppWebViewFlutterPlugin"
))
FlutterLocalNotificationsPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FlutterLocalNotificationsPlugin"
))
FPPPackageInfoPlusPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FPPPackageInfoPlusPlugin"
))
FPPPackageInfoPlusPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FPPPackageInfoPlusPlugin"
))
PathProviderPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"PathProviderPlugin"
))
PathProviderPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"PathProviderPlugin"
))
SharedPreferencesPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"SharedPreferencesPlugin"
))
SharedPreferencesPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"SharedPreferencesPlugin"
))
...
...
pubspec.lock
View file @
f96fa9c8
# Generated by pub
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
packages:
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "23d16f00a2da8ffa997c782453c73867b0609bd90435195671a54de38a3566df"
url: "https://pub.dev"
source: hosted
version: "1.3.62"
args:
args:
dependency: transitive
dependency: transitive
description:
description:
...
@@ -153,6 +161,54 @@ packages:
...
@@ -153,6 +161,54 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "7.0.1"
version: "7.0.1"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "4dd96f05015c0dcceaa47711394c32971aee70169625d5e2477e7676c01ce0ee"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: "5873a370f0d232918e23a5a6137dbe4c2c47cf017301f4ea02d9d636e52f60f0"
url: "https://pub.dev"
source: hosted
version: "6.0.1"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: "61a51037312dac781f713308903bb7a1762a7f92f7bc286a3a0947fb2a713b82"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: ba12ad0b600e0c939fbb9391e1cd3320a5b5dad5284276b9182fc21eb1e72c2b
url: "https://pub.dev"
source: hosted
version: "16.0.2"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: b4bade67bfc09fcc56eb012b3fc72b59ca9e2259a34cdfb81b368169770ff536
url: "https://pub.dev"
source: hosted
version: "4.7.2"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "8ae4a00d178993feb79603cad324b53696375cbb78805e8eb603fe331866629d"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
fixnum:
fixnum:
dependency: transitive
dependency: transitive
description:
description:
...
@@ -254,6 +310,30 @@ packages:
...
@@ -254,6 +310,30 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "5.0.0"
version: "5.0.0"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
url: "https://pub.dev"
source: hosted
version: "17.2.4"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
url: "https://pub.dev"
source: hosted
version: "4.0.1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
url: "https://pub.dev"
source: hosted
version: "7.2.0"
flutter_svg:
flutter_svg:
dependency: "direct main"
dependency: "direct main"
description:
description:
...
@@ -725,6 +805,14 @@ packages:
...
@@ -725,6 +805,14 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "0.7.4"
version: "0.7.4"
timezone:
dependency: transitive
description:
name: timezone
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
url: "https://pub.dev"
source: hosted
version: "0.9.4"
typed_data:
typed_data:
dependency: transitive
dependency: transitive
description:
description:
...
...
pubspec.yaml
View file @
f96fa9c8
...
@@ -45,7 +45,10 @@ dependencies:
...
@@ -45,7 +45,10 @@ dependencies:
flutter_html
:
^3.0.0
flutter_html
:
^3.0.0
connectivity_plus
:
^6.1.0
connectivity_plus
:
^6.1.0
pull_to_refresh
:
^2.0.0
pull_to_refresh
:
^2.0.0
firebase_messaging
:
^16.0.2
flutter_inappwebview
:
^6.1.5
flutter_inappwebview
:
^6.1.5
firebase_core
:
^4.1.1
flutter_local_notifications
:
^17.2.0
dev_dependencies
:
dev_dependencies
:
flutter_test
:
flutter_test
:
...
...
windows/flutter/generated_plugin_registrant.cc
View file @
f96fa9c8
...
@@ -7,12 +7,15 @@
...
@@ -7,12 +7,15 @@
#include "generated_plugin_registrant.h"
#include "generated_plugin_registrant.h"
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
void
RegisterPlugins
(
flutter
::
PluginRegistry
*
registry
)
{
void
RegisterPlugins
(
flutter
::
PluginRegistry
*
registry
)
{
ConnectivityPlusWindowsPluginRegisterWithRegistrar
(
ConnectivityPlusWindowsPluginRegisterWithRegistrar
(
registry
->
GetRegistrarForPlugin
(
"ConnectivityPlusWindowsPlugin"
));
registry
->
GetRegistrarForPlugin
(
"ConnectivityPlusWindowsPlugin"
));
FirebaseCorePluginCApiRegisterWithRegistrar
(
registry
->
GetRegistrarForPlugin
(
"FirebaseCorePluginCApi"
));
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar
(
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar
(
registry
->
GetRegistrarForPlugin
(
"FlutterInappwebviewWindowsPluginCApi"
));
registry
->
GetRegistrarForPlugin
(
"FlutterInappwebviewWindowsPluginCApi"
));
PermissionHandlerWindowsPluginRegisterWithRegistrar
(
PermissionHandlerWindowsPluginRegisterWithRegistrar
(
...
...
windows/flutter/generated_plugins.cmake
View file @
f96fa9c8
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
list
(
APPEND FLUTTER_PLUGIN_LIST
list
(
APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
connectivity_plus
firebase_core
flutter_inappwebview_windows
flutter_inappwebview_windows
permission_handler_windows
permission_handler_windows
)
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment