From d9893fa59ef7f0aef17b7583688f0a08d01f228d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Oliveira?= <54298735+pedroolvj@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:19:11 -0300 Subject: [PATCH] ajustes de captura de tela ios e android --- books_viewer/android/Could | 0 books_viewer/android/Get | 0 books_viewer/android/Namespace | 0 books_viewer/android/Run | 0 books_viewer/android/app/build.gradle | 17 ++- books_viewer/android/build.gradle | 31 ++++- books_viewer/android/gradle.properties | 3 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- books_viewer/android/settings.gradle | 5 +- books_viewer/ios/Podfile | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 18 +++ books_viewer/ios/Runner/AppDelegate.swift | 80 ++++++++++++ .../ios/Runner/Base.lproj/Main.storyboard | 13 +- books_viewer/ios/Runner/Info.plist | 2 + books_viewer/lib/main.dart | 46 ++++++- books_viewer/lib/pages/login_page.dart | 8 +- books_viewer/lib/pages/privacy_page.dart | 38 +++--- books_viewer/lib/pages/qr_code_scanner.dart | 57 ++++----- .../lib/secure_screen/ios_secure_screen.dart | 16 +++ .../lib/secure_screen/secure_screen_io.dart | 6 +- books_viewer/lib/widgets/epub_viewer.dart | 18 +-- books_viewer/lib/widgets/epub_viewer2.dart | 120 ------------------ books_viewer/lib/widgets/pdf_viewer.dart | 6 +- books_viewer/lib/widgets/web_viewer.dart | 46 +++---- .../flutter/generated_plugin_registrant.cc | 4 - .../linux/flutter/generated_plugins.cmake | 1 - .../Flutter/GeneratedPluginRegistrant.swift | 10 +- books_viewer/pubspec.yaml | 22 ++-- .../flutter/generated_plugin_registrant.cc | 3 - .../windows/flutter/generated_plugins.cmake | 1 - 30 files changed, 321 insertions(+), 254 deletions(-) create mode 100644 books_viewer/android/Could create mode 100644 books_viewer/android/Get create mode 100644 books_viewer/android/Namespace create mode 100644 books_viewer/android/Run create mode 100644 books_viewer/lib/secure_screen/ios_secure_screen.dart delete mode 100644 books_viewer/lib/widgets/epub_viewer2.dart diff --git a/books_viewer/android/Could b/books_viewer/android/Could new file mode 100644 index 0000000..e69de29 diff --git a/books_viewer/android/Get b/books_viewer/android/Get new file mode 100644 index 0000000..e69de29 diff --git a/books_viewer/android/Namespace b/books_viewer/android/Namespace new file mode 100644 index 0000000..e69de29 diff --git a/books_viewer/android/Run b/books_viewer/android/Run new file mode 100644 index 0000000..e69de29 diff --git a/books_viewer/android/app/build.gradle b/books_viewer/android/app/build.gradle index aefff25..f2da2db 100644 --- a/books_viewer/android/app/build.gradle +++ b/books_viewer/android/app/build.gradle @@ -31,12 +31,17 @@ if (flutterVersionName == null) { android { namespace = "com.myrobot.MakerBook" - compileSdk = 34 // flutter.compileSdkVersion + compileSdk = 36 // flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + coreLibraryDesugaringEnabled true + } + + kotlinOptions { + jvmTarget = "17" } defaultConfig { @@ -45,7 +50,7 @@ android { // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdk = flutter.minSdkVersion - targetSdk = 34 //flutter.targetSdkVersion + targetSdk = 36 //flutter.targetSdkVersion versionCode = flutterVersionCode.toInteger() versionName = flutterVersionName } @@ -74,6 +79,10 @@ android { } +dependencies { + coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4" +} + flutter { source = "../.." } diff --git a/books_viewer/android/build.gradle b/books_viewer/android/build.gradle index d2ffbff..573e736 100644 --- a/books_viewer/android/build.gradle +++ b/books_viewer/android/build.gradle @@ -3,16 +3,43 @@ allprojects { google() mavenCentral() } + + tasks.withType(JavaCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_17.toString() + targetCompatibility = JavaVersion.VERSION_17.toString() + } + + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + kotlinOptions { + jvmTarget = "17" + } + } } rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { project.evaluationDependsOn(":app") } +subprojects { p -> + // Força especificamente o plugin qr_code_scanner + if (p.name == "qr_code_scanner") { + p.tasks.withType(JavaCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_17.toString() + targetCompatibility = JavaVersion.VERSION_17.toString() + } + p.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + kotlinOptions { jvmTarget = "17" } + } + } +} + + tasks.register("clean", Delete) { delete rootProject.buildDir } + +buildscript { + ext.kotlin_version = '2.0.20' +} diff --git a/books_viewer/android/gradle.properties b/books_viewer/android/gradle.properties index 3b5b324..37c2781 100644 --- a/books_viewer/android/gradle.properties +++ b/books_viewer/android/gradle.properties @@ -1,3 +1,4 @@ -org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +org.gradle.jvmargs=-Xmx4096m +kotlin.jvm.target=17 \ No newline at end of file diff --git a/books_viewer/android/gradle/wrapper/gradle-wrapper.properties b/books_viewer/android/gradle/wrapper/gradle-wrapper.properties index e1ca574..afa1e8e 100644 --- a/books_viewer/android/gradle/wrapper/gradle-wrapper.properties +++ b/books_viewer/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/books_viewer/android/settings.gradle b/books_viewer/android/settings.gradle index 536165d..c35249e 100644 --- a/books_viewer/android/settings.gradle +++ b/books_viewer/android/settings.gradle @@ -18,8 +18,9 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.7.10" apply false + id "com.android.application" version "8.6.0" apply false + id "com.android.library" version "8.6.0" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" diff --git a/books_viewer/ios/Podfile b/books_viewer/ios/Podfile index 620e46e..37f2b44 100644 --- a/books_viewer/ios/Podfile +++ b/books_viewer/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '13.0' +platform :ios, '15.5' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/books_viewer/ios/Runner.xcodeproj/project.pbxproj b/books_viewer/ios/Runner.xcodeproj/project.pbxproj index 36e691c..6fda878 100644 --- a/books_viewer/ios/Runner.xcodeproj/project.pbxproj +++ b/books_viewer/ios/Runner.xcodeproj/project.pbxproj @@ -198,6 +198,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, AE54976BBDDFFE7ECF874480 /* [CP] Embed Pods Frameworks */, + 851D672B5FE59B27299B483A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -329,6 +330,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 851D672B5FE59B27299B483A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; diff --git a/books_viewer/ios/Runner/AppDelegate.swift b/books_viewer/ios/Runner/AppDelegate.swift index 6266644..06523cf 100644 --- a/books_viewer/ios/Runner/AppDelegate.swift +++ b/books_viewer/ios/Runner/AppDelegate.swift @@ -3,11 +3,91 @@ import UIKit @main @objc class AppDelegate: FlutterAppDelegate { + + private var secureField: UITextField? + private var secureContainer: UIView? + override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + let controller = window?.rootViewController as! FlutterViewController + let channel = FlutterMethodChannel(name: "ios_secure_screen", binaryMessenger: controller.binaryMessenger) + + channel.setMethodCallHandler { [weak self] call, result in + guard let self = self else { return } + switch call.method { + case "enable": + self.enableSecureMode() + result(nil) + case "disable": + self.disableSecureMode() + result(nil) + default: + result(FlutterMethodNotImplemented) + } + } + GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + private func enableSecureMode() { + guard let window = self.window else { return } + guard let flutterVC = window.rootViewController else { return } + let flutterView = flutterVC.view! + + if secureContainer != nil { return } + + let field = UITextField(frame: window.bounds) + field.isSecureTextEntry = true + + // IMPORTANTE: precisa ficar interativo, senão mata os toques do FlutterView + field.isUserInteractionEnabled = true + field.isEnabled = true + field.textColor = .clear + field.tintColor = .clear + field.backgroundColor = .clear + field.borderStyle = .none + field.autocorrectionType = .no + field.spellCheckingType = .no + + guard let container = field.subviews.first else { return } + container.frame = window.bounds + container.isUserInteractionEnabled = true + + flutterView.removeFromSuperview() + container.addSubview(flutterView) + flutterView.frame = container.bounds + flutterView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + window.addSubview(field) + field.frame = window.bounds + field.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + self.secureField = field + self.secureContainer = container + } + + private func disableSecureMode() { + guard let window = self.window else { return } + guard let flutterVC = window.rootViewController else { return } + let flutterView = flutterVC.view! + + // Se não está habilitado, sai + guard let field = secureField else { return } + + // Remove flutter do container e volta pra window + flutterView.removeFromSuperview() + window.insertSubview(flutterView, belowSubview: field) + flutterView.frame = window.bounds + flutterView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + + // Remove o campo seguro + field.removeFromSuperview() + + self.secureField = nil + self.secureContainer = nil + } + } diff --git a/books_viewer/ios/Runner/Base.lproj/Main.storyboard b/books_viewer/ios/Runner/Base.lproj/Main.storyboard index f3c2851..4f4167b 100644 --- a/books_viewer/ios/Runner/Base.lproj/Main.storyboard +++ b/books_viewer/ios/Runner/Base.lproj/Main.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -14,13 +16,14 @@ - + - + + diff --git a/books_viewer/ios/Runner/Info.plist b/books_viewer/ios/Runner/Info.plist index abbd6f1..3e8cfa0 100644 --- a/books_viewer/ios/Runner/Info.plist +++ b/books_viewer/ios/Runner/Info.plist @@ -47,5 +47,7 @@ NSCameraUsageDescription Usamos a câmera para ler QR Code e permitir o login seguro no Maker Book. + NSMicrophoneUsageDescription + O Maker Book não grava áudio. Esta permissão pode ser exibida pelo iOS por causa de bibliotecas de reprodução de áudio usadas no app. diff --git a/books_viewer/lib/main.dart b/books_viewer/lib/main.dart index 54fcf01..bb3cc7f 100644 --- a/books_viewer/lib/main.dart +++ b/books_viewer/lib/main.dart @@ -1,22 +1,54 @@ -import 'dart:io'; +//import 'package:MakerBook/secure_screen/screenshot_guard.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_windowmanager/flutter_windowmanager.dart'; +import 'package:screen_protector/screen_protector.dart'; import 'pages/home_page.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - // Só Android tem esse plugin - if (Platform.isAndroid) { - await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE); - } + // Android → FLAG_SECURE + // iOS → blur no app switcher + bloqueio de screen recording + await ScreenProtector.preventScreenshotOn(); + await ScreenProtector.protectDataLeakageOn(); runApp(const MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatefulWidget { const MyApp({super.key}); + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State with WidgetsBindingObserver { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) async { + // iOS: protege quando vai para background / app switcher + if (state == AppLifecycleState.paused || + state == AppLifecycleState.inactive) { + await ScreenProtector.protectDataLeakageOn(); + } + + // remove blur ao voltar + if (state == AppLifecycleState.resumed) { + await ScreenProtector.protectDataLeakageOff(); + } + } + @override Widget build(BuildContext context) { return MaterialApp( diff --git a/books_viewer/lib/pages/login_page.dart b/books_viewer/lib/pages/login_page.dart index bbcb33f..ee28bdb 100644 --- a/books_viewer/lib/pages/login_page.dart +++ b/books_viewer/lib/pages/login_page.dart @@ -2,10 +2,11 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:audioplayers/audioplayers.dart'; +//import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; +import 'package:just_audio/just_audio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:MakerBook/pages/epub_page.dart'; import 'package:MakerBook/pages/qr_code_scanner.dart'; @@ -54,8 +55,11 @@ class _LoginPageState extends State { await baixarOuAtualizarArquivo(book_id, bookPath, ext, modifiedAt); + //final player = AudioPlayer(); + //await player.play(AssetSource('sounds/open_book.mp3')); final player = AudioPlayer(); - await player.play(AssetSource('sounds/open_book.mp3')); + await player.setAsset('assets/sounds/open_book.mp3'); + await player.play(); Navigator.push( context, diff --git a/books_viewer/lib/pages/privacy_page.dart b/books_viewer/lib/pages/privacy_page.dart index 0873bb9..117c962 100644 --- a/books_viewer/lib/pages/privacy_page.dart +++ b/books_viewer/lib/pages/privacy_page.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; @@ -10,17 +9,27 @@ class PrivacyPage extends StatefulWidget { } class _PrivacyPageState extends State { + late final WebViewController _controller; bool _loading = true; - //late WebViewController _controller; @override void initState() { super.initState(); - // Necessário para Android quando usando WebView em SDKs antigos - if (Platform.isAndroid) { - WebView.platform = SurfaceAndroidWebView(); - } + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate( + NavigationDelegate( + onPageFinished: (_) { + setState(() => _loading = false); + }, + onWebResourceError: (error) { + // Opcional: se quiser mostrar algo quando falhar + // print('WebView error: ${error.description}'); + }, + ), + ) + ..loadRequest(Uri.parse('https://makereducacional.com.br/privacy.html')); } @override @@ -34,22 +43,9 @@ class _PrivacyPageState extends State { ), body: Stack( children: [ - WebView( - initialUrl: 'https://makereducacional.com.br/privacy.html', - javascriptMode: JavascriptMode.unrestricted, - onWebViewCreated: (controller) { - //_controller = controller; - }, - onPageFinished: (_) { - setState(() { - _loading = false; - }); - }, - ), + WebViewWidget(controller: _controller), if (_loading) - const Center( - child: CircularProgressIndicator(), - ), + const Center(child: CircularProgressIndicator()), ], ), ); diff --git a/books_viewer/lib/pages/qr_code_scanner.dart b/books_viewer/lib/pages/qr_code_scanner.dart index 4895fae..cf82ddf 100644 --- a/books_viewer/lib/pages/qr_code_scanner.dart +++ b/books_viewer/lib/pages/qr_code_scanner.dart @@ -1,62 +1,53 @@ import 'package:flutter/material.dart'; -import 'package:qr_code_scanner/qr_code_scanner.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; class QRCodeScannerPage extends StatefulWidget { const QRCodeScannerPage({Key? key}) : super(key: key); @override - _QRCodeScannerPageState createState() => _QRCodeScannerPageState(); + State createState() => _QRCodeScannerPageState(); } class _QRCodeScannerPageState extends State { - final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); - QRViewController? controller; - bool lido = false; - @override - void dispose() { - controller?.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Leia o QR Code')), body: Stack( children: [ - // Câmera - QRView( - key: qrKey, - onQRViewCreated: _onQRViewCreated, + // 📷 Câmera + MobileScanner( + fit: BoxFit.cover, + onDetect: (capture) { + if (lido) return; + + final barcode = capture.barcodes.firstOrNull; + final value = barcode?.rawValue; + + if (value == null) return; + + lido = true; + debugPrint('[LOG] Leitura QRCode: $value'); + + Navigator.pop(context, value); + }, ), - // Escurecimento com buraco no centro - Positioned.fill( + // 🕶️ Overlay com janela central + const Positioned.fill( child: ScannerOverlay(), ), ], ), ); } - - - - void _onQRViewCreated(QRViewController controller) { - print("[LOG] QRCode criado"); - this.controller = controller; - controller.scannedDataStream.listen((scanData) { - if (!lido) { - lido = true; - print("[LOG] Leitura QRCode: ${scanData.code}"); - Navigator.pop(context, scanData.code); // Retorna o código escaneado - } - }); - } } class ScannerOverlay extends StatelessWidget { + const ScannerOverlay({super.key}); + @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, constraints) { @@ -68,10 +59,10 @@ class ScannerOverlay extends StatelessWidget { return Stack( children: [ - // Camada escura semi-transparente + // Camada escura Container(color: Colors.black.withOpacity(0.5)), - // Janela recortada no centro + // Janela central Positioned( left: left, top: top, diff --git a/books_viewer/lib/secure_screen/ios_secure_screen.dart b/books_viewer/lib/secure_screen/ios_secure_screen.dart new file mode 100644 index 0000000..fdbf29e --- /dev/null +++ b/books_viewer/lib/secure_screen/ios_secure_screen.dart @@ -0,0 +1,16 @@ +import 'dart:io'; +import 'package:flutter/services.dart'; + +class IosSecureScreen { + static const MethodChannel _ch = MethodChannel('ios_secure_screen'); + + static Future enable() async { + if (!Platform.isIOS) return; + await _ch.invokeMethod('enable'); + } + + static Future disable() async { + if (!Platform.isIOS) return; + await _ch.invokeMethod('disable'); + } +} diff --git a/books_viewer/lib/secure_screen/secure_screen_io.dart b/books_viewer/lib/secure_screen/secure_screen_io.dart index 38604b1..3c93881 100644 --- a/books_viewer/lib/secure_screen/secure_screen_io.dart +++ b/books_viewer/lib/secure_screen/secure_screen_io.dart @@ -1,10 +1,10 @@ import 'dart:io'; -import 'package:flutter_windowmanager/flutter_windowmanager.dart'; +//import 'package:flutter_windowmanager/flutter_windowmanager.dart'; class SecureScreen { static Future enable() async { if (Platform.isAndroid) { - await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE); + //await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE); } } -} +} \ No newline at end of file diff --git a/books_viewer/lib/widgets/epub_viewer.dart b/books_viewer/lib/widgets/epub_viewer.dart index 4a5203e..5043f72 100644 --- a/books_viewer/lib/widgets/epub_viewer.dart +++ b/books_viewer/lib/widgets/epub_viewer.dart @@ -7,7 +7,7 @@ import 'package:MakerBook/utils/global.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:vocsy_epub_viewer/epub_viewer.dart'; +//import 'package:vocsy_epub_viewer/epub_viewer.dart'; class EpubViewerPage extends StatefulWidget { final int book_id; @@ -28,14 +28,14 @@ class _EpubViewerPageState extends State { _prepareTempEpub(); // Registra um listener para capturar o lastLocation quando o leitor informar - VocsyEpub.locatorStream.listen((locator) async { + /*VocsyEpub.locatorStream.listen((locator) async { print('Localização atual: $locator'); // Armazena o locator como um Map em vez de string diretamente lastLocation = locator; await saveLastLocation(widget.book_id, lastLocation); Navigator.pop(context); - }); + });*/ //openLocalEpub(); } @@ -49,7 +49,7 @@ class _EpubViewerPageState extends State { await file.writeAsBytes(data.buffer.asUint8List()); // Config obrigatória - VocsyEpub.setConfig( + /*VocsyEpub.setConfig( themeColor: Colors.blue, identifier: 'test-book', scrollDirection: EpubScrollDirection.VERTICAL, @@ -57,7 +57,7 @@ class _EpubViewerPageState extends State { enableTts: false, ); - VocsyEpub.open(path); + VocsyEpub.open(path);*/ } @override @@ -84,19 +84,19 @@ class _EpubViewerPageState extends State { lastLocation = await getLastLocation(widget.book_id); // Configuração do leitor - VocsyEpub.setConfig( + /*VocsyEpub.setConfig( themeColor: Theme.of(context).primaryColor, identifier: widget.book_id.toString(), scrollDirection: EpubScrollDirection.ALLDIRECTIONS, allowSharing: false, enableTts: false, - ); + );*/ // Abrindo o arquivo EPUB e usando o lastLocation se estiver disponível - VocsyEpub.open( + /*VocsyEpub.open( tempFile.path, lastLocation: lastLocation != null ? EpubLocator.fromJson(jsonDecode(lastLocation!)) : null, - ); + );*/ } diff --git a/books_viewer/lib/widgets/epub_viewer2.dart b/books_viewer/lib/widgets/epub_viewer2.dart deleted file mode 100644 index e467e7d..0000000 --- a/books_viewer/lib/widgets/epub_viewer2.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:MakerBook/utils/encrypt.dart'; -import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:vocsy_epub_viewer/epub_viewer.dart'; - -class EpubViewer2Page extends StatefulWidget { - final int book_id; - - const EpubViewer2Page({super.key, required this.book_id}); - - @override - _EpubViewer2PageState createState() => _EpubViewer2PageState(); -} - -class _EpubViewer2PageState extends State { - - String? lastLocation; - String? epubPath; - - @override - void initState() { - super.initState(); - _prepareTempEpub(); - - //_initializeEpubController(); - - // Registra um listener para capturar o lastLocation quando o leitor informar - VocsyEpub.locatorStream.listen((locator) async { - print('Localização atual: $locator'); - // Armazena o locator como um Map em vez de string diretamente - lastLocation = locator; - - await _saveLastLocation(); - }); - } - - @override - void dispose() { - super.dispose(); - } - - // Função para salvar a última posição de leitura - Future _saveLastLocation() async { - if (lastLocation == null) return; - - final directory = await getApplicationDocumentsDirectory(); - final file = File('${directory.path}/${widget.book_id}.epub'); - - // Recarrega o conteúdo protegido atual, atualiza o lastLocation, e salva novamente - String protectedContent = await file.readAsString(); - Map fileData = unprotectFile(protectedContent); - String updatedProtectedContent = await protectFile(fileData['epubBytes'], lastLocation!); - await file.writeAsString(updatedProtectedContent); - - Navigator.pop(context); - } - - // Prepara o arquivo temporário para o leitor EPUB - Future _prepareTempEpub_bkp() async { - final directoryReal = await getApplicationDocumentsDirectory(); - final file = File('${directoryReal.path}/${widget.book_id}.epub'); - - final directory = await getTemporaryDirectory(); - final tempFile = File('${directory.path}/${widget.book_id}_temp.epub'); - - // Lê o conteúdo protegido e remove a proteção - String protectedContent = await file.readAsString(); - Map fileData = unprotectFile(protectedContent); - List unprotectedBytes = fileData['epubBytes']; - lastLocation = fileData['lastLocation']; // Recupera o lastLocation - - // Salva o arquivo descriptografado no diretório temporário - await tempFile.writeAsBytes(unprotectedBytes); - - // Configuração do leitor - VocsyEpub.setConfig( - themeColor: Theme.of(context).primaryColor, - identifier: widget.book_id.toString(), - scrollDirection: EpubScrollDirection.ALLDIRECTIONS, - allowSharing: false, - enableTts: false, - ); - - // Abrindo o arquivo EPUB e usando o lastLocation se estiver disponível - VocsyEpub.open( - tempFile.path, - lastLocation: lastLocation != null ? EpubLocator.fromJson(jsonDecode(lastLocation!)) : null, - ); - } - - // Prepara o arquivo temporário para o leitor EPUB - Future _prepareTempEpub() async { - final directoryReal = await getApplicationDocumentsDirectory(); - final file = File('${directoryReal.path}/${widget.book_id}.epub'); - - // Configuração do leitor - VocsyEpub.setConfig( - themeColor: Theme.of(context).primaryColor, - identifier: widget.book_id.toString(), - scrollDirection: EpubScrollDirection.ALLDIRECTIONS, - allowSharing: false, - enableTts: false, - ); - - // Abrindo o arquivo EPUB e usando o lastLocation se estiver disponível - VocsyEpub.open( - file.path, - lastLocation: lastLocation != null ? EpubLocator.fromJson(jsonDecode(lastLocation!)) : null, - ); - } - - @override - Widget build(BuildContext context) { - return const Center(child: CircularProgressIndicator()); - } - -} \ No newline at end of file diff --git a/books_viewer/lib/widgets/pdf_viewer.dart b/books_viewer/lib/widgets/pdf_viewer.dart index 8f497f0..1b3b137 100644 --- a/books_viewer/lib/widgets/pdf_viewer.dart +++ b/books_viewer/lib/widgets/pdf_viewer.dart @@ -1,6 +1,7 @@ // widgets/pdf_viewer.dart import 'dart:convert'; +import 'package:MakerBook/secure_screen/ios_secure_screen.dart'; import 'package:MakerBook/utils/global.dart'; import 'package:flutter/material.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart'; @@ -34,6 +35,7 @@ class _PdfViewerState extends State { @override void initState() { super.initState(); + IosSecureScreen.enable(); // <- liga a “tela segura” no iOS _loadPdf(); _verificaSeMostraTutorial(); } @@ -41,6 +43,7 @@ class _PdfViewerState extends State { @override void dispose() { _saveLastPage(); + IosSecureScreen.enable(); // <- liga a “tela segura” no iOS super.dispose(); } @@ -380,7 +383,8 @@ class _PdfViewerState extends State { void _verificaSeMostraTutorial() async { final prefs = await SharedPreferences.getInstance(); - bool jaViu = true; // prefs.getBool('tutorialPdfVisto') ?? false; + bool jaViu = prefs.getBool('tutorialPdfVisto') ?? false; + //bool jaViu = false; setState(() { setaTutorial = !jaViu; diff --git a/books_viewer/lib/widgets/web_viewer.dart b/books_viewer/lib/widgets/web_viewer.dart index 06753d5..1d31141 100644 --- a/books_viewer/lib/widgets/web_viewer.dart +++ b/books_viewer/lib/widgets/web_viewer.dart @@ -8,28 +8,40 @@ class WebViewer extends StatefulWidget { const WebViewer({super.key, required this.book_id}); @override - _WebViewerState createState() => _WebViewerState(); + State createState() => _WebViewerState(); } class _WebViewerState extends State { - late WebViewController _controller; + late final WebViewController _controller; bool _loading = true; - final String baseUrl = "http://192.168.99.115:8080/#fmt=EPUB&mode=read_book&book_id="; + final String baseUrl = + "http://192.168.99.115:8080/#fmt=EPUB&mode=read_book&book_id="; @override void initState() { super.initState(); - if (Platform.isAndroid) { - WebView.platform = SurfaceAndroidWebView(); - } + final fullUrl = baseUrl + widget.book_id; + + // Controller novo (API 4.x) + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setUserAgent("Mozilla/5.0 (Mobile; Flutter)") + ..setNavigationDelegate( + NavigationDelegate( + onPageFinished: (_) { + setState(() { + _loading = false; + }); + }, + ), + ) + ..loadRequest(Uri.parse(fullUrl)); } @override Widget build(BuildContext context) { - final fullUrl = baseUrl + widget.book_id; - return Scaffold( appBar: AppBar( title: const Text("Leitor Online"), @@ -38,21 +50,11 @@ class _WebViewerState extends State { ), body: Stack( children: [ - WebView( - initialUrl: fullUrl, - javascriptMode: JavascriptMode.unrestricted, - userAgent: "Mozilla/5.0 (Mobile; Flutter)", - onWebViewCreated: (controller) { - _controller = controller; - }, - onPageFinished: (_) { - setState(() { - _loading = false; - }); - }, - ), + WebViewWidget(controller: _controller), if (_loading) - const Center(child: CircularProgressIndicator()), + const Center( + child: CircularProgressIndicator(), + ), ], ), ); diff --git a/books_viewer/linux/flutter/generated_plugin_registrant.cc b/books_viewer/linux/flutter/generated_plugin_registrant.cc index 1830e5c..e71a16d 100644 --- a/books_viewer/linux/flutter/generated_plugin_registrant.cc +++ b/books_viewer/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,6 @@ #include "generated_plugin_registrant.h" -#include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); - audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); } diff --git a/books_viewer/linux/flutter/generated_plugins.cmake b/books_viewer/linux/flutter/generated_plugins.cmake index e9abb91..2e1de87 100644 --- a/books_viewer/linux/flutter/generated_plugins.cmake +++ b/books_viewer/linux/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - audioplayers_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/books_viewer/macos/Flutter/GeneratedPluginRegistrant.swift b/books_viewer/macos/Flutter/GeneratedPluginRegistrant.swift index 3165782..ff1fd1a 100644 --- a/books_viewer/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/books_viewer/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,18 @@ import FlutterMacOS import Foundation -import audioplayers_darwin +import audio_session +import just_audio +import mobile_scanner import path_provider_foundation import shared_preferences_foundation +import webview_flutter_wkwebview func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) + AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) + JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) + MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) } diff --git a/books_viewer/pubspec.yaml b/books_viewer/pubspec.yaml index 785f08d..4818e9a 100644 --- a/books_viewer/pubspec.yaml +++ b/books_viewer/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.3+14 +version: 1.0.4+18 environment: sdk: '>=3.4.3 <4.0.0' @@ -32,18 +32,22 @@ dependencies: sdk: flutter flutter_pdfview: ^1.0.4 http: ^1.4.0 - flutter_windowmanager: ^0.2.0 - qr_code_scanner: ^1.0.0 - vocsy_epub_viewer: ^3.0.0 + #flutter_windowmanager: ^0.2.0 + #qr_code_scanner: ^1.0.1 + mobile_scanner: ^6.0.2 + #vocsy_epub_viewer: ^3.0.0 encrypt: ^5.0.0 epub_view: ^3.2.0 - webview_flutter: ^3.0.4 - flutter_svg: ^1.1.6 + webview_flutter: ^4.13.0 + flutter_svg: ^2.2.3 flutter_launcher_icons: ^0.11.0 - google_fonts: ^4.0.4 - audioplayers: ^5.2.1 + google_fonts: ^6.3.3 + #audioplayers: ^6.5.1 + just_audio: ^0.9.38 tutorial_coach_mark: ^1.3.2 shared_preferences: ^2.2.0 + screen_protector: ^1.4.2 + #screenshot_callback: ^3.0.0 # The following adds the Cupertino Icons font to your application. @@ -66,7 +70,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^3.0.0 + flutter_lints: ^6.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/books_viewer/windows/flutter/generated_plugin_registrant.cc b/books_viewer/windows/flutter/generated_plugin_registrant.cc index 09e8e2c..8b6d468 100644 --- a/books_viewer/windows/flutter/generated_plugin_registrant.cc +++ b/books_viewer/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,6 @@ #include "generated_plugin_registrant.h" -#include void RegisterPlugins(flutter::PluginRegistry* registry) { - AudioplayersWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); } diff --git a/books_viewer/windows/flutter/generated_plugins.cmake b/books_viewer/windows/flutter/generated_plugins.cmake index 375535c..b93c4c3 100644 --- a/books_viewer/windows/flutter/generated_plugins.cmake +++ b/books_viewer/windows/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - audioplayers_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST