[],
+ ),
+ backgroundColor: const Color.fromARGB(255, 255, 255, 255),
+ body: Column(
+ children: [
+ // Header Section
+ Container(
+ width: MediaQuery.of(context).size.width,
+ height: 150,
decoration: BoxDecoration(
- color: const Color.fromARGB(224, 145, 145, 155),
+ color: const Color.fromARGB(225, 79, 76, 182),
borderRadius: BorderRadius.only(
- topLeft: Radius.circular(25),
- topRight: Radius.circular(25),
+ bottomLeft: Radius.circular(25),
+ bottomRight: Radius.circular(25),
),
),
child: Column(
children: [
- SizedBox(height: 5),
Padding(
- padding: EdgeInsets.symmetric(
- horizontal: MediaQuery.of(context).size.width / 4,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 20,
+ vertical: 6,
),
- child: Divider(
- color: const Color.fromARGB(255, 155, 147, 147),
- height: 20,
+ 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('');
+ },
+ ),
+ ],
+ ),
),
),
-
- 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: 20.0,
- left: 20,
- right: 20,
- ),
- 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: GridView.builder(
- gridDelegate:
- const SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: 1, // 2 Kolom
- crossAxisSpacing: 10,
- mainAxisSpacing: 10,
- childAspectRatio: 2.5,
- ),
- itemCount: _listContent.length,
- itemBuilder: (context, index) {
- return GestureDetector(
- child: CardList(
- title:
- _listContent[index]["title"] ??
- "",
- body:
- _listContent[index]["body"] ??
- "",
- ),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder:
- (
- context,
- ) => ListDetailScreen(
- title:
- filteredItems[index],
- imagePath:
- filteredItems[index],
- /* paragraphs: [
- """
- Enter the main heading, usually the same as the title.
- Be bold in stating your key points. Put them in a list:
-
- - The first item in your list
- - The second item; italicize key words
-
- Improve your image by including an image.
- 
- Add a link to your favorite Web site.
-
- Finally, link to another page in your own Web site.
- © Wiley Publishing, 2011
- """,
- ], */
- paragraphs: """
-
-
-
-
-
- Furikake: Taburan Lezat untuk Nasi!
-
-
-
- Furikake: Taburan Lezat untuk Nasi!
-
- 振り掛け
-
- Tahukah kamu bahwa di Jepang ada bumbu tabur yang
- bisa membuat nasi menjadi lebih enak? Namanya Furikake! Kata "furikake" berasal dari bahasa Jepang,
- yaitu "furi" yang berarti menaburkan dan "kake" yang berarti menuangkan.
- Jadi, furikake adalah bumbu yang ditaburkan di atas nasi supaya lebih lezat!
- """,
- ),
- ),
- );
- },
- );
- },
- ),
- ),
- ),
- ),
- ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children:
+ filteredCollections.map((item) {
+ return CollectionContainer(
+ label: item["label"]!,
+ imageSvg: item["image"]!,
+ iconw: 20,
+ iconh: 20,
+ width: 70,
+ height: 70,
+ textColor: Colors.black,
+ lblSize: 10,
+ colorContiner: ColorHelper.hexToColor(
+ item["color"],
+ ),
+ onTapAc:
+ () => {
+ searchController.clear(),
+ filterByCategory(item["category"]),
+ },
+ );
+ }).toList(),
),
],
),
),
- ),
- // Bottom Navigation
- // MainMenu(),
- ],
- ),
- );
+ // Collection Items dengan Filter
+ SizedBox(height: 20),
+ Expanded(
+ child: Container(
+ decoration: BoxDecoration(
+ color: const Color.fromARGB(223, 200, 200, 206),
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(25),
+ topRight: Radius.circular(25),
+ ),
+ ),
+ child: 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: GridView.builder(
+ gridDelegate:
+ const SliverGridDelegateWithFixedCrossAxisCount(
+ crossAxisCount: 1, // 2 Kolom
+ crossAxisSpacing: 10,
+ mainAxisSpacing: 10,
+ childAspectRatio: 2.5,
+ ),
+ itemCount: _listContent.length,
+ itemBuilder: (context, index) {
+ return GestureDetector(
+ child: CardList(
+ title:
+ _listContent[index]["title"] ??
+ "",
+ body:
+ _listContent[index]["body"] ??
+ "",
+ ),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder:
+ (
+ context,
+ ) => listDetailExtension.buildPage({
+ 'title':
+ filteredItems[index]['category'],
+ 'imagePath':
+ filteredItems[index]['image'],
+ 'filepath':
+ filteredItems[index]['file'],
+ 'paragraphs':
+ """
+ """ +
+ " ${_listContent[index]["title"]}
${_listContent[index]["body"]}",
+ }),
+ ),
+ );
+ },
+ );
+ },
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ } else {
+ return const Center(
+ child: Padding(
+ padding: EdgeInsets.all(40),
+ child: Text("WebView tidak tersedia untuk platform ini."),
+ ),
+ );
+ }
}
}
diff --git a/lib/screen/pustaka/pustaka_detail_screen.dart b/lib/screen/pustaka/pustaka_detail_screen.dart
index f1c506a..992500f 100644
--- a/lib/screen/pustaka/pustaka_detail_screen.dart
+++ b/lib/screen/pustaka/pustaka_detail_screen.dart
@@ -1,16 +1,19 @@
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
class ListDetailScreen extends StatefulWidget {
final String title;
final String imagePath;
final String paragraphs;
+ final String filepath;
const ListDetailScreen({
Key? key,
required this.title,
required this.imagePath,
required this.paragraphs,
+ required this.filepath,
}) : super(key: key);
@override
@@ -19,11 +22,13 @@ class ListDetailScreen extends StatefulWidget {
class _ListDetailScreenState extends State {
late List _readStatus;
+ String _htmlContent = '';
@override
void initState() {
super.initState();
_readStatus = List.generate(widget.paragraphs.length, (index) => false);
+ loadHtml();
}
void _toggleReadStatus(int index) {
@@ -32,6 +37,15 @@ class _ListDetailScreenState extends State {
});
}
+ Future loadHtml() async {
+ String html = await DefaultAssetBundle.of(
+ context,
+ ).loadString(widget.filepath);
+ setState(() {
+ _htmlContent = html;
+ });
+ }
+
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -85,7 +99,7 @@ class _ListDetailScreenState extends State {
// ),
const SizedBox(height: 0),
Expanded(
- child: Padding(
+ child: SingleChildScrollView(
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
child:
// ListView.builder(
@@ -156,7 +170,46 @@ class _ListDetailScreenState extends State {
// ),
Html(
style: {"body": Style(color: const Color.fromRGBO(0, 0, 0, 1))},
- data: widget.paragraphs,
+ // 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();
+ },
+ ),
+ ],
),
),
),
diff --git a/lib/screen/saya/akun_saya.dart b/lib/screen/saya/akun_saya.dart
index 0b36bc6..40157da 100644
--- a/lib/screen/saya/akun_saya.dart
+++ b/lib/screen/saya/akun_saya.dart
@@ -18,6 +18,8 @@ class AkunSaya extends StatefulWidget {
class _AkunSayaState extends State {
dynamic _profileImage;
dynamic _headerImage;
+ ImageProvider? imageProvider;
+
final ImagePicker _picker = ImagePicker();
Future _pickImage(bool isProfile) async {
@@ -35,13 +37,19 @@ class _AkunSayaState extends State {
} else {
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
+ final imageFile = File(pickedFile.path);
setState(() {
if (isProfile) {
- _profileImage = File(pickedFile.path);
+ _profileImage = imageFile;
} else {
- _headerImage = File(pickedFile.path);
+ _headerImage = imageFile;
}
+
+ imageProvider =
+ kIsWeb ? MemoryImage(_profileImage) : FileImage(_profileImage);
});
+ } else {
+ imageProvider = AssetImage("assets/images/luffy.png");
}
}
}
@@ -97,7 +105,7 @@ class _AkunSayaState extends State {
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 40),
children: [
TextFormField(
- initialValue: "Cepot",
+ initialValue: "Luffy Kun",
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'Nama',
@@ -106,7 +114,7 @@ class _AkunSayaState extends State {
style: TextStyle(color: Colors.black),
),
TextFormField(
- initialValue: "cpt09",
+ initialValue: "luffy01",
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'Nama Pengguna',
@@ -169,7 +177,7 @@ class _AkunSayaState extends State {
: null,
child:
_profileImage == null
- ? Icon(Icons.person, size: 50, color: Colors.white)
+ ? Image.asset("assets/images/luffy.png")
: null,
),
CircleAvatar(
@@ -184,14 +192,14 @@ class _AkunSayaState extends State {
Positioned(
top: 130,
- left: MediaQuery.of(context).size.width / 2 - 50,
+ left: MediaQuery.of(context).size.width / 2 - 30,
child: GestureDetector(
onTap: () => _pickImage(true),
child: Stack(
alignment: Alignment.bottomRight,
children: [
Text(
- "Nama Akun",
+ "Luffy kun",
style: TextStyle(
color: Colors.deepPurple,
fontSize: 18,
diff --git a/lib/screen/saya/profile_screen.dart b/lib/screen/saya/profile_screen.dart
index 0fc53fd..76440f0 100644
--- a/lib/screen/saya/profile_screen.dart
+++ b/lib/screen/saya/profile_screen.dart
@@ -24,6 +24,7 @@ class _ProfileScreenState extends State {
// final ImagePicker _picker = ImagePicker();
dynamic _profileImage;
dynamic _headerImage;
+ ImageProvider? imageProvider;
final ImagePicker _picker = ImagePicker();
Future _pickImage(bool isProfile) async {
@@ -41,13 +42,19 @@ class _ProfileScreenState extends State {
} else {
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
+ final imageFile = File(pickedFile.path);
setState(() {
if (isProfile) {
- _profileImage = File(pickedFile.path);
+ _profileImage = imageFile;
} else {
- _headerImage = File(pickedFile.path);
+ _headerImage = imageFile;
}
+
+ imageProvider =
+ kIsWeb ? MemoryImage(_profileImage) : FileImage(_profileImage);
});
+ } else {
+ imageProvider = AssetImage("assets/images/luffy.png");
}
}
}
@@ -135,10 +142,8 @@ class _ProfileScreenState extends State {
: null,
child:
_profileImage == null
- ? Icon(
- Icons.person,
- size: 50,
- color: Colors.white,
+ ? Image.asset(
+ "assets/images/luffy.png",
)
: null,
),
@@ -162,9 +167,16 @@ class _ProfileScreenState extends State {
Row(
children: [
Text(
- "Name",
+ "Luffy",
style: TextStyle(
- color: Colors.blueAccent,
+ color: const Color.fromARGB(
+ 255,
+ 0,
+ 0,
+ 0,
+ ),
+ fontSize: 16,
+ fontWeight: FontWeight.bold,
),
),
],
@@ -172,9 +184,15 @@ class _ProfileScreenState extends State {
Row(
children: [
Text(
- "Edit Profile",
+ "Luffy Kun",
style: TextStyle(
- color: Colors.blueAccent,
+ color: const Color.fromARGB(
+ 255,
+ 0,
+ 0,
+ 0,
+ ),
+ fontWeight: FontWeight.normal,
),
),
],
diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc
index 7299b5c..d05487b 100644
--- a/linux/flutter/generated_plugin_registrant.cc
+++ b/linux/flutter/generated_plugin_registrant.cc
@@ -6,10 +6,14 @@
#include "generated_plugin_registrant.h"
+#include
#include
#include
void fl_register_plugins(FlPluginRegistry* registry) {
+ g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
+ fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
+ desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake
index 786ff5c..2b5fad0 100644
--- a/linux/flutter/generated_plugins.cmake
+++ b/linux/flutter/generated_plugins.cmake
@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
+ desktop_webview_window
file_selector_linux
url_launcher_linux
)
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index 09f86aa..f681062 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -5,12 +5,14 @@
import FlutterMacOS
import Foundation
+import desktop_webview_window
import file_selector_macos
import shared_preferences_foundation
import url_launcher_macos
import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+ DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
diff --git a/pubspec.lock b/pubspec.lock
index a912fe7..8b95e34 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -121,6 +121,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
+ desktop_webview_window:
+ dependency: "direct main"
+ description:
+ name: desktop_webview_window
+ sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.3"
dropdown_button2:
dependency: "direct main"
description:
@@ -241,7 +249,7 @@ packages:
source: hosted
version: "0.15.4"
http:
- dependency: transitive
+ dependency: "direct main"
description:
name: http
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
@@ -368,6 +376,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.2"
+ list_detail_extension:
+ dependency: "direct main"
+ description:
+ path: "."
+ ref: main
+ resolved-ref: e80f292f5a1a72de280fded5385c549507e12e0e
+ url: "https://github.com/fhauze/list_detail_screen.git"
+ source: git
+ version: "0.0.1"
matcher:
dependency: transitive
description:
@@ -782,7 +799,7 @@ packages:
source: hosted
version: "4.11.0"
webview_flutter_android:
- dependency: transitive
+ dependency: "direct main"
description:
name: webview_flutter_android
sha256: "5c3b6f992d123084903ec091b84f021c413a92a9af49038e4564a1b26c8452cf"
@@ -798,7 +815,7 @@ packages:
source: hosted
version: "2.11.0"
webview_flutter_wkwebview:
- dependency: transitive
+ dependency: "direct main"
description:
name: webview_flutter_wkwebview
sha256: c9f9be526fa0d3347374ceaa05c4b3acb85f4f112abd62f7d74b7d301fa515ff
diff --git a/pubspec.yaml b/pubspec.yaml
index 34cc4be..384d8a8 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -31,6 +31,7 @@ dependencies:
flutter:
sdk: flutter
camera: ^0.10.5+5
+ http: 1.3.0
permission_handler: ^11.3.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
@@ -46,6 +47,13 @@ dependencies:
image_picker_web: ^4.0.0
flutter_plugin_android_lifecycle: ^2.0.9
webview_flutter: ^4.11.0
+ webview_flutter_android: ^4.4.1
+ webview_flutter_wkwebview: ^3.9.3
+ list_detail_extension:
+ git:
+ url: https://github.com/fhauze/list_detail_screen.git
+ ref: main
+ desktop_webview_window: ^0.2.3
# arcore_flutter_plugin: ^0.2.0-alpha
# flutter_unity_widget: ^2022.2.1
# arcore_flutter_plugin:
@@ -102,6 +110,20 @@ flutter:
- assets/icons/Saya.svg
- assets/icons/Scan.svg
+ #HTML File
+ - assets/html/
+ - assets/html/index.html
+ - assets/html/furikake/index.html
+ - assets/html/furikake/
+ # HTML Images
+ - assets/html/isipiringku.png
+ - assets/html/karbohidrat.png
+ - assets/html/lemak.png
+ - assets/html/protein.png
+ - assets/html/seratair.png
+ - assets/html/vitaminmineral.png
+
+
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc
index 4e586f9..5d07d38 100644
--- a/windows/flutter/generated_plugin_registrant.cc
+++ b/windows/flutter/generated_plugin_registrant.cc
@@ -6,11 +6,14 @@
#include "generated_plugin_registrant.h"
+#include
#include
#include
#include
void RegisterPlugins(flutter::PluginRegistry* registry) {
+ DesktopWebviewWindowPluginRegisterWithRegistrar(
+ registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake
index 1119879..379ad60 100644
--- a/windows/flutter/generated_plugins.cmake
+++ b/windows/flutter/generated_plugins.cmake
@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
+ desktop_webview_window
file_selector_windows
permission_handler_windows
url_launcher_windows