ajustes de captura de tela ios e android
This commit is contained in:
parent
bebed14863
commit
d9893fa59e
|
|
@ -31,12 +31,17 @@ if (flutterVersionName == null) {
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.myrobot.MakerBook"
|
namespace = "com.myrobot.MakerBook"
|
||||||
compileSdk = 34 // flutter.compileSdkVersion
|
compileSdk = 36 // flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "17"
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
@ -45,7 +50,7 @@ android {
|
||||||
// You can update the following values to match your application needs.
|
// 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.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
targetSdk = 34 //flutter.targetSdkVersion
|
targetSdk = 36 //flutter.targetSdkVersion
|
||||||
versionCode = flutterVersionCode.toInteger()
|
versionCode = flutterVersionCode.toInteger()
|
||||||
versionName = flutterVersionName
|
versionName = flutterVersionName
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +79,10 @@ android {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
|
||||||
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,43 @@ allprojects {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
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"
|
rootProject.buildDir = "../build"
|
||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
}
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(":app")
|
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) {
|
tasks.register("clean", Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '2.0.20'
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
|
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
org.gradle.jvmargs=-Xmx4096m
|
||||||
|
kotlin.jvm.target=17
|
||||||
|
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
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
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ pluginManagement {
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "7.3.0" apply false
|
id "com.android.application" version "8.6.0" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "1.7.10" 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"
|
include ":app"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
# 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.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
AE54976BBDDFFE7ECF874480 /* [CP] Embed Pods Frameworks */,
|
AE54976BBDDFFE7ECF874480 /* [CP] Embed Pods Frameworks */,
|
||||||
|
851D672B5FE59B27299B483A /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
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";
|
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;
|
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 */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,91 @@ import UIKit
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
|
|
||||||
|
private var secureField: UITextField?
|
||||||
|
private var secureContainer: UIView?
|
||||||
|
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
) -> Bool {
|
) -> 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)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Flutter View Controller-->
|
<!--Flutter View Controller-->
|
||||||
|
|
@ -14,13 +16,14 @@
|
||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
|
<point key="canvasLocation" x="-16" y="-40"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
||||||
|
|
@ -47,5 +47,7 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Usamos a câmera para ler QR Code e permitir o login seguro no Maker Book.</string>
|
<string>Usamos a câmera para ler QR Code e permitir o login seguro no Maker Book.</string>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>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.</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,54 @@
|
||||||
import 'dart:io';
|
//import 'package:MakerBook/secure_screen/screenshot_guard.dart';
|
||||||
import 'package:flutter/material.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';
|
import 'pages/home_page.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
// Só Android tem esse plugin
|
// Android → FLAG_SECURE
|
||||||
if (Platform.isAndroid) {
|
// iOS → blur no app switcher + bloqueio de screen recording
|
||||||
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
|
await ScreenProtector.preventScreenshotOn();
|
||||||
}
|
await ScreenProtector.protectDataLeakageOn();
|
||||||
|
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyApp> createState() => _MyAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyAppState extends State<MyApp> 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:audioplayers/audioplayers.dart';
|
//import 'package:audioplayers/audioplayers.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:just_audio/just_audio.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:MakerBook/pages/epub_page.dart';
|
import 'package:MakerBook/pages/epub_page.dart';
|
||||||
import 'package:MakerBook/pages/qr_code_scanner.dart';
|
import 'package:MakerBook/pages/qr_code_scanner.dart';
|
||||||
|
|
@ -54,8 +55,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
|
|
||||||
await baixarOuAtualizarArquivo(book_id, bookPath, ext, modifiedAt);
|
await baixarOuAtualizarArquivo(book_id, bookPath, ext, modifiedAt);
|
||||||
|
|
||||||
|
//final player = AudioPlayer();
|
||||||
|
//await player.play(AssetSource('sounds/open_book.mp3'));
|
||||||
final player = AudioPlayer();
|
final player = AudioPlayer();
|
||||||
await player.play(AssetSource('sounds/open_book.mp3'));
|
await player.setAsset('assets/sounds/open_book.mp3');
|
||||||
|
await player.play();
|
||||||
|
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
|
|
@ -10,17 +9,27 @@ class PrivacyPage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PrivacyPageState extends State<PrivacyPage> {
|
class _PrivacyPageState extends State<PrivacyPage> {
|
||||||
|
late final WebViewController _controller;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
//late WebViewController _controller;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Necessário para Android quando usando WebView em SDKs antigos
|
_controller = WebViewController()
|
||||||
if (Platform.isAndroid) {
|
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||||
WebView.platform = SurfaceAndroidWebView();
|
..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
|
@override
|
||||||
|
|
@ -34,22 +43,9 @@ class _PrivacyPageState extends State<PrivacyPage> {
|
||||||
),
|
),
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
WebView(
|
WebViewWidget(controller: _controller),
|
||||||
initialUrl: 'https://makereducacional.com.br/privacy.html',
|
|
||||||
javascriptMode: JavascriptMode.unrestricted,
|
|
||||||
onWebViewCreated: (controller) {
|
|
||||||
//_controller = controller;
|
|
||||||
},
|
|
||||||
onPageFinished: (_) {
|
|
||||||
setState(() {
|
|
||||||
_loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (_loading)
|
if (_loading)
|
||||||
const Center(
|
const Center(child: CircularProgressIndicator()),
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,53 @@
|
||||||
import 'package:flutter/material.dart';
|
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 {
|
class QRCodeScannerPage extends StatefulWidget {
|
||||||
const QRCodeScannerPage({Key? key}) : super(key: key);
|
const QRCodeScannerPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_QRCodeScannerPageState createState() => _QRCodeScannerPageState();
|
State<QRCodeScannerPage> createState() => _QRCodeScannerPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _QRCodeScannerPageState extends State<QRCodeScannerPage> {
|
class _QRCodeScannerPageState extends State<QRCodeScannerPage> {
|
||||||
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
|
|
||||||
QRViewController? controller;
|
|
||||||
|
|
||||||
bool lido = false;
|
bool lido = false;
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
controller?.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Leia o QR Code')),
|
appBar: AppBar(title: const Text('Leia o QR Code')),
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
// Câmera
|
// 📷 Câmera
|
||||||
QRView(
|
MobileScanner(
|
||||||
key: qrKey,
|
fit: BoxFit.cover,
|
||||||
onQRViewCreated: _onQRViewCreated,
|
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
|
// 🕶️ Overlay com janela central
|
||||||
Positioned.fill(
|
const Positioned.fill(
|
||||||
child: ScannerOverlay(),
|
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 {
|
class ScannerOverlay extends StatelessWidget {
|
||||||
|
const ScannerOverlay({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(builder: (context, constraints) {
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
|
|
@ -68,10 +59,10 @@ class ScannerOverlay extends StatelessWidget {
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
// Camada escura semi-transparente
|
// Camada escura
|
||||||
Container(color: Colors.black.withOpacity(0.5)),
|
Container(color: Colors.black.withOpacity(0.5)),
|
||||||
|
|
||||||
// Janela recortada no centro
|
// Janela central
|
||||||
Positioned(
|
Positioned(
|
||||||
left: left,
|
left: left,
|
||||||
top: top,
|
top: top,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class IosSecureScreen {
|
||||||
|
static const MethodChannel _ch = MethodChannel('ios_secure_screen');
|
||||||
|
|
||||||
|
static Future<void> enable() async {
|
||||||
|
if (!Platform.isIOS) return;
|
||||||
|
await _ch.invokeMethod('enable');
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> disable() async {
|
||||||
|
if (!Platform.isIOS) return;
|
||||||
|
await _ch.invokeMethod('disable');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
|
//import 'package:flutter_windowmanager/flutter_windowmanager.dart';
|
||||||
|
|
||||||
class SecureScreen {
|
class SecureScreen {
|
||||||
static Future<void> enable() async {
|
static Future<void> enable() async {
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
|
//await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import 'package:MakerBook/utils/global.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:path_provider/path_provider.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 {
|
class EpubViewerPage extends StatefulWidget {
|
||||||
final int book_id;
|
final int book_id;
|
||||||
|
|
@ -28,14 +28,14 @@ class _EpubViewerPageState extends State<EpubViewerPage> {
|
||||||
_prepareTempEpub();
|
_prepareTempEpub();
|
||||||
|
|
||||||
// Registra um listener para capturar o lastLocation quando o leitor informar
|
// 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');
|
print('Localização atual: $locator');
|
||||||
// Armazena o locator como um Map<String, dynamic> em vez de string diretamente
|
// Armazena o locator como um Map<String, dynamic> em vez de string diretamente
|
||||||
lastLocation = locator;
|
lastLocation = locator;
|
||||||
|
|
||||||
await saveLastLocation(widget.book_id, lastLocation);
|
await saveLastLocation(widget.book_id, lastLocation);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
});
|
});*/
|
||||||
|
|
||||||
//openLocalEpub();
|
//openLocalEpub();
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ class _EpubViewerPageState extends State<EpubViewerPage> {
|
||||||
await file.writeAsBytes(data.buffer.asUint8List());
|
await file.writeAsBytes(data.buffer.asUint8List());
|
||||||
|
|
||||||
// Config obrigatória
|
// Config obrigatória
|
||||||
VocsyEpub.setConfig(
|
/*VocsyEpub.setConfig(
|
||||||
themeColor: Colors.blue,
|
themeColor: Colors.blue,
|
||||||
identifier: 'test-book',
|
identifier: 'test-book',
|
||||||
scrollDirection: EpubScrollDirection.VERTICAL,
|
scrollDirection: EpubScrollDirection.VERTICAL,
|
||||||
|
|
@ -57,7 +57,7 @@ class _EpubViewerPageState extends State<EpubViewerPage> {
|
||||||
enableTts: false,
|
enableTts: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
VocsyEpub.open(path);
|
VocsyEpub.open(path);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -84,19 +84,19 @@ class _EpubViewerPageState extends State<EpubViewerPage> {
|
||||||
lastLocation = await getLastLocation(widget.book_id);
|
lastLocation = await getLastLocation(widget.book_id);
|
||||||
|
|
||||||
// Configuração do leitor
|
// Configuração do leitor
|
||||||
VocsyEpub.setConfig(
|
/*VocsyEpub.setConfig(
|
||||||
themeColor: Theme.of(context).primaryColor,
|
themeColor: Theme.of(context).primaryColor,
|
||||||
identifier: widget.book_id.toString(),
|
identifier: widget.book_id.toString(),
|
||||||
scrollDirection: EpubScrollDirection.ALLDIRECTIONS,
|
scrollDirection: EpubScrollDirection.ALLDIRECTIONS,
|
||||||
allowSharing: false,
|
allowSharing: false,
|
||||||
enableTts: false,
|
enableTts: false,
|
||||||
);
|
);*/
|
||||||
|
|
||||||
// Abrindo o arquivo EPUB e usando o lastLocation se estiver disponível
|
// Abrindo o arquivo EPUB e usando o lastLocation se estiver disponível
|
||||||
VocsyEpub.open(
|
/*VocsyEpub.open(
|
||||||
tempFile.path,
|
tempFile.path,
|
||||||
lastLocation: lastLocation != null ? EpubLocator.fromJson(jsonDecode(lastLocation!)) : null,
|
lastLocation: lastLocation != null ? EpubLocator.fromJson(jsonDecode(lastLocation!)) : 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<EpubViewer2Page> {
|
|
||||||
|
|
||||||
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<String, dynamic> 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<void> _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<String, dynamic> 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<void> _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<String, dynamic> fileData = unprotectFile(protectedContent);
|
|
||||||
List<int> 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<void> _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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// widgets/pdf_viewer.dart
|
// widgets/pdf_viewer.dart
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:MakerBook/secure_screen/ios_secure_screen.dart';
|
||||||
import 'package:MakerBook/utils/global.dart';
|
import 'package:MakerBook/utils/global.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_pdfview/flutter_pdfview.dart';
|
import 'package:flutter_pdfview/flutter_pdfview.dart';
|
||||||
|
|
@ -34,6 +35,7 @@ class _PdfViewerState extends State<PdfViewer> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
IosSecureScreen.enable(); // <- liga a “tela segura” no iOS
|
||||||
_loadPdf();
|
_loadPdf();
|
||||||
_verificaSeMostraTutorial();
|
_verificaSeMostraTutorial();
|
||||||
}
|
}
|
||||||
|
|
@ -41,6 +43,7 @@ class _PdfViewerState extends State<PdfViewer> {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_saveLastPage();
|
_saveLastPage();
|
||||||
|
IosSecureScreen.enable(); // <- liga a “tela segura” no iOS
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,7 +383,8 @@ class _PdfViewerState extends State<PdfViewer> {
|
||||||
|
|
||||||
void _verificaSeMostraTutorial() async {
|
void _verificaSeMostraTutorial() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
bool jaViu = true; // prefs.getBool('tutorialPdfVisto') ?? false;
|
bool jaViu = prefs.getBool('tutorialPdfVisto') ?? false;
|
||||||
|
//bool jaViu = false;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
setaTutorial = !jaViu;
|
setaTutorial = !jaViu;
|
||||||
|
|
|
||||||
|
|
@ -8,28 +8,40 @@ class WebViewer extends StatefulWidget {
|
||||||
const WebViewer({super.key, required this.book_id});
|
const WebViewer({super.key, required this.book_id});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_WebViewerState createState() => _WebViewerState();
|
State<WebViewer> createState() => _WebViewerState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _WebViewerState extends State<WebViewer> {
|
class _WebViewerState extends State<WebViewer> {
|
||||||
late WebViewController _controller;
|
late final WebViewController _controller;
|
||||||
bool _loading = true;
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
final fullUrl = baseUrl + widget.book_id;
|
||||||
WebView.platform = SurfaceAndroidWebView();
|
|
||||||
}
|
// 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final fullUrl = baseUrl + widget.book_id;
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Leitor Online"),
|
title: const Text("Leitor Online"),
|
||||||
|
|
@ -38,21 +50,11 @@ class _WebViewerState extends State<WebViewer> {
|
||||||
),
|
),
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
WebView(
|
WebViewWidget(controller: _controller),
|
||||||
initialUrl: fullUrl,
|
|
||||||
javascriptMode: JavascriptMode.unrestricted,
|
|
||||||
userAgent: "Mozilla/5.0 (Mobile; Flutter)",
|
|
||||||
onWebViewCreated: (controller) {
|
|
||||||
_controller = controller;
|
|
||||||
},
|
|
||||||
onPageFinished: (_) {
|
|
||||||
setState(() {
|
|
||||||
_loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (_loading)
|
if (_loading)
|
||||||
const Center(child: CircularProgressIndicator()),
|
const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,6 @@
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_linux
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,18 @@
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import audioplayers_darwin
|
import audio_session
|
||||||
|
import just_audio
|
||||||
|
import mobile_scanner
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
import webview_flutter_wkwebview
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
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"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
# 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
|
# 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.
|
# 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:
|
environment:
|
||||||
sdk: '>=3.4.3 <4.0.0'
|
sdk: '>=3.4.3 <4.0.0'
|
||||||
|
|
@ -32,18 +32,22 @@ dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_pdfview: ^1.0.4
|
flutter_pdfview: ^1.0.4
|
||||||
http: ^1.4.0
|
http: ^1.4.0
|
||||||
flutter_windowmanager: ^0.2.0
|
#flutter_windowmanager: ^0.2.0
|
||||||
qr_code_scanner: ^1.0.0
|
#qr_code_scanner: ^1.0.1
|
||||||
vocsy_epub_viewer: ^3.0.0
|
mobile_scanner: ^6.0.2
|
||||||
|
#vocsy_epub_viewer: ^3.0.0
|
||||||
encrypt: ^5.0.0
|
encrypt: ^5.0.0
|
||||||
epub_view: ^3.2.0
|
epub_view: ^3.2.0
|
||||||
webview_flutter: ^3.0.4
|
webview_flutter: ^4.13.0
|
||||||
flutter_svg: ^1.1.6
|
flutter_svg: ^2.2.3
|
||||||
flutter_launcher_icons: ^0.11.0
|
flutter_launcher_icons: ^0.11.0
|
||||||
google_fonts: ^4.0.4
|
google_fonts: ^6.3.3
|
||||||
audioplayers: ^5.2.1
|
#audioplayers: ^6.5.1
|
||||||
|
just_audio: ^0.9.38
|
||||||
tutorial_coach_mark: ^1.3.2
|
tutorial_coach_mark: ^1.3.2
|
||||||
shared_preferences: ^2.2.0
|
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.
|
# 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
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# 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
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
AudioplayersWindowsPluginRegisterWithRegistrar(
|
|
||||||
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_windows
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue