diff --git a/Frontend/patient_manager/lib/main.dart b/Frontend/patient_manager/lib/main.dart index 424260a9..dc674548 100644 --- a/Frontend/patient_manager/lib/main.dart +++ b/Frontend/patient_manager/lib/main.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:patient_manager/env/env.dart'; import 'package:patient_manager/router/routeGenerator.dart'; import 'package:patient_manager/theme/mihTheme.dart'; -import 'package:no_screenshot/no_screenshot.dart'; +import 'package:flutter_windowmanager/flutter_windowmanager.dart'; class MzanziInnovationHub extends StatefulWidget { const MzanziInnovationHub({ @@ -21,8 +21,6 @@ class _MzanziInnovationHubState extends State { late ThemeMode _themeMode; late MyTheme theme; - final _noScreenshot = NoScreenshot.instance; - Color getPrimany() { return theme.primaryColor(); } @@ -50,32 +48,23 @@ class _MzanziInnovationHubState extends State { }); } - void disableScreenshot() async { - await _noScreenshot.startScreenshotListening(); - bool result = await _noScreenshot.screenshotOff(); - debugPrint('Screenshot Off: $result'); - } - - void setPlatformSpecificPlugins() { - print("is PWA: ${theme.isPwa()}"); - if (theme.isPwa()) { - disableScreenshot(); - //print(object) - } - } - @override void initState() { _themeMode = ThemeMode.dark; theme = MyTheme(); - + theme.platform = Theme.of(context).platform; theme.mode = "Dark"; super.initState(); } @override Widget build(BuildContext context) { - setPlatformSpecificPlugins(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + if (theme.getPlatform() == "Android") { + await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE); + } + }); + double width = MediaQuery.sizeOf(context).width; theme.setScreenType(width); precacheImage(theme.loadingImage(), context); diff --git a/Frontend/patient_manager/lib/pages/authentication/signin.dart b/Frontend/patient_manager/lib/pages/authentication/signin.dart index 91ee484f..9ba838f0 100644 --- a/Frontend/patient_manager/lib/pages/authentication/signin.dart +++ b/Frontend/patient_manager/lib/pages/authentication/signin.dart @@ -304,7 +304,7 @@ class _SignInState extends State { const SizedBox(height: 10), //Heading Text( - 'Sign In (PWA: ${MzanziInnovationHub.of(context)!.theme.isPwa()})', + 'Sign In (${MzanziInnovationHub.of(context)!.theme.getPlatform()})', style: TextStyle( fontSize: 25, fontWeight: FontWeight.bold, diff --git a/Frontend/patient_manager/lib/test_files/test.dart b/Frontend/patient_manager/lib/test_files/test.dart index d0201769..d8c85bf1 100644 --- a/Frontend/patient_manager/lib/test_files/test.dart +++ b/Frontend/patient_manager/lib/test_files/test.dart @@ -1,97 +1,193 @@ -import 'package:flutter/material.dart'; -import 'package:no_screenshot/no_screenshot.dart'; -import 'package:no_screenshot/screenshot_snapshot.dart'; +import 'dart:async'; -void main() { - runApp(const MyApp()); -} +import 'package:flutter/material.dart'; +import 'package:secure_application/secure_application.dart'; + +void main() => runApp(MaterialApp(home: MyApp())); class MyApp extends StatefulWidget { - const MyApp({super.key}); - @override - State createState() => _MyAppState(); + _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { - final _noScreenshot = NoScreenshot.instance; - bool _isListeningToScreenshotSnapshot = false; - ScreenshotSnapshot _latestValue = ScreenshotSnapshot( - isScreenshotProtectionOn: false, - wasScreenshotTaken: false, - screenshotPath: '', - ); + bool failedAuth = false; + double blurr = 20; + double opacity = 0.6; + StreamSubscription? subLock; + List history = []; @override void initState() { super.initState(); - _noScreenshot.screenshotStream.listen((value) { - setState(() { - _latestValue = value; - }); - }); + } + + @override + void dispose() { + subLock?.cancel(); + super.dispose(); } @override Widget build(BuildContext context) { + var width = MediaQuery.of(context).size.width * 0.8; return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('No Screenshot Plugin Example'), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ElevatedButton( - onPressed: () async { - await _noScreenshot.startScreenshotListening(); - setState(() { - _isListeningToScreenshotSnapshot = true; - }); - }, - child: const Text('Start Listening'), + home: SecureApplication( + nativeRemoveDelay: 1000, + onNeedUnlock: (secure) async { + print( + 'need unlock maybe use biometric to confirm and then sercure.unlock() or you can use the lockedBuilder'); + // var authResult = authMyUser(); + // if (authResul) { + // secure.unlock(); + // return SecureApplicationAuthenticationStatus.SUCCESS; + //} + // else { + // return SecureApplicationAuthenticationStatus.FAILED; + //} + return null; + }, + onAuthenticationFailed: () async { + // clean you data + setState(() { + failedAuth = true; + }); + print('auth failed'); + }, + onAuthenticationSucceed: () async { + // clean you data + + setState(() { + failedAuth = false; + }); + print('auth success'); + }, + child: Builder(builder: (context) { + if (subLock == null) + subLock = SecureApplicationProvider.of(context, listen: false) + ?.lockEvents + .listen((s) => history.add( + '${DateTime.now().toIso8601String()} - ${s ? 'locked' : 'unlocked'}')); + return SecureGate( + blurr: blurr, + opacity: opacity, + lockedBuilder: (context, secureNotifier) => Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + child: Text('UNLOCK'), + onPressed: () => secureNotifier?.authSuccess(unlock: true), + ), + ElevatedButton( + child: Text('FAIL AUTHENTICATION'), + onPressed: () => secureNotifier?.authFailed(unlock: true), + ), + ], + )), + child: Scaffold( + appBar: AppBar( + title: const Text('Secure Window Example'), ), - ElevatedButton( - onPressed: () async { - await _noScreenshot.stopScreenshotListening(); - setState(() { - _isListeningToScreenshotSnapshot = false; - }); - }, - child: const Text('Stop Listening'), + body: Center( + child: Builder(builder: (context) { + var valueNotifier = SecureApplicationProvider.of(context); + if (valueNotifier == null) + throw new Exception( + 'Unable to find secure application context'); + return ListView( + children: [ + Text('This is secure content'), + ValueListenableBuilder( + valueListenable: valueNotifier, + builder: (context, state, _) => state.secured + ? Column( + children: [ + ElevatedButton( + onPressed: () => valueNotifier.open(), + child: Text('Open app'), + ), + state.paused + ? ElevatedButton( + onPressed: () => + valueNotifier.unpause(), + child: Text('resume security'), + ) + : ElevatedButton( + onPressed: () => + valueNotifier.pause(), + child: Text('pause security'), + ), + ], + ) + : ElevatedButton( + onPressed: () => valueNotifier.secure(), + child: Text('Secure app'), + ), + ), + failedAuth + ? Text( + 'Auth failed we cleaned sensitive data', + style: TextStyle(color: Colors.red), + ) + : Text( + 'Auth success', + style: TextStyle(color: Colors.green), + ), + FlutterLogo( + size: width, + ), + StreamBuilder( + stream: valueNotifier.authenticationEvents, + builder: (context, snapshot) => + Text('Last auth status is: ${snapshot.data}'), + ), + ElevatedButton( + onPressed: () => valueNotifier.lock(), + child: Text('manually lock'), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Text('Blurr:'), + Expanded( + child: Slider( + value: blurr, + min: 0, + max: 100, + onChanged: (v) => setState(() => blurr = v)), + ), + Text(blurr.floor().toString()), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Text('opacity:'), + Expanded( + child: Slider( + value: opacity, + min: 0, + max: 1, + onChanged: (v) => + setState(() => opacity = v)), + ), + Text((opacity * 100).floor().toString() + "%"), + ], + ), + ), + ...history.map((h) => Text(h)).toList(), + ], + ); + }), ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Text( - "Screenshot Streaming is ${_isListeningToScreenshotSnapshot ? 'ON' : 'OFF'}\n\nIsScreenshotProtectionOn: ${_latestValue.isScreenshotProtectionOn}\nwasScreenshotTaken: ${_latestValue.wasScreenshotTaken}\nScreenshot Path: ${_latestValue.screenshotPath}"), - ), - ElevatedButton( - onPressed: () async { - bool result = await _noScreenshot.screenshotOff(); - debugPrint('Screenshot Off: $result'); - }, - child: const Text('Disable Screenshot'), - ), - ElevatedButton( - onPressed: () async { - bool result = await _noScreenshot.screenshotOn(); - debugPrint('Enable Screenshot: $result'); - }, - child: const Text('Enable Screenshot'), - ), - ElevatedButton( - onPressed: () async { - bool result = await _noScreenshot.toggleScreenshot(); - debugPrint('Toggle Screenshot: $result'); - }, - child: const Text('Toggle Screenshot'), - ), - const SizedBox(height: 20), - ], - ), - ), + ), + ); + }), ), ); } -} +} \ No newline at end of file diff --git a/Frontend/patient_manager/lib/theme/mihTheme.dart b/Frontend/patient_manager/lib/theme/mihTheme.dart index e6eaa8f4..c6924cfc 100644 --- a/Frontend/patient_manager/lib/theme/mihTheme.dart +++ b/Frontend/patient_manager/lib/theme/mihTheme.dart @@ -10,6 +10,7 @@ class MyTheme { late String mode; late String screenType; late AssetImage loading; + late TargetPlatform platform; bool kIsWeb = const bool.fromEnvironment('dart.library.js_util'); // Options:- // f3f9d2 = Cream @@ -74,6 +75,19 @@ class MyTheme { )); } + String getPlatform() { + if (kIsWeb) { + return "Web"; + } else if (isPwa()) { + if (platform == TargetPlatform.android) { + return "Android"; + } else if (platform == TargetPlatform.iOS) { + return "iOS"; + } + } + return "Other"; + } + bool isPwa() { return html.window.matchMedia('(display-mode: standalone)').matches; } diff --git a/Frontend/patient_manager/macos/Flutter/GeneratedPluginRegistrant.swift b/Frontend/patient_manager/macos/Flutter/GeneratedPluginRegistrant.swift index b80957e7..71b7ea6c 100644 --- a/Frontend/patient_manager/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/Frontend/patient_manager/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,7 +8,6 @@ import Foundation import app_links import device_info_plus import google_sign_in_ios -import no_screenshot import path_provider_foundation import shared_preferences_foundation import sign_in_with_apple @@ -19,7 +18,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) - NoScreenshotPlugin.register(with: registry.registrar(forPlugin: "NoScreenshotPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) diff --git a/Frontend/patient_manager/pubspec.lock b/Frontend/patient_manager/pubspec.lock index 19ba1ce0..61e6d018 100644 --- a/Frontend/patient_manager/pubspec.lock +++ b/Frontend/patient_manager/pubspec.lock @@ -400,6 +400,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_windowmanager: + dependency: "direct main" + description: + name: flutter_windowmanager + sha256: b4d0bc06f6777952b729c0cdb7ce9ad1ecabd8b8b1cb0acb57a36621457dab1b + url: "https://pub.dev" + source: hosted + version: "0.2.0" font_awesome_flutter: dependency: transitive description: @@ -688,14 +696,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.27" - no_screenshot: - dependency: "direct main" - description: - name: no_screenshot - sha256: ec3d86d7ee89a09c3a3939c1003012536ba4b3fcb4f8cbd23d87ada595c99258 - url: "https://pub.dev" - source: hosted - version: "0.3.1" package_config: dependency: transitive description: @@ -844,10 +844,10 @@ packages: dependency: transitive description: name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" url: "https://pub.dev" source: hosted - version: "0.28.0" + version: "0.27.7" scratch_space: dependency: transitive description: @@ -856,6 +856,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + secure_application: + dependency: "direct main" + description: + name: secure_application + sha256: b8e34b4bc2467a3a3c0a649e46ae6a442df7ca27aeaddebb8a53c40656da0385 + url: "https://pub.dev" + source: hosted + version: "4.0.1" shared_preferences: dependency: transitive description: diff --git a/Frontend/patient_manager/pubspec.yaml b/Frontend/patient_manager/pubspec.yaml index 9f5ef65b..adb76166 100644 --- a/Frontend/patient_manager/pubspec.yaml +++ b/Frontend/patient_manager/pubspec.yaml @@ -50,9 +50,10 @@ dependencies: gif: ^2.3.0 intl: ^0.19.0 flutter_native_splash: ^2.4.1 - no_screenshot: ^0.3.1 #google_maps_flutter_web: ^0.5.10 url_strategy: ^0.3.0 + secure_application: ^4.0.1 + flutter_windowmanager: ^0.2.0 dev_dependencies: flutter_test: diff --git a/Frontend/patient_manager/windows/flutter/generated_plugin_registrant.cc b/Frontend/patient_manager/windows/flutter/generated_plugin_registrant.cc index 444f34f1..ce97f888 100644 --- a/Frontend/patient_manager/windows/flutter/generated_plugin_registrant.cc +++ b/Frontend/patient_manager/windows/flutter/generated_plugin_registrant.cc @@ -7,12 +7,15 @@ #include "generated_plugin_registrant.h" #include +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { AppLinksPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("AppLinksPluginCApi")); + SecureApplicationPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SecureApplicationPlugin")); SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("SyncfusionPdfviewerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/Frontend/patient_manager/windows/flutter/generated_plugins.cmake b/Frontend/patient_manager/windows/flutter/generated_plugins.cmake index 0b201a1d..9c12cf88 100644 --- a/Frontend/patient_manager/windows/flutter/generated_plugins.cmake +++ b/Frontend/patient_manager/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links + secure_application syncfusion_pdfviewer_windows url_launcher_windows )