134 lines
5.1 KiB
Dart
134 lines
5.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
|
import 'dart:convert';
|
|
|
|
class ListDetailScreen extends StatefulWidget {
|
|
final String title;
|
|
final String? filepath;
|
|
|
|
const ListDetailScreen({super.key, required this.title, this.filepath});
|
|
|
|
@override
|
|
State<ListDetailScreen> createState() => _ListDetailScreenState();
|
|
}
|
|
|
|
class _ListDetailScreenState extends State<ListDetailScreen> {
|
|
late InAppWebViewController _webViewController;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
String _getMimeType(String path) {
|
|
if (path.endsWith('.png')) return 'image/png';
|
|
if (path.endsWith('.jpg') || path.endsWith('.jpeg')) return 'image/jpeg';
|
|
if (path.endsWith('.svg')) return 'image/svg+xml';
|
|
if (path.endsWith('.html')) return 'text/html';
|
|
if (path.endsWith('.css')) return 'text/css';
|
|
if (path.endsWith('.js')) return 'application/javascript';
|
|
return 'application/octet-stream';
|
|
}
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(widget.title)),
|
|
body:
|
|
widget.filepath != null
|
|
? InAppWebView(
|
|
initialUrlRequest: URLRequest(url: WebUri("about:blank")),
|
|
initialOptions: InAppWebViewGroupOptions(
|
|
crossPlatform: InAppWebViewOptions(
|
|
javaScriptEnabled: true,
|
|
allowFileAccessFromFileURLs: true,
|
|
allowUniversalAccessFromFileURLs: true,
|
|
),
|
|
),
|
|
onWebViewCreated: (controller) async {
|
|
_webViewController = controller;
|
|
|
|
final html = await rootBundle.loadString(widget.filepath!);
|
|
final base = widget.filepath!.substring(
|
|
0,
|
|
widget.filepath!.lastIndexOf('/') + 1,
|
|
);
|
|
await controller.loadData(
|
|
data: html,
|
|
baseUrl: WebUri(
|
|
"file:///android_asset/flutter_assets/$base",
|
|
), // agar path relatif seperti img1/* jalan
|
|
mimeType: 'text/html',
|
|
encoding: 'utf-8',
|
|
);
|
|
debugPrint("http://localhost/$base");
|
|
debugPrint("file:///android_asset/flutter_assets/$base");
|
|
},
|
|
onLoadStop: (controller, url) async {
|
|
debugPrint("🚀 onLoadStop called. URL: $url");
|
|
|
|
var result = await controller.evaluateJavascript(
|
|
source: """
|
|
(() => {
|
|
const board = document.getElementById('game-board');
|
|
const hasRender = typeof renderGrid === 'function';
|
|
return { hasRender, boardExists: board !== null };
|
|
})();
|
|
""",
|
|
);
|
|
|
|
debugPrint("📊 Evaluated JS result: $result");
|
|
|
|
final jsCheck = await controller.evaluateJavascript(
|
|
source: """
|
|
typeof renderGrid === 'function' &&
|
|
document.querySelector('#game-board') !== null
|
|
""",
|
|
);
|
|
|
|
debugPrint(
|
|
"Apakah renderGrid tersedia dan board muncul? => $jsCheck",
|
|
);
|
|
|
|
final imageLoaded = await controller.evaluateJavascript(
|
|
source: """
|
|
Array.from(document.images).every(img => img.complete)
|
|
""",
|
|
);
|
|
|
|
debugPrint("Semua gambar berhasil dimuat? => $imageLoaded");
|
|
},
|
|
|
|
// (Opsional) tangkap log dari JS
|
|
onConsoleMessage: (controller, consoleMessage) {
|
|
debugPrint("📢 JS Console: ${consoleMessage.message}");
|
|
},
|
|
shouldInterceptRequest: (controller, request) async {
|
|
final url = request.url;
|
|
if (url == null || url.host != 'localhost') return null;
|
|
|
|
try {
|
|
// Strip "http://localhost/" from the path
|
|
final path = url.path.replaceFirst('/', '');
|
|
|
|
final asset = await rootBundle.load(path);
|
|
final mimeType = _getMimeType(path);
|
|
|
|
return WebResourceResponse(
|
|
contentType: mimeType,
|
|
data: asset.buffer.asUint8List(),
|
|
statusCode: 200,
|
|
reasonPhrase: 'OK',
|
|
);
|
|
} catch (e) {
|
|
print("⚠️ Asset not found: ${url.path} -> $e");
|
|
return WebResourceResponse(
|
|
contentType: 'text/plain',
|
|
data: Uint8List.fromList(utf8.encode('404 Not Found')),
|
|
statusCode: 404,
|
|
reasonPhrase: 'Not Found',
|
|
);
|
|
}
|
|
},
|
|
)
|
|
: const Center(child: Text("Tidak ada file HTML")),
|
|
);
|
|
}
|
|
}
|