Commit f7b0d1aa authored by Sai Srinivas's avatar Sai Srinivas
Browse files

ios changes

parent 64c42cd9
......@@ -56,6 +56,8 @@ PODS:
- Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_pdfview (1.0.2):
- Flutter
- flutter_ringtone_player (0.0.1):
- Flutter
- fluttertoast (0.0.2):
......@@ -136,6 +138,8 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- printing (1.0.0):
- Flutter
- PromisesObjC (2.4.0)
- qr_code_scanner (0.2.0):
- Flutter
......@@ -154,6 +158,8 @@ PODS:
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- syncfusion_flutter_pdfviewer (0.0.1):
- Flutter
- url_launcher_ios (0.0.1):
- Flutter
- webview_flutter_wkwebview (0.0.1):
......@@ -172,6 +178,7 @@ DEPENDENCIES:
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_pdfview (from `.symlinks/plugins/flutter_pdfview/ios`)
- flutter_ringtone_player (from `.symlinks/plugins/flutter_ringtone_player/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- geocoding_ios (from `.symlinks/plugins/geocoding_ios/ios`)
......@@ -182,10 +189,12 @@ DEPENDENCIES:
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- printing (from `.symlinks/plugins/printing/ios`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
......@@ -232,6 +241,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_pdfview:
:path: ".symlinks/plugins/flutter_pdfview/ios"
flutter_ringtone_player:
:path: ".symlinks/plugins/flutter_ringtone_player/ios"
fluttertoast:
......@@ -252,6 +263,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
printing:
:path: ".symlinks/plugins/printing/ios"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
share_plus:
......@@ -260,6 +273,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
syncfusion_flutter_pdfviewer:
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
webview_flutter_wkwebview:
......@@ -282,6 +297,7 @@ SPEC CHECKSUMS:
flutter_inappwebview_ios: 8d8d2c6290a3c4787cad303603662fac9a788f75
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
flutter_pdfview: 2e4d13ffb774858562ffbdfdb61b40744b191adc
flutter_ringtone_player: 15eba85187230b87b2512f0e1b92225618bc03e7
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
geocoding_ios: d7460f56e80e118d57678efe5c2cdc888739ff18
......@@ -301,6 +317,7 @@ SPEC CHECKSUMS:
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
......@@ -308,6 +325,7 @@ SPEC CHECKSUMS:
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
syncfusion_flutter_pdfviewer: cfcf23c03816192575902e615fa50adc9f95b724
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
webview_flutter_wkwebview: ab1e58b71690b7e61b58eae7a963b68ee286a146
......
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
......@@ -10,6 +11,7 @@ import 'package:generp/Notifiers/LogoutNotifier.dart';
import 'package:generp/Notifiers/ProfileNotifier.dart';
import 'package:generp/screens/LoginScreen.dart';
import 'package:generp/screens/ScannerLogin.dart';
import 'package:generp/screens/WebERPIOS.dart';
import 'package:generp/screens/WebERPScreen.dart';
import 'package:generp/screens/WebWhizzdomScreen.dart';
import 'package:generp/screens/finance/financeDashboard.dart';
......@@ -127,8 +129,8 @@ class _MyHomePageState extends State<MyHomePage> {
"Nearby",
"Inventory",
"Whizzdom",
"CRM",
"Finance",
// "CRM",
// "Finance",
];
final icons = [
"assets/svg/home_icons_1.svg",
......@@ -138,8 +140,8 @@ class _MyHomePageState extends State<MyHomePage> {
"assets/svg/home_icons_5.svg",
"assets/svg/home_icons_6.svg",
"assets/svg/home_icons_81.svg",
"assets/svg/home_icons_8.svg",
"assets/svg/home_icons_8.svg",
// "assets/svg/home_icons_8.svg",
// "assets/svg/home_icons_8.svg",
];
final requiredRoles = [
"430",
......@@ -149,8 +151,8 @@ class _MyHomePageState extends State<MyHomePage> {
"433",
"432",
"431",
"431",
"431",
// "431",
// "431",
];
final filteredItems = <Map<String, String>>[];
......@@ -372,15 +374,28 @@ class _MyHomePageState extends State<MyHomePage> {
bool isGpsEnabled =
await Geolocator.isLocationServiceEnabled();
if (isGpsEnabled) {
if (Platform.isAndroid) {
res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => WebErpScreen(
erp_url: homescreen.webPageUrl,
erp_url:
homescreen.webPageUrl,
),
),
);
} else {
res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => WebERPIOS(
url: homescreen.webPageUrl,
),
),
);
}
} else {
requestGpsPermission();
}
......@@ -445,13 +460,13 @@ class _MyHomePageState extends State<MyHomePage> {
//res = await Navigator.push(context, MaterialPageRoute(builder: (context)=>CRMScreen()));
break;
case "Finance":
res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => Financedashboard(),
),
);
// res = await Navigator.push(
// context,
// MaterialPageRoute(
// builder:
// (context) => Financedashboard(),
// ),
// );
break;
default:
print("111");
......
import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_download_manager/flutter_download_manager.dart';
import 'package:flutter_svg/svg.dart';
import 'package:generp/Utils/app_colors.dart';
import 'package:generp/Utils/commonWidgets.dart';
import 'package:generp/screens/WebERPScreen.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:url_launcher/url_launcher.dart';
const MAX_PROGRESS = 100;
Future main() async {
await FlutterDownloader.initialize(
debug: true, // optional: set false to disable printing logs to console
);
await Permission.storage.request();
}
class WebERPIOS extends StatefulWidget {
final String url;
const WebERPIOS({Key? key, required this.url}) : super(key: key);
@override
State<WebERPIOS> createState() => _WebERPIOSState();
}
class _WebERPIOSState extends State<WebERPIOS> {
final Completer<InAppWebViewController> _controller =
Completer<InAppWebViewController>();
var empId = "";
var sessionId = "";
bool isLoading = true;
InAppWebViewController? webViewController;
PullToRefreshController? pullToRefreshController;
PullToRefreshSettings pullToRefreshSettings = PullToRefreshSettings(
color: AppColors.app_blue,
);
bool pullToRefreshEnabled = true;
final GlobalKey webViewKey = GlobalKey();
var dl = DownloadManager();
@override
void initState() {
// loadData();
pullToRefreshController =
kIsWeb
? null
: PullToRefreshController(
settings: pullToRefreshSettings,
onRefresh: () async {
if (defaultTargetPlatform == Platform.isAndroid) {
webViewController?.reload();
} else if (defaultTargetPlatform == Platform.isIOS) {
webViewController?.loadUrl(
urlRequest: URLRequest(
url: await webViewController?.getUrl(),
),
);
}
},
);
print("WebURL:${widget.url}");
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (await webViewController!.canGoBack()) {
webViewController!.goBack();
return false; // Prevent default back button behavior
}
return true; // Allow default back button behavior
},
child: Scaffold(
appBar: appbar(context, "Web ERP"),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: Stack(
children: [
InAppWebView(
initialUrlRequest: URLRequest(
url: WebUri(widget.url.toString()),
),
androidOnGeolocationPermissionsShowPrompt: (
InAppWebViewController controller,
String origin,
) async {
return GeolocationPermissionShowPromptResponse(
origin: origin,
allow: true,
retain: true,
);
},
initialOptions: InAppWebViewGroupOptions(
android: AndroidInAppWebViewOptions(
useWideViewPort: true,
loadWithOverviewMode: true,
allowContentAccess: true,
geolocationEnabled: true,
allowFileAccess: true,
databaseEnabled: true, // Enables the WebView database
domStorageEnabled: true, // Enables DOM storage
builtInZoomControls:
true, // Enables the built-in zoom controls
displayZoomControls:
false, // Disables displaying zoom controls
safeBrowsingEnabled: true, // Enables Safe Browsing
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
allowsLinkPreview: true,
allowsBackForwardNavigationGestures: true,
),
),
androidOnPermissionRequest: (
InAppWebViewController controller,
String origin,
List<String> resources,
) async {
return PermissionRequestResponse(
resources: resources,
action: PermissionRequestResponseAction.GRANT,
);
},
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
allowFileAccess: true,
allowContentAccess: true,
clearCache: true,
blockNetworkLoads: false,
networkAvailable: true,
useOnLoadResource: true,
thirdPartyCookiesEnabled: true,
supportZoom: false,
geolocationEnabled: true,
safeBrowsingEnabled: false,
saveFormData: true,
allowFileAccessFromFileURLs: true,
useWideViewPort: true,
databaseEnabled: true,
domStorageEnabled: true,
allowsBackForwardNavigationGestures: true,
allowUniversalAccessFromFileURLs: true,
allowsLinkPreview: true,
),
onPermissionRequest: (controller, request) async {
return PermissionResponse(
resources: request.resources,
action: PermissionResponseAction.GRANT,
);
},
keepAlive: InAppWebViewKeepAlive(),
// initialData:
// InAppWebViewInitialData(baseUrl: WebUri(widget.url),data: ),
onWebViewCreated: (controller) {
webViewController = controller;
_controller.complete(controller);
},
pullToRefreshController: pullToRefreshController,
shouldOverrideUrlLoading: (
controller,
navigationAction,
) async {
var uri = navigationAction.request.url!;
print("urib scgefes");
print(uri);
print(uri.scheme);
if (uri.scheme == "tel") {
// Launch the phone dialer app with the specified phone number
if (await canLaunch(uri.toString())) {
await launch(uri.toString());
return NavigationActionPolicy.CANCEL;
}
} else if (uri.scheme == "mailto") {
if (await canLaunch(uri.toString())) {
await launch(uri.toString());
return NavigationActionPolicy.CANCEL;
}
} else if (uri.scheme == "whatsapp") {
// Launch WhatsApp with the specified chat or phone number
if (await canLaunch(uri.toString())) {
await launch(uri.toString());
return NavigationActionPolicy.CANCEL;
}
}
// // Check if the URL is trying to access the camera for image upload
// if (uri.scheme == 'camera' && uri.path.contains('/camera/')) {
// // Handle camera image upload here
// // You might want to display a custom UI for image selection or directly trigger the camera
// // You can use platform-specific plugins like image_picker for this purpose
// // Once the image is selected, you can pass it to the web view using JavaScript injection
// if (await canLaunch(uri.toString())) {
// await launch(uri.toString());
// return NavigationActionPolicy.CANCEL;
// }
// }
return NavigationActionPolicy.ALLOW;
},
onLoadStart: (controller, url) {
return setState(() {
isLoading = true;
});
},
onLoadStop: (controller, url) {
pullToRefreshController?.endRefreshing();
return setState(() {
isLoading = false;
});
},
onReceivedError: (controller, request, error) {
pullToRefreshController?.endRefreshing();
},
onProgressChanged: (controller, progress) {
if (progress == 100) {
pullToRefreshController?.endRefreshing();
}
},
),
if (isLoading) ...[
Container(
color: Colors.white.withOpacity(0.7),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SpinKitRing(
color: AppColors.app_blue,
lineWidth: 4,
// duration: Duration(seconds: 2),
size: 50,
),
const SizedBox(height: 15),
SizedBox(
width: 200,
child: Text(
"Please wait.......",
textAlign: TextAlign.center,
style: TextStyle(
decorationThickness: 0,
fontSize: 15,
fontWeight: FontWeight.normal,
color: AppColors.app_blue,
),
),
),
// SvgPicture.asset("/assets/images/NutsLoader.gif")
],
),
),
],
],
),
),
],
),
),
),
);
}
}
......@@ -19,17 +19,19 @@ import 'dart:math';
import 'package:flutter/widgets.dart';
import 'package:url_launcher/url_launcher.dart';
const MAX_PROGRESS = 100;
Future main() async {
await FlutterDownloader.initialize(
debug: true // optional: set false to disable printing logs to console
debug: true, // optional: set false to disable printing logs to console
);
await Permission.storage.request();
}
class WebErpScreen extends StatefulWidget {
final String erp_url;
const WebErpScreen({super.key,required this.erp_url});
const WebErpScreen({super.key, required this.erp_url});
@override
State<WebErpScreen> createState() => _WebErpScreenState();
......@@ -47,7 +49,8 @@ class _WebErpScreenState extends State<WebErpScreen> {
color: AppColors.app_blue,
);
bool pullToRefreshEnabled = true;
final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();
final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();
static const platform = MethodChannel('in.webgrid.generp/download');
final GlobalKey webViewKey = GlobalKey();
......@@ -56,7 +59,8 @@ class _WebErpScreenState extends State<WebErpScreen> {
void initState() {
// loadData();
super.initState();
pullToRefreshController = kIsWeb
pullToRefreshController =
kIsWeb
? null
: PullToRefreshController(
settings: pullToRefreshSettings,
......@@ -65,21 +69,22 @@ class _WebErpScreenState extends State<WebErpScreen> {
_webViewController?.reload();
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
_webViewController?.loadUrl(
urlRequest:
URLRequest(url: await _webViewController?.getUrl()));
urlRequest: URLRequest(
url: await _webViewController?.getUrl(),
),
);
}
},
);
// print("URL:${widget.url}");
_initializeNotifications();
}
Future<void> _initializeNotifications() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
);
final InitializationSettings initializationSettings =
InitializationSettings(android: initializationSettingsAndroid);
await _notificationsPlugin.initialize(initializationSettings);
// Create a notification channel for Android
......@@ -90,7 +95,9 @@ class _WebErpScreenState extends State<WebErpScreen> {
importance: Importance.high,
);
await _notificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.createNotificationChannel(channel);
}
......@@ -98,6 +105,7 @@ class _WebErpScreenState extends State<WebErpScreen> {
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
......@@ -110,9 +118,10 @@ class _WebErpScreenState extends State<WebErpScreen> {
},
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar:appbar(context, "Web ERP"),
appBar: appbar(context, "Web ERP"),
body: Container(
child: Column(children: <Widget>[
child: Column(
children: <Widget>[
Expanded(
child: Stack(
children: [
......@@ -122,17 +131,19 @@ class _WebErpScreenState extends State<WebErpScreen> {
allowsCellularAccess: true,
allowsConstrainedNetworkAccess: true,
allowsExpensiveNetworkAccess: true,
),
androidOnGeolocationPermissionsShowPrompt:
(InAppWebViewController controller, String origin) async {
androidOnGeolocationPermissionsShowPrompt: (
InAppWebViewController controller,
String origin,
) async {
return GeolocationPermissionShowPromptResponse(
origin: origin, allow: true, retain: true);
origin: origin,
allow: true,
retain: true,
);
},
initialOptions: InAppWebViewGroupOptions(
android: AndroidInAppWebViewOptions(
useWideViewPort: true,
loadWithOverviewMode: true,
allowContentAccess: true,
......@@ -152,10 +163,11 @@ class _WebErpScreenState extends State<WebErpScreen> {
supportMultipleWindows: true,
// Enable camera access
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
allowsLinkPreview: true,
allowsBackForwardNavigationGestures: true,
),
crossPlatform: InAppWebViewOptions(
javaScriptEnabled: true,
......@@ -163,32 +175,50 @@ class _WebErpScreenState extends State<WebErpScreen> {
allowFileAccessFromFileURLs: true,
allowUniversalAccessFromFileURLs: true,
mediaPlaybackRequiresUserGesture: true,
),
),
androidOnPermissionRequest: (InAppWebViewController controller,
String origin, List<String> resources) async {
androidOnPermissionRequest: (
InAppWebViewController controller,
String origin,
List<String> resources,
) async {
return PermissionRequestResponse(
resources: resources,
action: PermissionRequestResponseAction.GRANT);
action: PermissionRequestResponseAction.GRANT,
);
},
onPermissionRequest: (controller, request) async {
return PermissionResponse(
resources: request.resources,
action: PermissionResponseAction.GRANT,
);
},
keepAlive: InAppWebViewKeepAlive(),
onWebViewCreated: (controller) {
_webViewController = controller;
_controller.complete(controller);
_webViewController!.addJavaScriptHandler(
handlerName: 'MobileAppJavascriptInterface',
callback: (args) {
print("JavaScript called MobileAppJavascriptInterface with args: $args");
print(
"JavaScript called MobileAppJavascriptInterface with args: $args",
);
return {'status': 'success'};
},
);
_webViewController!.addJavaScriptHandler(
handlerName: 'downloadFile',
callback: (args) async {
if (Platform.isAndroid) {
final url = args[0] as String;
await _handleDownload(url, '', 'application/octet-stream','');
await _handleDownload(
url,
'',
'application/octet-stream',
'',
);
}
},
);
},
......@@ -225,11 +255,12 @@ class _WebErpScreenState extends State<WebErpScreen> {
allowsLinkPreview: true,
databaseEnabled: true, // Enables the WebView database
clearSessionCache: true,
mediaType:"image/*",
mediaType: "image/*",
),
shouldOverrideUrlLoading:
(controller, navigationAction) async {
shouldOverrideUrlLoading: (
controller,
navigationAction,
) async {
var uri = navigationAction.request.url!;
print("urib scgefes");
print(uri);
......@@ -274,6 +305,9 @@ class _WebErpScreenState extends State<WebErpScreen> {
},
onReceivedError: (controller, request, error) {
pullToRefreshController?.endRefreshing();
return setState(() {
isLoading = false;
});
},
onProgressChanged: (controller, progress) {
if (progress == 100) {
......@@ -285,7 +319,8 @@ class _WebErpScreenState extends State<WebErpScreen> {
debugPrint("consoleMessage${consoleMessage}");
}
debugPrint(
"JavaScript console message: ${consoleMessage.message}");
"JavaScript console message: ${consoleMessage.message}",
);
},
// onDownloadStartRequest: (controller, url) async {
// await ApiCalling.download_files(
......@@ -293,24 +328,41 @@ class _WebErpScreenState extends State<WebErpScreen> {
// .then((data) => {debugPrint(data)});
//
// },
onDownloadStartRequest: (controller, downloadStartRequest) async {
onDownloadStartRequest: (
controller,
downloadStartRequest,
) async {
if (Platform.isAndroid) {
await _handleDownload(
downloadStartRequest.url.toString(),
downloadStartRequest.suggestedFilename!,
downloadStartRequest.mimeType ?? 'application/octet-stream',
downloadStartRequest.mimeType ??
'application/octet-stream',
downloadStartRequest.suggestedFilename ?? '',
);
}
},
shouldInterceptAjaxRequest: (controller, ajaxRequest) async {
shouldInterceptAjaxRequest: (
controller,
ajaxRequest,
) async {
if (Platform.isAndroid) {
if (ajaxRequest.url.toString().contains('download')) {
await _handleDownload(ajaxRequest.url.toString(), '', 'application/octet-stream','');
await _handleDownload(
ajaxRequest.url.toString(),
'',
'application/octet-stream',
'',
);
}
return ajaxRequest;
}
return ajaxRequest;
},
),
if (isLoading) ...[Container(
if (isLoading) ...[
Container(
color: Colors.white.withOpacity(0.7),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
......@@ -322,9 +374,7 @@ class _WebErpScreenState extends State<WebErpScreen> {
// duration: Duration(seconds: 2),
size: 50,
),
const SizedBox(
height: 15,
),
const SizedBox(height: 15),
SizedBox(
width: 200,
child: Text(
......@@ -334,28 +384,41 @@ class _WebErpScreenState extends State<WebErpScreen> {
decorationThickness: 0,
fontSize: 15,
fontWeight: FontWeight.normal,
color: AppColors.app_blue),
color: AppColors.app_blue,
),
),
),
// SvgPicture.asset("/assets/images/NutsLoader.gif")
],
),
)]
),
],
],
))
])),
),
),
],
),
),
),
);
}
Future<void> _handleDownload(String url, String contentDisposition, String mimeType,String suggestedFilename) async {
Future<void> _handleDownload(
String url,
String contentDisposition,
String mimeType,
String suggestedFilename,
) async {
// Request notification permission for Android 13+
if (Platform.isIOS) {
_handleIOSDownload(url, suggestedFilename);
} else if (Platform.isAndroid) {
if (await Permission.notification.request().isGranted) {
try {
// Show custom notification (optional, since DownloadManager shows its own)
if (Platform.isAndroid) {
// Call native Android Download Manager
final userAgent = 'Flutter InAppWebView';
await platform.invokeMethod('startDownload', {
......@@ -365,7 +428,9 @@ class _WebErpScreenState extends State<WebErpScreen> {
'mimeType': mimeType,
'suggestedFilename': suggestedFilename,
});
} else if (Platform.isIOS) {
_handleIOSDownload(url, suggestedFilename);
}
} catch (e) {
print("Download Error $e");
}
......@@ -373,9 +438,108 @@ class _WebErpScreenState extends State<WebErpScreen> {
toast(context, "Notification Permission Denied");
}
}
}
}
Future<void> _handleIOSDownload(String url, String suggestedFilename) async {
try {
// Show initial download notification
await _showDownloadNotification(0, suggestedFilename, isComplete: false);
// Get the temporary directory for iOS
final tempDir = await getTemporaryDirectory();
final fileName =
suggestedFilename.isNotEmpty
? suggestedFilename
: url.split('/').last;
final filePath = '${tempDir.path}/$fileName';
// Download the file using http
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
// Save the file
final file = File(filePath);
await file.writeAsBytes(response.bodyBytes);
// Show completion notification
await _showDownloadNotification(100, fileName, isComplete: true);
// Optionally, open the file or notify the user
toast(context, "File downloaded to $filePath");
} else {
throw Exception("Failed to download file: HTTP ${response.statusCode}");
}
} catch (e) {
print("iOS Download Error: $e");
await _showDownloadNotification(
0,
suggestedFilename,
isComplete: false,
isError: true,
);
toast(context, "Failed to download file: $e");
}
}
Future<void> _showDownloadNotification(
int progress,
String fileName, {
bool isComplete = false,
bool isError = false,
}) async {
final androidDetails = AndroidNotificationDetails(
'download_channel',
'Downloads',
channelDescription: 'Notifications for file downloads',
importance: Importance.high,
priority: Priority.high,
showProgress: !isComplete && !isError,
maxProgress: 100,
progress: progress,
ongoing: !isComplete && !isError,
playSound: isComplete || isError,
styleInformation: BigTextStyleInformation(
isError
? 'Download failed for $fileName'
: isComplete
? 'Download complete: $fileName'
: 'Downloading $fileName...',
),
);
final iosDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: isComplete || isError,
subtitle:
isError
? 'Download failed'
: isComplete
? 'Download complete'
: 'Downloading...',
threadIdentifier: 'download_thread',
);
final notificationDetails = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
);
await _notificationsPlugin.show(
fileName.hashCode, // Unique ID for the notification
isError
? 'Download Failed'
: isComplete
? 'Download Complete'
: 'Downloading File',
isError
? 'Failed to download $fileName'
: isComplete
? 'Successfully downloaded $fileName'
: 'Downloading $fileName ($progress%)',
notificationDetails,
);
}
}
class SpinKitRing extends StatefulWidget {
const SpinKitRing({
......@@ -397,7 +561,8 @@ class SpinKitRing extends StatefulWidget {
State<SpinKitRing> createState() => _SpinKitRingState();
}
class _SpinKitRingState extends State<SpinKitRing> with SingleTickerProviderStateMixin {
class _SpinKitRingState extends State<SpinKitRing>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation1;
late Animation<double> _animation2;
......@@ -407,7 +572,9 @@ class _SpinKitRingState extends State<SpinKitRing> with SingleTickerProviderStat
void initState() {
super.initState();
_controller = (widget.controller ?? AnimationController(vsync: this, duration: widget.duration))
_controller =
(widget.controller ??
AnimationController(vsync: this, duration: widget.duration))
..addListener(() {
if (mounted) {
setState(() {});
......@@ -446,7 +613,8 @@ class _SpinKitRingState extends State<SpinKitRing> with SingleTickerProviderStat
Widget build(BuildContext context) {
return Center(
child: Transform(
transform: Matrix4.identity()..rotateZ((_animation1.value) * 5 * pi / 6),
transform:
Matrix4.identity()..rotateZ((_animation1.value) * 5 * pi / 6),
alignment: FractionalOffset.center,
child: SizedBox.fromSize(
size: Size.square(widget.size),
......@@ -470,7 +638,8 @@ class RingPainter extends CustomPainter {
this.progressPercent,
this.startAngle,
required this.trackColor,
}) : trackPaint = Paint()
}) : trackPaint =
Paint()
..color = trackColor
..style = PaintingStyle.stroke
..strokeWidth = paintWidth
......
......@@ -37,10 +37,10 @@ packages:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
version: "2.13.0"
barcode:
dependency: transitive
description:
......@@ -285,10 +285,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.3"
ffi:
dependency: transitive
description:
......@@ -924,26 +924,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "11.0.1"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
lints:
dependency: transitive
description:
......@@ -1641,10 +1641,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev"
source: hosted
version: "14.3.1"
version: "15.0.0"
web:
dependency: transitive
description:
......
......@@ -180,3 +180,4 @@ flutter:
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
generate: true
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment