html content
This commit is contained in:
@@ -55,7 +55,13 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
||||
charSex: "Laki-laki",
|
||||
charOrigin: "Jawa Barat",
|
||||
content:
|
||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan! Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang, hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol, Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk di dekatnya saat ia bercerita.
|
||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan!
|
||||
Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang,
|
||||
hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras,
|
||||
suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol,
|
||||
Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur
|
||||
orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah
|
||||
duduk di dekatnya saat ia bercerita.
|
||||
""",
|
||||
),
|
||||
),
|
||||
@@ -119,8 +125,20 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
||||
charName: "Cepot",
|
||||
charSex: "Laki-laki",
|
||||
charOrigin: "Jawa Barat",
|
||||
content:
|
||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan! Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang, hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol, Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk di dekatnya saat ia bercerita.
|
||||
content: """
|
||||
Cepot adalah sosok yang begitu menarik—aneh,
|
||||
ceria, dan penuh kejutan! Ia muncul seperti
|
||||
tokoh dari dongeng lama yang lupa pulang ke rumah,
|
||||
dengan wajah merah seperti apel matang,
|
||||
hidung besar yang tampak siap
|
||||
mencium rahasia, dan mata bulat
|
||||
yang selalu bersinar penuh rasa ingin
|
||||
tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat
|
||||
pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol,
|
||||
Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan
|
||||
yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak
|
||||
menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk
|
||||
di dekatnya saat ia bercerita.
|
||||
""",
|
||||
),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
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> {
|
||||
List<bool> checklist = [];
|
||||
late WebViewController _controller;
|
||||
late String? fPath = widget.filepath;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller =
|
||||
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||
checklist = List.generate(paragraphs.length, (index) => false);
|
||||
if (fPath != null && fPath!.isNotEmpty) {
|
||||
_loadContent(fPath!); // <- ini penting
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> paragraphs = [
|
||||
"Paragraf pertama tentang ${"widget.title"}.",
|
||||
"Paragraf kedua dengan informasi tambahan.",
|
||||
"Paragraf ketiga yang menjelaskan detail lebih lanjut.",
|
||||
"Paragraf keempat yang melengkapi pembahasan.",
|
||||
];
|
||||
|
||||
void _loadContent(String path) async {
|
||||
try {
|
||||
if (path.startsWith('http')) {
|
||||
_controller.loadRequest(Uri.parse(path));
|
||||
} else {
|
||||
String fileHtml = await rootBundle.loadString(path);
|
||||
_controller.loadHtmlString(fileHtml);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Error loading HTML: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(title: Text(widget.title)),
|
||||
body:
|
||||
(fPath != null && fPath!.isNotEmpty)
|
||||
? WebViewWidget(controller: _controller)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/default.png',
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Ini adalah detail dari ${widget.title}.",
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: paragraphs.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(paragraphs[index]),
|
||||
trailing: Checkbox(
|
||||
value: checklist[index],
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
checklist[index] = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class ListDetailScreen extends StatefulWidget {
|
||||
final String title;
|
||||
@@ -13,89 +14,118 @@ class ListDetailScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ListDetailScreenState extends State<ListDetailScreen> {
|
||||
List<bool> checklist = [];
|
||||
late WebViewController _controller;
|
||||
late String? fPath = widget.filepath;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
checklist = List.generate(paragraphs.length, (index) => false);
|
||||
}
|
||||
|
||||
final List<String> paragraphs = [
|
||||
"Paragraf pertama tentang ${"widget.title"}.",
|
||||
"Paragraf kedua dengan informasi tambahan.",
|
||||
"Paragraf ketiga yang menjelaskan detail lebih lanjut.",
|
||||
"Paragraf keempat yang melengkapi pembahasan.",
|
||||
];
|
||||
|
||||
void _loadContent(String path) async {
|
||||
if (path.startsWith('http')) {
|
||||
// Load dari Internet
|
||||
_controller.loadRequest(Uri.parse(path));
|
||||
} else {
|
||||
// Load dari assets lokal
|
||||
String fileHtml = await rootBundle.loadString(path);
|
||||
_controller.loadHtmlString(fileHtml);
|
||||
}
|
||||
}
|
||||
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(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(title: Text(widget.title)),
|
||||
body:
|
||||
(fPath != null && fPath!.isNotEmpty)
|
||||
? WebViewWidget(controller: _controller)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Gambar di kiri atas dengan teks di kanan
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/default.png', // Ganti dengan gambar yang sesuai
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Ini adalah detail dari ${widget.title}.",
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Paragraf dengan checklist
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: paragraphs.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(paragraphs[index]),
|
||||
trailing: Checkbox(
|
||||
value: checklist[index],
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
checklist[index] = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
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(
|
||||
"http://localhost/$base",
|
||||
), // agar path relatif seperti img1/* jalan
|
||||
mimeType: 'text/html',
|
||||
encoding: 'utf-8',
|
||||
);
|
||||
},
|
||||
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")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ import 'package:flutter/services.dart';
|
||||
import 'package:freekake/components/card_list.dart';
|
||||
import 'package:freekake/components/collection_container%20copy.dart';
|
||||
import 'package:freekake/helpers/color_helper.dart';
|
||||
import 'package:freekake/screen/pustaka/list_detail_screen.dart';
|
||||
import 'package:list_detail_extension/list_detail_extension.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
class ListEducation extends StatefulWidget {
|
||||
const ListEducation({super.key});
|
||||
final String? selectedCategory;
|
||||
const ListEducation({super.key, this.selectedCategory});
|
||||
|
||||
@override
|
||||
State<ListEducation> createState() => _ListEducationState();
|
||||
@@ -22,8 +24,7 @@ class _ListEducationState extends State<ListEducation> {
|
||||
late final WebViewController _controller;
|
||||
late String urlOrAssetPath;
|
||||
bool _shouldShowWebView = false;
|
||||
|
||||
// load extension
|
||||
String? selectedCategory;
|
||||
final listDetailExtension = ListDetailExtension();
|
||||
|
||||
Future<void> _initExtension() async {
|
||||
@@ -69,18 +70,55 @@ class _ListEducationState extends State<ListEducation> {
|
||||
""",
|
||||
"file": "assets/html/index.html",
|
||||
},
|
||||
{
|
||||
"title": "Memori Game",
|
||||
"image": "assets/html/freekake.png",
|
||||
"color": "#cef1da",
|
||||
"category": "Gizi",
|
||||
"type": "Materi",
|
||||
"point": "100",
|
||||
"coint": "20",
|
||||
"body":
|
||||
"""Game untuk melatih daya ingat siswa, sehingga bisa diharapkan bisa
|
||||
menemukan cara sendiri untuk mengingat sesuatu
|
||||
""",
|
||||
"file": "assets/html/memory/memory.html",
|
||||
},
|
||||
{
|
||||
"title": "Find Words",
|
||||
"image": "assets/html/freekake.png",
|
||||
"color": "#cef1da",
|
||||
"category": "Kesehatan",
|
||||
"type": "Materi",
|
||||
"point": "100",
|
||||
"coint": "20",
|
||||
"body": """
|
||||
No Descripptions
|
||||
""",
|
||||
"file": "assets/html/findwords/findwords.html",
|
||||
},
|
||||
];
|
||||
List<Map<String, dynamic>> filteredItems = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
filteredItems = List.from(_listContent);
|
||||
|
||||
selectedCategory = widget.selectedCategory;
|
||||
print(selectedCategory);
|
||||
if (selectedCategory != null && selectedCategory!.isNotEmpty) {
|
||||
filteredItems =
|
||||
_listContent
|
||||
.where((item) => item["category"] == selectedCategory)
|
||||
.toList();
|
||||
} else {
|
||||
filteredItems = List.from(_listContent);
|
||||
}
|
||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||
_shouldShowWebView = true;
|
||||
_controller =
|
||||
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||
urlOrAssetPath = "assets/makanan_bergizi/index.html";
|
||||
urlOrAssetPath = "assets/html/index.html";
|
||||
_loadContent(urlOrAssetPath);
|
||||
_initExtension();
|
||||
}
|
||||
@@ -92,18 +130,20 @@ class _ListEducationState extends State<ListEducation> {
|
||||
// Load dari Internet
|
||||
_controller.loadRequest(Uri.parse(path));
|
||||
} else {
|
||||
// Load dari assets lokal
|
||||
// String fileHtml = await rootBundle.loadString(path);
|
||||
String fileHtml = await DefaultAssetBundle.of(
|
||||
context,
|
||||
).loadString('assets/html/index.html');
|
||||
_controller.loadHtmlString(fileHtml);
|
||||
try {
|
||||
await rootBundle.load(path);
|
||||
await _controller.loadFlutterAsset(path);
|
||||
} catch (e) {
|
||||
print("Gagal memuat file HTML: $path\nError: $e");
|
||||
}
|
||||
_controller.loadFlutterAsset(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void filterSearch(String query) {
|
||||
setState(() {
|
||||
selectedCategory = null;
|
||||
if (query.isEmpty) {
|
||||
filteredItems = List.from(_listContent);
|
||||
} else {
|
||||
@@ -117,6 +157,7 @@ class _ListEducationState extends State<ListEducation> {
|
||||
|
||||
void filterByCategory(String category) {
|
||||
setState(() {
|
||||
selectedCategory = category;
|
||||
filteredItems =
|
||||
_listContent.where((item) {
|
||||
return item["category"].toLowerCase() == category.toLowerCase();
|
||||
@@ -126,7 +167,6 @@ class _ListEducationState extends State<ListEducation> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String searchQuery = "";
|
||||
final List<Map<String, dynamic>> collections = [
|
||||
{
|
||||
"label": "Kesehatan",
|
||||
@@ -158,7 +198,8 @@ class _ListEducationState extends State<ListEducation> {
|
||||
collections
|
||||
.where(
|
||||
(item) => item["label"].toLowerCase().contains(
|
||||
searchQuery.toLowerCase(),
|
||||
// searchQuery.toLowerCase(),
|
||||
searchController.text.toLowerCase(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
@@ -176,7 +217,7 @@ class _ListEducationState extends State<ListEducation> {
|
||||
body: Column(
|
||||
children: [
|
||||
// Header Section
|
||||
headerContainer(context, filteredCollections),
|
||||
headerContainer(context, collections),
|
||||
// Collection Items dengan Filter
|
||||
SizedBox(height: 20),
|
||||
Expanded(child: contentContainer(context)),
|
||||
@@ -255,6 +296,7 @@ class _ListEducationState extends State<ListEducation> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children:
|
||||
filteredCollections.map((item) {
|
||||
final isSelected = selectedCategory == item["category"];
|
||||
return CollectionContainer(
|
||||
label: item["label"]!,
|
||||
imageSvg: item["image"]!,
|
||||
@@ -262,9 +304,16 @@ class _ListEducationState extends State<ListEducation> {
|
||||
iconh: 20,
|
||||
width: 70,
|
||||
height: 70,
|
||||
textColor: Colors.black,
|
||||
textColor:
|
||||
isSelected
|
||||
? const Color.fromARGB(255, 230, 48, 160)
|
||||
: Colors.black,
|
||||
lblSize: 10,
|
||||
colorContiner: ColorHelper.hexToColor(item["color"]),
|
||||
// colorContiner: ColorHelper.hexToColor(item["color"]),
|
||||
colorContiner:
|
||||
isSelected
|
||||
? const Color.fromARGB(255, 84, 3, 224)
|
||||
: ColorHelper.hexToColor(item["color"]),
|
||||
onTapAc:
|
||||
() => {
|
||||
searchController.clear(),
|
||||
@@ -347,36 +396,41 @@ class _ListEducationState extends State<ListEducation> {
|
||||
GridView _generateList() {
|
||||
return GridView.builder(
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 1, // 2 Kolom
|
||||
crossAxisCount: 1,
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisSpacing: 10,
|
||||
childAspectRatio: 2.5,
|
||||
),
|
||||
itemCount: _listContent.length,
|
||||
itemCount: filteredItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
child: CardList(
|
||||
title: _listContent[index]["title"] ?? "",
|
||||
body: _listContent[index]["body"] ?? "",
|
||||
gambar: _listContent[index]['image'],
|
||||
point: _listContent[index]['coint'],
|
||||
coint: _listContent[index]['point'],
|
||||
tipe: _listContent[index]['tipe'],
|
||||
title: filteredItems[index]["title"] ?? "",
|
||||
body: filteredItems[index]["body"] ?? "",
|
||||
gambar: filteredItems[index]['image'],
|
||||
point: filteredItems[index]['point'],
|
||||
coint: filteredItems[index]['coint'],
|
||||
tipe: filteredItems[index]['type'],
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => listDetailExtension.buildPage({
|
||||
'title': filteredItems[index]['category'],
|
||||
'imagePath': filteredItems[index]['image'],
|
||||
'filepath': filteredItems[index]['file'],
|
||||
'paragraphs':
|
||||
"""
|
||||
"""
|
||||
"<h1> ${_listContent[index]["title"]} </h1> <p> ${_listContent[index]["body"]}",
|
||||
}),
|
||||
// (context) => listDetailExtension.buildPage({
|
||||
// 'title': filteredItems[index]['category'],
|
||||
// 'imagePath': filteredItems[index]['image'],
|
||||
// 'filepath': filteredItems[index]['file'],
|
||||
// 'paragraphs':
|
||||
// """
|
||||
// """
|
||||
// "<h1> ${filteredItems[index]["title"]} </h1> <p> ${filteredItems[index]["body"]}",
|
||||
// }),
|
||||
(context) => ListDetailScreen(
|
||||
title: filteredItems[index]['category'],
|
||||
// 'imagePath': filteredItems[index]['image'],
|
||||
filepath: filteredItems[index]['file'],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -74,106 +74,11 @@ class _ListDetailScreenState extends State<ListPustakaDetailScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(20.0),
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Image.asset(
|
||||
// widget.imagePath,
|
||||
// width: 100,
|
||||
// height: 100,
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// const SizedBox(width: 16),
|
||||
// Expanded(
|
||||
// child: Center(
|
||||
// child: Text(
|
||||
// widget.title,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 22,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(height: 0),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
|
||||
child:
|
||||
// ListView.builder(
|
||||
// itemCount: widget.paragraphs.length,
|
||||
// itemBuilder: (context, index) {
|
||||
// return
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.only(bottom: 16.0),
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child:
|
||||
// // Text(
|
||||
// // widget.paragraphs[index] +
|
||||
// // style: TextStyle(color: Colors.black),
|
||||
// Html(
|
||||
// // style: {
|
||||
// // "body": Style(
|
||||
// // color: const Color.fromRGBO(0, 0, 0, 1),
|
||||
// // ),
|
||||
// // },
|
||||
// data:
|
||||
// widget.paragraphs +
|
||||
// """
|
||||
// <html>
|
||||
// <!-- Text between angle brackets is an HTML tag and is not displayed.
|
||||
// Most tags, such as the HTML and /HTML tags that surround the contents of
|
||||
// a page, come in pairs; some tags, like HR, for a horizontal rule, stand
|
||||
// alone. Comments, such as the text you're reading, are not displayed when
|
||||
// the Web page is shown. The information between the HEAD and /HEAD tags is
|
||||
// not displayed. The information between the BODY and /BODY tags is displayed.-->
|
||||
// <head>
|
||||
// <title>Enter a title, displayed at the top of the window.</title>
|
||||
// </head>
|
||||
// <!-- The information between the BODY and /BODY tags is displayed.-->
|
||||
// <body>
|
||||
// <h1>Enter the main heading, usually the same as the title.</h1>
|
||||
// <p>Be <b>bold</b> in stating your key points. Put them in a list: </p>
|
||||
// <ul>
|
||||
// <li>The first item in your list</li>
|
||||
// <li>The second item; <i>italicize</i> key words</li>
|
||||
// </ul>
|
||||
// <p>Improve your image by including an image. </p>
|
||||
// <p><img src="http://www.mygifs.com/CoverImage.gif" alt="A Great HTML Resource"></p>
|
||||
// <p>Add a link to your favorite <a href="https://www.dummies.com/">Web site</a>.
|
||||
// Break up your page with a horizontal rule or two. </p>
|
||||
// <hr>
|
||||
// <p>Finally, link to <a href="page2.html">another page</a> in your own Web site.</p>
|
||||
// <!-- And add a copyright notice.-->
|
||||
// <p>© Wiley Publishing, 2011</p>
|
||||
// </body>
|
||||
// </html>
|
||||
// """,
|
||||
// ),
|
||||
// ),
|
||||
// // ),
|
||||
// // Checkbox(
|
||||
// // value: _readStatus[index],
|
||||
// // onChanged: (bool? value) {
|
||||
// // _toggleReadStatus(index);
|
||||
// // },
|
||||
// // ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
htmlBody(),
|
||||
child: htmlBody(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -44,6 +44,32 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
},
|
||||
];
|
||||
|
||||
final List<Map<String, dynamic>> _genres = [
|
||||
{
|
||||
"label": "Game",
|
||||
"type": "game",
|
||||
"image": "assets/icons/healthy.svg",
|
||||
"color": "#cdd0ee",
|
||||
},
|
||||
{
|
||||
"label": "Novel",
|
||||
"image": "assets/icons/Nutrition.svg",
|
||||
"color": "#e8e29a",
|
||||
},
|
||||
{
|
||||
"label": "TTS",
|
||||
"type": "puzzle",
|
||||
"image": "assets/icons/Education.svg",
|
||||
"color": "#efd8c6",
|
||||
},
|
||||
{
|
||||
"label": "Pazzle",
|
||||
"type": "puzzle",
|
||||
"image": "assets/icons/Safety.svg",
|
||||
"color": "#cef1da",
|
||||
},
|
||||
];
|
||||
|
||||
void _onMenuTapped(int index) {
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
@@ -60,14 +86,23 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final buttonScanSize = screenWidth * 0.20;
|
||||
final double bottomPadding = (9000 / screenWidth).clamp(0, 0.2);
|
||||
List<Map<String, dynamic>> filteredCollections =
|
||||
_collections
|
||||
.where(
|
||||
(item) => item["label"]!.toLowerCase().contains(
|
||||
_searchQuery.toLowerCase(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
List<Map<String, dynamic>> filterCollections(
|
||||
List<Map<String, dynamic>> collections,
|
||||
String query,
|
||||
) {
|
||||
return collections
|
||||
.where(
|
||||
(item) =>
|
||||
item["label"]!.toLowerCase().contains(query.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> filteredCollections = filterCollections(
|
||||
_collections,
|
||||
_searchQuery,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
||||
@@ -121,16 +156,6 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// // Date Display
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
// child: Text(
|
||||
// DateTime.now().toString(),
|
||||
// style: const TextStyle(color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
|
||||
// Search Bar
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||
@@ -198,7 +223,10 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const ListEducation(),
|
||||
builder:
|
||||
(_) => ListEducation(
|
||||
selectedCategory: item["label"],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -231,61 +259,61 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: List.generate(
|
||||
10,
|
||||
(index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
elevation: 5,
|
||||
color: ColorHelper.hexToColor("#efd8c6"),
|
||||
// color: const Color.fromARGB(140, 255, 255, 255),
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(15),
|
||||
// ),
|
||||
child: GestureDetector(
|
||||
onTap:
|
||||
() => {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEducation(),
|
||||
),
|
||||
children:
|
||||
_genres.map((genre) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
elevation: 5,
|
||||
color: ColorHelper.hexToColor("#efd8c6"),
|
||||
// color: const Color.fromARGB(140, 255, 255, 255),
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(15),
|
||||
// ),
|
||||
child: GestureDetector(
|
||||
onTap:
|
||||
() => {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEducation(),
|
||||
),
|
||||
),
|
||||
},
|
||||
child: Container(
|
||||
width: 80,
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.book,
|
||||
size: 50,
|
||||
color: Colors.blueAccent,
|
||||
),
|
||||
Text(
|
||||
genre['label'],
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color.fromARGB(255, 0, 0, 0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
child: Container(
|
||||
width: 80,
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.book,
|
||||
size: 50,
|
||||
color: Colors.blueAccent,
|
||||
),
|
||||
Text(
|
||||
'Topic ${index + 1}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color.fromARGB(255, 0, 0, 0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Bottom Navigation
|
||||
// MainMenu(),
|
||||
],
|
||||
),
|
||||
// BG MEnu
|
||||
|
||||
Reference in New Issue
Block a user