FreekakeApp/lib/screen/pustaka/pustaka_detail_screen.dart
2025-07-04 16:04:09 +07:00

157 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
class ListPustakaDetailScreen extends StatefulWidget {
final String title;
final String imagePath;
final String paragraphs;
final String filepath;
const ListPustakaDetailScreen({
super.key,
required this.title,
required this.imagePath,
required this.paragraphs,
required this.filepath,
});
@override
_ListDetailScreenState createState() => _ListDetailScreenState();
}
class _ListDetailScreenState extends State<ListPustakaDetailScreen> {
late List<bool> _readStatus;
String _htmlContent = '';
@override
void initState() {
super.initState();
_readStatus = List.generate(widget.paragraphs.length, (index) => false);
loadHtml();
}
void _toggleReadStatus(int index) {
setState(() {
_readStatus[index] = !_readStatus[index];
});
}
Future<void> loadHtml() async {
String html = await DefaultAssetBundle.of(
context,
).loadString(widget.filepath);
html = html.replaceAllMapped(
RegExp(r'<div class="gizi-grid">(.*?)</div>', dotAll: true),
(match) => '<gizi-grid>${match.group(1)}</gizi-grid>',
);
setState(() {
_htmlContent = html;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(widget.title),
backgroundColor: Color.fromARGB(225, 79, 76, 182),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 10,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(40),
bottomRight: Radius.circular(40),
),
color: Color.fromARGB(225, 79, 76, 182),
),
),
),
const SizedBox(height: 0),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
child: htmlBody(),
),
),
],
),
// ),
);
}
Html htmlBody() {
return Html(
style: {"body": Style(color: const Color.fromRGBO(0, 0, 0, 1))},
// data: widget.paragraphs,
data: _htmlContent,
extensions: [
TagExtension(
tagsToExtend: {"img"},
builder: (ExtensionContext context) {
final attrs = context.attributes;
final src = attrs['src'] ?? '';
if (src.isNotEmpty) {
if (src.startsWith('assets/html/')) {
return Image.asset(
src,
width: 100,
errorBuilder:
(context, error, stackTrace) =>
const Text('Image not found'),
);
} else if (!src.startsWith('http')) {
return Image.asset(
'assets/images/$src',
width: 100,
errorBuilder:
(context, error, stackTrace) =>
const Text('Image not found'),
);
} else {
return Image.network(
src,
width: 100,
errorBuilder:
(context, error, stackTrace) =>
const Text('Image failed to load'),
);
}
}
return const SizedBox();
},
),
TagExtension(
tagsToExtend: {"gizi-grid"},
builder: (context) {
final spans = context.inlineSpanChildren ?? [];
final widgets =
spans.map((span) {
if (span is WidgetSpan) return span.child;
return const SizedBox();
}).toList();
return Wrap(
spacing: 12,
runSpacing: 12,
children:
widgets.map((child) {
return SizedBox(width: 160, child: child);
}).toList(),
);
},
),
],
);
}
}