FreekakeApp/lib/screen/pustaka/list_education.dart
2025-07-07 17:31:26 +07:00

486 lines
15 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
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/models/users.dart';
import 'package:freekake/screen/pustaka/list_detail_screen.dart';
import 'package:freekake/util/api_client.dart';
import 'package:list_detail_extension/list_detail_extension.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:dio/dio.dart';
class ListEducation extends StatefulWidget {
final String? selectedCategory;
const ListEducation({super.key, this.selectedCategory});
@override
State<ListEducation> createState() => _ListEducationState();
}
class _ListEducationState extends State<ListEducation> {
TextEditingController searchController = TextEditingController();
late final WebViewController _controller;
late String urlOrAssetPath;
bool _shouldShowWebView = false;
String? selectedCategory;
final listDetailExtension = ListDetailExtension();
// Data fetch
final ApiClient _apiClient = ApiClient();
List<Users> _posts = [];
bool _isLoading = true;
String _error = '';
Future<void> _initExtension() async {
await listDetailExtension.load();
}
List<String> allItems = [
"Matematika",
"Fisika",
"Kimia",
"Biologi",
"Sejarah",
"Geografi",
];
final List<Map<String, dynamic>> _listContent = [
{
"title": "Taburan Lezat untuk Nasi!",
"image": "assets/html/furikake/furikake.jpg",
"color": "#cdd0ee",
"category": "Kesehatan",
"type": "Materi",
"point": "10",
"coint": "100",
"body":
"""Tahukah kamu bahwa di Jepang ada bumbu tabur yang bisa membuat nasi
menjadi lebih enak?
""",
"file": "assets/html/furikake/index.html",
},
{
"title": "Makan Sehat dengan Gizi Seimbang",
"image": "assets/html/lemak.png",
"color": "#cef1da",
"category": "Keselamatan",
"type": "Materi",
"point": "100",
"coint": "20",
"body":
"""upaya makan kita sehat, ada aturan "Isi Piringku" yang bisa kita ikuti:
🍽️ Separuh piring: Sayur dan buah 🍽️ Seperempat piring: Karbohidrat (seperti nasi atau roti)
🍽️ Seperempat piring: Protein (seperti ayam atau tempe) 🍽️ Sedikit lemak sehat
""",
"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();
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/html/index.html";
_loadContent(urlOrAssetPath);
_initExtension();
}
}
void _loadContent(String path) async {
if (_shouldShowWebView) {
if (path.startsWith('http')) {
// Load dari Internet
_controller.loadRequest(Uri.parse(path));
} else {
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 {
filteredItems =
_listContent.where((item) {
return item["title"].toLowerCase().contains(query.toLowerCase());
}).toList();
}
});
}
void filterByCategory(String category) {
setState(() {
selectedCategory = category;
filteredItems =
_listContent.where((item) {
return item["category"].toLowerCase() == category.toLowerCase();
}).toList();
});
}
Future<void> _fetchPosts() async {
try {
setState(() {
_isLoading = true;
_error = '';
});
// Melakukan permintaan GET ke endpoint
final Response response = await _apiClient.dio.get('auth/users');
if (response.statusCode == 200) {
// Konversi data JSON ke List
List<dynamic> postJson = response.data;
_posts = postJson.map((json) => Users.fromJson(json)).toList();
} else {
_error = 'Gagal memuat data: ${response.statusCode}';
}
} on DioException catch (e) {
if (e.response != null) {
_error =
'Server Error: ${e.response?.statusCode} - ${e.response?.statusMessage}';
} else {
_error = 'Network Error: ${e.message}';
}
print('DioError: $e');
} catch (e) {
_error = 'Terjadi kesalahan tidak terduga: $e';
print('General Error: $e');
} finally {
setState(() {
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
final List<Map<String, dynamic>> collections = [
{
"label": "Kesehatan",
"image": "assets/icons/healthy.svg",
"color": "#cdd0ee",
"category": "kesehatan",
},
{
"label": "Gizi",
"image": "assets/icons/Nutrition.svg",
"color": "#e8e29a",
"category": "gizi",
},
{
"label": "Pendidikan",
"image": "assets/icons/Education.svg",
"color": "#efd8c6",
"category": "pendidikan",
},
{
"label": "Keselamatan",
"image": "assets/icons/Safety.svg",
"color": "#cef1da",
"category": "keselamatan",
},
];
final List<Map<String, dynamic>> filteredCollections =
collections
.where(
(item) => item["label"].toLowerCase().contains(
// searchQuery.toLowerCase(),
searchController.text.toLowerCase(),
),
)
.toList();
if (_shouldShowWebView) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromARGB(225, 79, 76, 182),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(false),
),
actions: <Widget>[],
),
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
body: Column(
children: [
// Header Section
headerContainer(context, collections),
// Collection Items dengan Filter
SizedBox(height: 20),
Expanded(child: contentContainer(context)),
],
),
);
} else {
return const Center(
child: Padding(
padding: EdgeInsets.all(40),
child: Text("WebView tidak tersedia untuk platform ini."),
),
);
}
}
Container headerContainer(
BuildContext context,
List<Map<String, dynamic>> filteredCollections,
) {
return Container(
width: MediaQuery.of(context).size.width,
height: 150,
decoration: BoxDecoration(
color: const Color.fromARGB(225, 79, 76, 182),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(25),
bottomRight: Radius.circular(25),
),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 6),
child: Container(
height: 47,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey.shade200,
),
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: [
const Icon(
Icons.search,
color: Color.fromARGB(137, 180, 172, 172),
size: 18,
),
const SizedBox(width: 8),
Expanded(
child: TextField(
controller: searchController,
onChanged: filterSearch, // Memanggil filter saat mengetik
style: const TextStyle(color: Colors.black, fontSize: 14),
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Cari pelajaran...',
hintStyle: TextStyle(color: Colors.black54),
),
),
),
if (searchController.text.isNotEmpty)
IconButton(
icon: const Icon(Icons.close, color: Colors.black54),
onPressed: () {
searchController.clear();
filterSearch('');
},
),
],
),
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:
filteredCollections.map((item) {
final isSelected = selectedCategory == item["category"];
return CollectionContainer(
label: item["label"]!,
imageSvg: item["image"]!,
iconw: 20,
iconh: 20,
width: 70,
height: 70,
textColor:
isSelected
? const Color.fromARGB(255, 230, 48, 160)
: Colors.black,
lblSize: 10,
// colorContiner: ColorHelper.hexToColor(item["color"]),
colorContiner:
isSelected
? const Color.fromARGB(255, 84, 3, 224)
: ColorHelper.hexToColor(item["color"]),
onTapAc:
() => {
searchController.clear(),
filterByCategory(item["category"]),
},
);
}).toList(),
),
],
),
);
}
Container contentContainer(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: const Color.fromARGB(223, 200, 200, 206),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
),
),
child: _listCard(context),
);
}
Column _listCard(BuildContext context) {
return Column(
children: [
SizedBox(height: 5),
Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 4,
),
child: Divider(
color: const Color.fromARGB(255, 255, 255, 255),
thickness: 2,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
// vertical: 10,
),
child:
filteredItems.isEmpty
? const Center(
child: Text(
"Tidak ada hasil",
style: TextStyle(fontSize: 16, color: Colors.black54),
),
)
: Padding(
padding: EdgeInsets.only(top: 10.0, left: 10, right: 10),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
color: const Color.fromARGB(255, 222, 181, 133),
),
child: Padding(
padding: EdgeInsets.only(
top: 12,
right: 20,
left: 20,
),
child: _generateList(),
),
),
),
),
),
],
);
}
GridView _generateList() {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 2.5,
),
itemCount: filteredItems.length,
itemBuilder: (context, index) {
return GestureDetector(
child: CardList(
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> ${filteredItems[index]["title"]} </h1> <p> ${filteredItems[index]["body"]}",
// }),
(context) => ListDetailScreen(
title: filteredItems[index]['category'],
// 'imagePath': filteredItems[index]['image'],
filepath: filteredItems[index]['file'],
),
),
);
},
);
},
);
}
}