From 6ad6b6ccbd1629d552cefb390c7809372895e4c9 Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 15:41:55 +0200 Subject: [PATCH] Support linux version of MIH --- mih_ui/lib/mih_config/mih_env.dart | 12 ++----- mih_ui/lib/mih_config/mih_theme.dart | 6 ++++ .../mih_package_components/mih_package.dart | 5 +-- .../package_tools/mih_business_qr_code.dart | 19 +++++++++-- .../builder/build_loyalty_card_list.dart | 6 ++-- .../lib/mih_services/mih_alert_services.dart | 6 +++- .../lib/mih_services/mih_file_services.dart | 4 ++- .../mih_services/mih_location_services.dart | 8 +++++ mih_ui/pubspec.lock | 32 +++++++++++++++++++ mih_ui/pubspec.yaml | 1 + 10 files changed, 81 insertions(+), 18 deletions(-) diff --git a/mih_ui/lib/mih_config/mih_env.dart b/mih_ui/lib/mih_config/mih_env.dart index e9dcdd2f..9af57766 100644 --- a/mih_ui/lib/mih_config/mih_env.dart +++ b/mih_ui/lib/mih_config/mih_env.dart @@ -20,13 +20,13 @@ abstract class AppEnviroment { switch (env) { case Enviroment.dev: { - if (kIsWeb) { + if (kIsWeb || Platform.isIOS || Platform.isLinux) { //================= Web Dev Urls ================= baseAppUrl = "http://localhost:80"; baseApiUrl = "http://localhost:8080"; baseFileUrl = "http://localhost:9000"; baseAiUrl = "http://localhost:11434"; - bannerAdUnitId = 'ca-app-pub-3940256099942544/2435281174'; + bannerAdUnitId = 'ca-app-pub-3940256099942544/2435281174'; // IOS ID break; } else if (Platform.isAndroid) { //================= Android Dev Urls ================= @@ -35,14 +35,6 @@ abstract class AppEnviroment { baseFileUrl = "http://10.0.2.2:9000"; baseAiUrl = "http://10.0.2.2:11434"; bannerAdUnitId = 'ca-app-pub-3940256099942544/9214589741'; - } else { - //================= Web & iOS Dev Urls ================= - baseAppUrl = "http://localhost:80"; - baseApiUrl = "http://localhost:8080"; - baseFileUrl = "http://localhost:9000"; - baseAiUrl = "http://localhost:11434"; - bannerAdUnitId = 'ca-app-pub-3940256099942544/2435281174'; - break; } } case Enviroment.prod: diff --git a/mih_ui/lib/mih_config/mih_theme.dart b/mih_ui/lib/mih_config/mih_theme.dart index 02f1fa42..1e4870cc 100644 --- a/mih_ui/lib/mih_config/mih_theme.dart +++ b/mih_ui/lib/mih_config/mih_theme.dart @@ -98,6 +98,12 @@ class MihTheme { return "Android"; } else if (platform == TargetPlatform.iOS) { return "iOS"; + } else if (platform == TargetPlatform.linux) { + return "Linux"; + } else if (platform == TargetPlatform.macOS) { + return "macOS"; + } else if (platform == TargetPlatform.windows) { + return "Windows"; } } return "Other"; diff --git a/mih_ui/lib/mih_package_components/mih_package.dart b/mih_ui/lib/mih_package_components/mih_package.dart index e402d564..f387f5c7 100644 --- a/mih_ui/lib/mih_package_components/mih_package.dart +++ b/mih_ui/lib/mih_package_components/mih_package.dart @@ -1,7 +1,8 @@ +import 'dart:io'; + import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; -import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_scack_bar.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/components/mih_app_drawer.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tools.dart'; @@ -100,7 +101,7 @@ class _MihPackageState extends State // _peakAnimation(); // }); // } - if (!MzansiInnovationHub.of(context)!.theme.kIsWeb) { + if (Platform.isAndroid || Platform.isIOS) { // Trigger the peak animation only AFTER the route transition is complete WidgetsBinding.instance.addPostFrameCallback((_) { final ModalRoute? currentRoute = ModalRoute.of(context); diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 4d6fd736..ab1142fa 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_saver/file_saver.dart'; @@ -82,6 +84,19 @@ class _MihBusinessQrCodeState extends State { fileExtension: "png", mimeType: MimeType.png, ); + } else if (defaultTargetPlatform == TargetPlatform.linux || + defaultTargetPlatform == TargetPlatform.windows) { + // Use File Picker to get a save path on Desktop + String? outputFile = await FilePicker.platform.saveFile( + dialogTitle: 'Please select where to save your QR Code:', + fileName: filename, + ); + + if (outputFile != null) { + final file = File(outputFile); + await file.writeAsBytes(imageBytes); + KenLogger.success("Saved to $outputFile"); + } } else { await FileSaver.instance.saveAs( name: filename, @@ -95,14 +110,14 @@ class _MihBusinessQrCodeState extends State { Future downloadQrCode() async { if (_isUserSignedIn) { await screenshotController.capture().then((image) { - KenLogger.success("Image Captured: $image"); + // KenLogger.success("Image Captured: $image"); setState(() { businessQRImageFile = image; }); }).catchError((onError) { KenLogger.error(onError); }); - KenLogger.success("QR Code Image Captured : $businessQRImageFile"); + // KenLogger.success("QR Code Image Captured : $businessQRImageFile"); saveImage(businessQRImageFile!); } else { showSignInRequiredAlert(); diff --git a/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index 9a7e84bf..be1cde25 100644 --- a/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; @@ -545,7 +547,7 @@ class _BuildLoyaltyCardListState extends State { ), ), SizedBox(height: 10), - MihBannerAd() + if (Platform.isAndroid || Platform.isIOS) MihBannerAd() // MihBannerAd(), ], ), @@ -572,7 +574,7 @@ class _BuildLoyaltyCardListState extends State { } Future setScreenBrightness(double newBrightness) async { - if (!kIsWeb) { + if (!kIsWeb && !Platform.isLinux) { bool canChange = await ScreenBrightness.instance.canChangeSystemBrightness; diff --git a/mih_ui/lib/mih_services/mih_alert_services.dart b/mih_ui/lib/mih_services/mih_alert_services.dart index fe01c2ce..c2e4e721 100644 --- a/mih_ui/lib/mih_services/mih_alert_services.dart +++ b/mih_ui/lib/mih_services/mih_alert_services.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; @@ -134,7 +136,9 @@ class MihAlertServices { ), const SizedBox(height: 15), Text( - "To get the most out of MIH, we need your location. Please go to the site settings of the app and enable location services. Once you do that, we can start showing you relevant information based on your location.", + Platform.isLinux + ? "To get the most out of MIH, we need your location. Please go to your System Settings and enable location services. Once you do that, we can start showing you relevant information based on your location." + : "To get the most out of MIH, we need your location. Please go to the site settings of the app and enable location services. Once you do that, we can start showing you relevant information based on your location.", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == diff --git a/mih_ui/lib/mih_services/mih_file_services.dart b/mih_ui/lib/mih_services/mih_file_services.dart index 76a15836..9dd0c8a8 100644 --- a/mih_ui/lib/mih_services/mih_file_services.dart +++ b/mih_ui/lib/mih_services/mih_file_services.dart @@ -55,10 +55,12 @@ class MihFileApi { // Navigator.of(context).pop(); // Always pop loading dialog } KenLogger.success("File URL: $fileUrl"); - if (AppEnviroment.getEnv() == "Dev" && isSkiaWeb) { + if (AppEnviroment.getEnv() == "Dev" && kIsWeb) { fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); } else if (AppEnviroment.getEnv() == "Dev" && Platform.isIOS) { fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); + } else if (AppEnviroment.getEnv() == "Dev" && Platform.isLinux) { + fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); } KenLogger.success("File URL: $fileUrl"); return fileUrl; diff --git a/mih_ui/lib/mih_services/mih_location_services.dart b/mih_ui/lib/mih_services/mih_location_services.dart index a27c6e61..a18d745c 100644 --- a/mih_ui/lib/mih_services/mih_location_services.dart +++ b/mih_ui/lib/mih_services/mih_location_services.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -13,6 +15,12 @@ class MIHLocationAPI { ///if user has blocked permission (denied or denied forver), user will get error pop up. ///if user has granted permission (while in use), function will return Position object. Future getGPSPosition(BuildContext context) async { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled && Platform.isLinux) { + // Direct the user to their System Settings + MihAlertServices().locationPermissionAlert(context); + return null; + } print("Before checkPermission"); // Debug LocationPermission permission = await Geolocator.checkPermission(); print("After checkPermission: $permission"); // Debug diff --git a/mih_ui/pubspec.lock b/mih_ui/pubspec.lock index 6c3cdb57..a253f2b4 100644 --- a/mih_ui/pubspec.lock +++ b/mih_ui/pubspec.lock @@ -369,6 +369,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" device_info_plus: dependency: transitive description: @@ -808,6 +816,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + geoclue: + dependency: transitive + description: + name: geoclue + sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f + url: "https://pub.dev" + source: hosted + version: "0.1.1" geolocator: dependency: "direct main" description: @@ -832,6 +848,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.13" + geolocator_linux: + dependency: "direct main" + description: + name: geolocator_linux + sha256: d64112a205931926f4363bb6bd48f14cb38e7326833041d170615586cd143797 + url: "https://pub.dev" + source: hosted + version: "0.2.4" geolocator_platform_interface: dependency: transitive description: @@ -904,6 +928,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + gsettings: + dependency: transitive + description: + name: gsettings + sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" + url: "https://pub.dev" + source: hosted + version: "0.2.8" html: dependency: transitive description: diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index f0b73b3e..e7d52726 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: flutter_native_splash: ^2.4.6 printing: ^5.13.3 geolocator: ^14.0.1 + geolocator_linux: ^0.2.4 table_calendar: ^3.1.2 youtube_player_iframe: ^5.2.0 mobile_scanner: ^7.0.1