update profile and html content
@@ -41,6 +41,10 @@ android {
|
|||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dependencies {
|
||||||
|
implementation("androidx.core:core-ktx:1.9.0")
|
||||||
|
implementation("com.google.android.material:material:1.6.1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
|
|||||||
@@ -45,4 +45,6 @@
|
|||||||
</queries>
|
</queries>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 351 KiB |
|
After Width: | Height: | Size: 175 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,279 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Furikake: Taburan Lezat untuk Nasi!</title>
|
||||||
|
<style>
|
||||||
|
/* Base Styles */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #666;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
margin: 30px 0 15px 0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 30px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bahan-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bahan-item {
|
||||||
|
text-align: center;
|
||||||
|
flex: 1 0 calc(25% - 15px); /* 4 items per row by default */
|
||||||
|
min-width: calc(25% - 15px);
|
||||||
|
max-width: calc(25% - 15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bahan-item img {
|
||||||
|
width: 100%;
|
||||||
|
height: 120px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bahan-item p {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Adjustments */
|
||||||
|
|
||||||
|
/* Tablet Size (768px and below) - 2 items per row */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.bahan-item {
|
||||||
|
flex: 1 0 calc(50% - 15px);
|
||||||
|
min-width: calc(50% - 15px);
|
||||||
|
max-width: calc(50% - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Size (480px and below) - 1 item per row */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.japanese-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, li {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bahan-item {
|
||||||
|
flex: 1 0 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Mobile (360px and below) - Adjust font sizes further */
|
||||||
|
@media (max-width: 360px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<h1>Furikake: Taburan Lezat untuk Nasi!</h1>
|
||||||
|
<p class="subtitle">Tahukah kamu bahwa di Jepang ada bumbu tabur yang bisa membuat nasi menjadi lebih enak?</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="japanese-title">ふりかけ</div>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
<p>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!</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Asal Usul Furikake</h2>
|
||||||
|
<p>Furikake pertama kali dibuat di Jepang pada tahun 1913 oleh seorang apoteker bernama Suekichi Yoshimaru. Awalnya, ia ingin membantu orang-orang yang kekurangan kalsium. Maka, ia membuat bubuk dari tulang ikan kering, biji wijen, dan rumput laut. Campuran ini kemudian diberi nama "Gohan no Tomo" yang artinya "Teman Nasi" karena memang cocok untuk dimakan bersama nasi.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Perkembangan Furikake</h2>
|
||||||
|
<p>Seiring berjalannya waktu, furikake menjadi semakin populer dan dibuat dengan berbagai rasa. Dulu, furikake hanya bisa dibeli oleh orang kaya, tetapi setelah Perang Dunia II, furikake mulai dijual dengan harga terjangkau sehingga semua orang bisa menikmatinya. Akhirnya, pada tahun 1959, furikake semakin terkenal dan banyak orang mulai membuat berbagai variasi rasa yang lebih menarik.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Apa Saja Isi Furikake?</h2>
|
||||||
|
<p>Furikake biasanya terbuat dari campuran beberapa bahan seperti:</p>
|
||||||
|
|
||||||
|
<div class="bahan-container">
|
||||||
|
<div class="bahan-item">
|
||||||
|
<img src="assets/html/furikake/nori.jpeg" alt="Nori">
|
||||||
|
<p>Nori (Rumput Laut)</p>
|
||||||
|
</div>
|
||||||
|
<div class="bahan-item">
|
||||||
|
<img src="assets/html/furikake/wijen.jpeg" alt="Biji Wijen">
|
||||||
|
<p>Biji Wijen</p>
|
||||||
|
</div>
|
||||||
|
<div class="bahan-item">
|
||||||
|
<img src="assets/html/furikake/ikankering.jpg" alt="Katsuobushi">
|
||||||
|
<p>Katsuobushi (Ikan Kering)</p>
|
||||||
|
</div>
|
||||||
|
<div class="bahan-item">
|
||||||
|
<img src="assets/html/furikake/gulagaram.jpg" alt="Garam dan Gula">
|
||||||
|
<p>Garam & Gula</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Rumput laut kering (nori) yang memberikan rasa laut yang khas.</li>
|
||||||
|
<li>Biji wijen yang menambah rasa gurih dan tekstur renyah.</li>
|
||||||
|
<li>Katsuobushi (ikan kering) yang menambah rasa gurih dan protein.</li>
|
||||||
|
<li>Gula dan garam untuk memberikan keseimbangan rasa.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Beragam Rasa Furikake</h2>
|
||||||
|
<p>Sekarang, furikake punya banyak rasa yang bisa dipilih sesuai selera! Beberapa contoh rasa furikake adalah:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Wasabi Furikake, untuk yang suka rasa pedas khas wasabi.</li>
|
||||||
|
<li>Salmon Furikake, dengan aroma salmon yang lezat.</li>
|
||||||
|
<li>Furikake Vegan, yang dibuat tanpa bahan dari hewan, cocok untuk vegetarian.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="furikake.jpg" alt="Contoh produk furikake" class="full-width-image">
|
||||||
|
<figcaption>Berbagai varian produk furikake yang tersedia di pasaran</figcaption>
|
||||||
|
</figure>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Cara Menikmati Furikake</h2>
|
||||||
|
<p>Furikake sangat mudah digunakan! Cukup taburkan di atas nasi hangat, dan nasi pun menjadi lebih lezat. Bisa juga ditambahkan ke dalam mie, sup, atau onigiri (nasi kepal) untuk menambah rasa.</p>
|
||||||
|
<p>Nah, sekarang kamu tahu tentang furikake! Kalau suatu saat berkesempatan mencobanya, jangan lupa untuk menikmati kelezatannya. Siapa tahu, kamu jadi semakin suka makan nasi!</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Artikel tentang Furikake - Taburan Lezat untuk Nasi</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,243 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Makan Sehat dengan Gizi Seimbang!</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #666;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
margin: 30px 0 15px 0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 30px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gizi-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gizi-item {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 100px;
|
||||||
|
flex: 1 1 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gizi-item img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, li {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gizi-grid {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gizi-item {
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<h1>Makan Sehat dengan Gizi Seimbang!</h1>
|
||||||
|
<p class="subtitle">Tahukah kamu bahwa makan dengan gizi seimbang itu penting untuk tubuh kita?</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
<p>Gizi seimbang berarti kita harus makan berbagai jenis makanan dengan jumlah yang pas supaya tubuh tetap sehat dan kuat!</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Apa Itu Gizi Seimbang?</h2>
|
||||||
|
<p>Gizi seimbang adalah cara makan yang mengandung semua zat gizi yang dibutuhkan tubuh. Zat gizi itu terdiri dari:</p>
|
||||||
|
|
||||||
|
<div class="gizi-grid">
|
||||||
|
<div class="gizi-item">
|
||||||
|
<img src="assets/html/karbohidrat.png" alt="Karbohidrat" />
|
||||||
|
<p><strong>Karbohidrat</strong><br>Sumber energi seperti nasi, roti, dan kentang.</p>
|
||||||
|
</div>
|
||||||
|
<div class="gizi-item">
|
||||||
|
<img src="assets/html/protein.png" alt="Protein" />
|
||||||
|
<p><strong>Protein</strong><br>Untuk membangun otot, misalnya ikan, telur, dan tahu.</p>
|
||||||
|
</div>
|
||||||
|
<div class="gizi-item">
|
||||||
|
<img src="assets/html/lemak.png" alt="Lemak" />
|
||||||
|
<p><strong>Lemak</strong><br>Memberikan tenaga, seperti dari kacang-kacangan dan minyak sehat.</p>
|
||||||
|
</div>
|
||||||
|
<div class="gizi-item">
|
||||||
|
<img src="assets/html/vitaminmineral.png" alt="Vitamin dan Mineral" />
|
||||||
|
<p><strong>Vitamin dan mineral</strong><br>Dari sayur dan buah yang membantu tubuh bekerja dengan baik.</p>
|
||||||
|
</div>
|
||||||
|
<div class="gizi-item">
|
||||||
|
<img src="assets/html/seratair.png" alt="Serat dan Air" />
|
||||||
|
<p><strong>Serat dan air</strong><br>Membantu pencernaan dan menjaga tubuh tetap segar!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Porsi Makan yang Seimbang</h2>
|
||||||
|
<p>Supaya makan kita sehat, ada aturan "Isi Piringku" yang bisa kita ikuti:</p>
|
||||||
|
<ul>
|
||||||
|
<li>🍽️ Separuh piring: Sayur dan buah</li>
|
||||||
|
<li>🍽️ Seperempat piring: Karbohidrat (seperti nasi atau roti)</li>
|
||||||
|
<li>🍽️ Seperempat piring: Protein (seperti ayam atau tempe)</li>
|
||||||
|
<li>🍽️ Sedikit lemak sehat</li>
|
||||||
|
</ul>
|
||||||
|
<img src="assets/html/isipiringku.png" alt="Piring Gizi Seimbang" class="full-width-image">
|
||||||
|
<figcaption>Isi Piringku</figcaption>
|
||||||
|
<p>Selain itu, kita tidak boleh makan terlalu banyak atau terlalu sedikit, karena bisa membuat tubuh tidak sehat. Makan berlebihan bisa menyebabkan obesitas, sedangkan makan terlalu sedikit bisa membuat tubuh lemas dan kurang gizi.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Menjaga Kebersihan Makanan</h2>
|
||||||
|
<p>Selain memilih makanan sehat, kita juga harus menjaga kebersihan makanan agar tidak sakit perut! Caranya:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Cuci tangan sebelum makan dan mengolah makanan.</li>
|
||||||
|
<li>Simpan makanan dengan baik agar tidak terkena kuman.</li>
|
||||||
|
<li>Masak makanan dengan suhu yang cukup supaya aman dimakan.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Aktivitas Fisik Itu Penting!</h2>
|
||||||
|
<p>Selain makan sehat, kita juga harus rajin bergerak! Olahraga atau bermain di luar rumah bisa membantu tubuh tetap bugar, menjaga berat badan, dan membuat kita lebih bersemangat.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Yuk, Mulai Gizi Seimbang!</h2>
|
||||||
|
<p>Makan dengan gizi seimbang akan membuat tubuh kita lebih sehat, kuat, dan penuh energi. Yuk, biasakan makan sehat mulai sekarang supaya kita tumbuh dengan baik dan terhindar dari penyakit!</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Artikel tentang Makan Sehat dengan Gizi Seimbang</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
@@ -9,10 +9,12 @@ void main() async {
|
|||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||||
|
|
||||||
await SystemChrome.setPreferredOrientations([
|
await SystemChrome.setPreferredOrientations([
|
||||||
DeviceOrientation.portraitUp,
|
DeviceOrientation.portraitUp,
|
||||||
DeviceOrientation.portraitDown, // bisa dihapus jika hanya ingin satu arah
|
DeviceOrientation.portraitDown, // bisa dihapus jika hanya ingin satu arah
|
||||||
]);
|
]);
|
||||||
|
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
|
||||||
|
class CharacterView extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final String imagePath;
|
||||||
|
final String content;
|
||||||
|
|
||||||
|
const CharacterView({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.imagePath,
|
||||||
|
required this.content,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CharacterViewState createState() => _CharacterViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CharacterViewState extends State<CharacterView> {
|
||||||
|
String _content = '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_content = widget.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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: Text(_content),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
class ListDetailScreen extends StatefulWidget {
|
class ListDetailScreen extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
|
final String? filepath;
|
||||||
|
|
||||||
const ListDetailScreen({super.key, required this.title});
|
const ListDetailScreen({super.key, required this.title, this.filepath});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ListDetailScreen> createState() => _ListDetailScreenState();
|
State<ListDetailScreen> createState() => _ListDetailScreenState();
|
||||||
@@ -11,6 +14,8 @@ class ListDetailScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _ListDetailScreenState extends State<ListDetailScreen> {
|
class _ListDetailScreenState extends State<ListDetailScreen> {
|
||||||
List<bool> checklist = [];
|
List<bool> checklist = [];
|
||||||
|
late WebViewController _controller;
|
||||||
|
late String? fPath = widget.filepath;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -25,58 +30,72 @@ class _ListDetailScreenState extends State<ListDetailScreen> {
|
|||||||
"Paragraf keempat yang melengkapi pembahasan.",
|
"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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: AppBar(title: Text(widget.title)),
|
appBar: AppBar(title: Text(widget.title)),
|
||||||
body: Padding(
|
body:
|
||||||
padding: const EdgeInsets.all(16.0),
|
(fPath != null && fPath!.isNotEmpty)
|
||||||
child: Column(
|
? WebViewWidget(controller: _controller)
|
||||||
children: [
|
: Padding(
|
||||||
// Gambar di kiri atas dengan teks di kanan
|
padding: const EdgeInsets.all(16.0),
|
||||||
Row(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
// Gambar di kiri atas dengan teks di kanan
|
||||||
Image.asset(
|
Row(
|
||||||
'assets/images/default.png', // Ganti dengan gambar yang sesuai
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
width: 100,
|
children: [
|
||||||
height: 100,
|
Image.asset(
|
||||||
fit: BoxFit.cover,
|
'assets/images/default.png', // Ganti dengan gambar yang sesuai
|
||||||
),
|
width: 100,
|
||||||
const SizedBox(width: 16),
|
height: 100,
|
||||||
Expanded(
|
fit: BoxFit.cover,
|
||||||
child: Text(
|
),
|
||||||
"Ini adalah detail dari ${widget.title}.",
|
const SizedBox(width: 16),
|
||||||
style: const TextStyle(fontSize: 18),
|
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!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
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!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:furibase/components/buildcard_info.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:furibase/components/card_list.dart';
|
import 'package:furibase/components/card_list.dart';
|
||||||
import 'package:furibase/components/collection_container%20copy.dart';
|
import 'package:furibase/components/collection_container%20copy.dart';
|
||||||
import 'package:furibase/components/main_menu.dart';
|
// import 'package:furibase/components/main_menu.dart';
|
||||||
import 'package:furibase/components/topbar_container.dart';
|
// import 'package:furibase/components/topbar_container.dart';
|
||||||
import 'package:furibase/helpers/color_helper.dart';
|
import 'package:furibase/helpers/color_helper.dart';
|
||||||
import 'package:furibase/screen/pustaka/pustaka_detail_screen.dart';
|
import 'package:list_detail_extension/list_detail_extension.dart';
|
||||||
|
|
||||||
|
// import 'package:furibase/screen/pustaka/pustaka_detail_screen.dart';
|
||||||
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
|
|
||||||
class ListEducation extends StatefulWidget {
|
class ListEducation extends StatefulWidget {
|
||||||
const ListEducation({super.key});
|
const ListEducation({super.key});
|
||||||
@@ -16,6 +23,17 @@ class ListEducation extends StatefulWidget {
|
|||||||
|
|
||||||
class _ListEducationState extends State<ListEducation> {
|
class _ListEducationState extends State<ListEducation> {
|
||||||
TextEditingController searchController = TextEditingController();
|
TextEditingController searchController = TextEditingController();
|
||||||
|
late final WebViewController _controller;
|
||||||
|
late String urlOrAssetPath;
|
||||||
|
bool _shouldShowWebView = false;
|
||||||
|
|
||||||
|
// load extension
|
||||||
|
final listDetailExtension = ListDetailExtension();
|
||||||
|
|
||||||
|
Future<void> _initExtension() async {
|
||||||
|
await listDetailExtension.load();
|
||||||
|
}
|
||||||
|
|
||||||
List<String> allItems = [
|
List<String> allItems = [
|
||||||
"Matematika",
|
"Matematika",
|
||||||
"Fisika",
|
"Fisika",
|
||||||
@@ -24,20 +42,83 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
"Sejarah",
|
"Sejarah",
|
||||||
"Geografi",
|
"Geografi",
|
||||||
];
|
];
|
||||||
List<String> filteredItems = [];
|
|
||||||
|
final List<Map<String, dynamic>> _listContent = [
|
||||||
|
{
|
||||||
|
"title": "Taburan Lezat untuk Nasi!",
|
||||||
|
"image": "assets/icons/healthy.svg",
|
||||||
|
"color": "#cdd0ee",
|
||||||
|
"category": "Kesehatan",
|
||||||
|
"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/icons/Safety.svg",
|
||||||
|
"color": "#cef1da",
|
||||||
|
"category": "Keselamatan",
|
||||||
|
"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",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
List<Map<String, dynamic>> filteredItems = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
filteredItems = List.from(allItems);
|
filteredItems = List.from(_listContent);
|
||||||
|
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
|
_shouldShowWebView = true;
|
||||||
|
_controller =
|
||||||
|
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||||
|
urlOrAssetPath = "assets/makanan_bergizi/index.html";
|
||||||
|
_loadContent(urlOrAssetPath);
|
||||||
|
_initExtension();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _loadContent(String path) async {
|
||||||
|
if (_shouldShowWebView && _controller != null) {
|
||||||
|
if (path.startsWith('http')) {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterSearch(String query) {
|
void filterSearch(String query) {
|
||||||
|
setState(() {
|
||||||
|
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(() {
|
setState(() {
|
||||||
filteredItems =
|
filteredItems =
|
||||||
allItems
|
_listContent.where((item) {
|
||||||
.where((item) => item.toLowerCase().contains(query.toLowerCase()))
|
return item["category"].toLowerCase() == category.toLowerCase();
|
||||||
.toList();
|
}).toList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,32 +152,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
final List<Map<String, dynamic>> _listContent = [
|
final List<Map<String, dynamic>> filteredCollections =
|
||||||
{
|
|
||||||
"title": "Taburan Lezat untuk Nasi!",
|
|
||||||
"image": "assets/icons/healthy.svg",
|
|
||||||
"color": "#cdd0ee",
|
|
||||||
"category": "kesehatan",
|
|
||||||
"body":
|
|
||||||
"""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!
|
|
||||||
""",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Makan Sehat dengan Gizi Seimbang",
|
|
||||||
"image": "assets/icons/Safety.svg",
|
|
||||||
"color": "#cef1da",
|
|
||||||
"category": "keselamatan",
|
|
||||||
"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
|
|
||||||
""",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
List<Map<String, dynamic>> filteredCollections =
|
|
||||||
_collections
|
_collections
|
||||||
.where(
|
.where(
|
||||||
(item) => item["label"].toLowerCase().contains(
|
(item) => item["label"].toLowerCase().contains(
|
||||||
@@ -104,415 +160,239 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
return Scaffold(
|
if (_shouldShowWebView && _controller != null) {
|
||||||
appBar: AppBar(
|
return Scaffold(
|
||||||
backgroundColor: Color.fromARGB(225, 79, 76, 182),
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
backgroundColor: Color.fromARGB(225, 79, 76, 182),
|
||||||
icon: Icon(Icons.arrow_back),
|
leading: IconButton(
|
||||||
onPressed: () => Navigator.of(context).pop(false),
|
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
|
|
||||||
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) {
|
|
||||||
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(),
|
|
||||||
filterSearch(item["category"]),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
actions: <Widget>[],
|
||||||
// Search Bar
|
),
|
||||||
// Padding(
|
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
||||||
// padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
body: Column(
|
||||||
// child: Container(
|
children: [
|
||||||
// height: 47,
|
// Header Section
|
||||||
// decoration: BoxDecoration(
|
Container(
|
||||||
// borderRadius: BorderRadius.circular(20),
|
width: MediaQuery.of(context).size.width,
|
||||||
// color: Colors.grey.shade200,
|
height: 150,
|
||||||
// ),
|
|
||||||
// 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('');
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// Collection Items dengan Filter
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color.fromARGB(224, 145, 145, 155),
|
color: const Color.fromARGB(225, 79, 76, 182),
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(25),
|
bottomLeft: Radius.circular(25),
|
||||||
topRight: Radius.circular(25),
|
bottomRight: Radius.circular(25),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 5),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width / 4,
|
horizontal: 20,
|
||||||
|
vertical: 6,
|
||||||
),
|
),
|
||||||
child: Divider(
|
child: Container(
|
||||||
color: const Color.fromARGB(255, 155, 147, 147),
|
height: 47,
|
||||||
height: 20,
|
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(
|
||||||
Expanded(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Padding(
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
padding: const EdgeInsets.symmetric(
|
children:
|
||||||
horizontal: 10,
|
filteredCollections.map((item) {
|
||||||
// vertical: 10,
|
return CollectionContainer(
|
||||||
),
|
label: item["label"]!,
|
||||||
child:
|
imageSvg: item["image"]!,
|
||||||
filteredItems.isEmpty
|
iconw: 20,
|
||||||
? const Center(
|
iconh: 20,
|
||||||
child: Text(
|
width: 70,
|
||||||
"Tidak ada hasil",
|
height: 70,
|
||||||
style: TextStyle(
|
textColor: Colors.black,
|
||||||
fontSize: 16,
|
lblSize: 10,
|
||||||
color: Colors.black54,
|
colorContiner: ColorHelper.hexToColor(
|
||||||
),
|
item["color"],
|
||||||
),
|
),
|
||||||
)
|
onTapAc:
|
||||||
: Padding(
|
() => {
|
||||||
padding: EdgeInsets.only(
|
searchController.clear(),
|
||||||
top: 20.0,
|
filterByCategory(item["category"]),
|
||||||
left: 20,
|
},
|
||||||
right: 20,
|
);
|
||||||
),
|
}).toList(),
|
||||||
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: [
|
|
||||||
"""
|
|
||||||
<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="https://via.placeholder.com/150" alt="A Great HTML Resource"></p>
|
|
||||||
<p>Add a link to your favorite <a href="https://www.dummies.com/">Web site</a>.</p>
|
|
||||||
<hr>
|
|
||||||
<p>Finally, link to <a href="page2.html">another page</a> in your own Web site.</p>
|
|
||||||
<p>© Wiley Publishing, 2011</p>
|
|
||||||
""",
|
|
||||||
], */
|
|
||||||
paragraphs: """
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="id">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Furikake: Taburan Lezat untuk Nasi!</title>
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #333;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 15px;
|
|
||||||
max-width: 100%;
|
|
||||||
max-height:100%;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #d32f2f;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
margin: 10px 0 15px 0;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
color: #f57c00;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin: 20px 0 10px 0;
|
|
||||||
font-weight: 500;
|
|
||||||
padding-bottom: 3px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kanji {
|
|
||||||
font-size: 2.2rem;
|
|
||||||
text-align: center;
|
|
||||||
color: #333;
|
|
||||||
margin: 10px 0;
|
|
||||||
font-family: 'Noto Sans JP', sans-serif;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-image {
|
|
||||||
width: 100%;
|
|
||||||
margin: 15px 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-image img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-image p {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: #666;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ingredients {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 10px;
|
|
||||||
margin: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ingredient {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ingredient img {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ingredient p {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
margin-top: 3px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
padding: 12px;
|
|
||||||
margin: 15px 0;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 20px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Furikake: Taburan Lezat untuk Nasi!</h1>
|
|
||||||
|
|
||||||
<div class="kanji">振り掛け</div>
|
|
||||||
|
|
||||||
<p>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!</p>
|
|
||||||
""",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
// Collection Items dengan Filter
|
||||||
// Bottom Navigation
|
SizedBox(height: 20),
|
||||||
// MainMenu(),
|
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':
|
||||||
|
"""
|
||||||
|
""" +
|
||||||
|
"<h1> ${_listContent[index]["title"]} </h1> <p> ${_listContent[index]["body"]}",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(40),
|
||||||
|
child: Text("WebView tidak tersedia untuk platform ini."),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
|
||||||
class ListDetailScreen extends StatefulWidget {
|
class ListDetailScreen extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final String imagePath;
|
final String imagePath;
|
||||||
final String paragraphs;
|
final String paragraphs;
|
||||||
|
final String filepath;
|
||||||
|
|
||||||
const ListDetailScreen({
|
const ListDetailScreen({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.imagePath,
|
required this.imagePath,
|
||||||
required this.paragraphs,
|
required this.paragraphs,
|
||||||
|
required this.filepath,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -19,11 +22,13 @@ class ListDetailScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _ListDetailScreenState extends State<ListDetailScreen> {
|
class _ListDetailScreenState extends State<ListDetailScreen> {
|
||||||
late List<bool> _readStatus;
|
late List<bool> _readStatus;
|
||||||
|
String _htmlContent = '';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_readStatus = List.generate(widget.paragraphs.length, (index) => false);
|
_readStatus = List.generate(widget.paragraphs.length, (index) => false);
|
||||||
|
loadHtml();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleReadStatus(int index) {
|
void _toggleReadStatus(int index) {
|
||||||
@@ -32,6 +37,15 @@ class _ListDetailScreenState extends State<ListDetailScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> loadHtml() async {
|
||||||
|
String html = await DefaultAssetBundle.of(
|
||||||
|
context,
|
||||||
|
).loadString(widget.filepath);
|
||||||
|
setState(() {
|
||||||
|
_htmlContent = html;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -85,7 +99,7 @@ class _ListDetailScreenState extends State<ListDetailScreen> {
|
|||||||
// ),
|
// ),
|
||||||
const SizedBox(height: 0),
|
const SizedBox(height: 0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
|
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
|
||||||
child:
|
child:
|
||||||
// ListView.builder(
|
// ListView.builder(
|
||||||
@@ -156,7 +170,46 @@ class _ListDetailScreenState extends State<ListDetailScreen> {
|
|||||||
// ),
|
// ),
|
||||||
Html(
|
Html(
|
||||||
style: {"body": Style(color: const Color.fromRGBO(0, 0, 0, 1))},
|
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();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ class AkunSaya extends StatefulWidget {
|
|||||||
class _AkunSayaState extends State<AkunSaya> {
|
class _AkunSayaState extends State<AkunSaya> {
|
||||||
dynamic _profileImage;
|
dynamic _profileImage;
|
||||||
dynamic _headerImage;
|
dynamic _headerImage;
|
||||||
|
ImageProvider? imageProvider;
|
||||||
|
|
||||||
final ImagePicker _picker = ImagePicker();
|
final ImagePicker _picker = ImagePicker();
|
||||||
|
|
||||||
Future<void> _pickImage(bool isProfile) async {
|
Future<void> _pickImage(bool isProfile) async {
|
||||||
@@ -35,13 +37,19 @@ class _AkunSayaState extends State<AkunSaya> {
|
|||||||
} else {
|
} else {
|
||||||
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
|
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
|
||||||
if (pickedFile != null) {
|
if (pickedFile != null) {
|
||||||
|
final imageFile = File(pickedFile.path);
|
||||||
setState(() {
|
setState(() {
|
||||||
if (isProfile) {
|
if (isProfile) {
|
||||||
_profileImage = File(pickedFile.path);
|
_profileImage = imageFile;
|
||||||
} else {
|
} 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<AkunSaya> {
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 40),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 40),
|
||||||
children: [
|
children: [
|
||||||
TextFormField(
|
TextFormField(
|
||||||
initialValue: "Cepot",
|
initialValue: "Luffy Kun",
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
border: UnderlineInputBorder(),
|
border: UnderlineInputBorder(),
|
||||||
labelText: 'Nama',
|
labelText: 'Nama',
|
||||||
@@ -106,7 +114,7 @@ class _AkunSayaState extends State<AkunSaya> {
|
|||||||
style: TextStyle(color: Colors.black),
|
style: TextStyle(color: Colors.black),
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
initialValue: "cpt09",
|
initialValue: "luffy01",
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
border: UnderlineInputBorder(),
|
border: UnderlineInputBorder(),
|
||||||
labelText: 'Nama Pengguna',
|
labelText: 'Nama Pengguna',
|
||||||
@@ -169,7 +177,7 @@ class _AkunSayaState extends State<AkunSaya> {
|
|||||||
: null,
|
: null,
|
||||||
child:
|
child:
|
||||||
_profileImage == null
|
_profileImage == null
|
||||||
? Icon(Icons.person, size: 50, color: Colors.white)
|
? Image.asset("assets/images/luffy.png")
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
@@ -184,14 +192,14 @@ class _AkunSayaState extends State<AkunSaya> {
|
|||||||
|
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 130,
|
top: 130,
|
||||||
left: MediaQuery.of(context).size.width / 2 - 50,
|
left: MediaQuery.of(context).size.width / 2 - 30,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _pickImage(true),
|
onTap: () => _pickImage(true),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.bottomRight,
|
alignment: Alignment.bottomRight,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Nama Akun",
|
"Luffy kun",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.deepPurple,
|
color: Colors.deepPurple,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
// final ImagePicker _picker = ImagePicker();
|
// final ImagePicker _picker = ImagePicker();
|
||||||
dynamic _profileImage;
|
dynamic _profileImage;
|
||||||
dynamic _headerImage;
|
dynamic _headerImage;
|
||||||
|
ImageProvider? imageProvider;
|
||||||
final ImagePicker _picker = ImagePicker();
|
final ImagePicker _picker = ImagePicker();
|
||||||
|
|
||||||
Future<void> _pickImage(bool isProfile) async {
|
Future<void> _pickImage(bool isProfile) async {
|
||||||
@@ -41,13 +42,19 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
} else {
|
} else {
|
||||||
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
|
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
|
||||||
if (pickedFile != null) {
|
if (pickedFile != null) {
|
||||||
|
final imageFile = File(pickedFile.path);
|
||||||
setState(() {
|
setState(() {
|
||||||
if (isProfile) {
|
if (isProfile) {
|
||||||
_profileImage = File(pickedFile.path);
|
_profileImage = imageFile;
|
||||||
} else {
|
} 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<ProfileScreen> {
|
|||||||
: null,
|
: null,
|
||||||
child:
|
child:
|
||||||
_profileImage == null
|
_profileImage == null
|
||||||
? Icon(
|
? Image.asset(
|
||||||
Icons.person,
|
"assets/images/luffy.png",
|
||||||
size: 50,
|
|
||||||
color: Colors.white,
|
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
@@ -162,9 +167,16 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Name",
|
"Luffy",
|
||||||
style: TextStyle(
|
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<ProfileScreen> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Edit Profile",
|
"Luffy Kun",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blueAccent,
|
color: const Color.fromARGB(
|
||||||
|
255,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -6,10 +6,14 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||||
#include <file_selector_linux/file_selector_plugin.h>
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
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 =
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
desktop_webview_window
|
||||||
file_selector_linux
|
file_selector_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,12 +5,14 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import desktop_webview_window
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import webview_flutter_wkwebview
|
import webview_flutter_wkwebview
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
|
|||||||
@@ -121,6 +121,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
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:
|
dropdown_button2:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -241,7 +249,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.4"
|
version: "0.15.4"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||||
@@ -368,6 +376,15 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
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:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -782,7 +799,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "4.11.0"
|
version: "4.11.0"
|
||||||
webview_flutter_android:
|
webview_flutter_android:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_android
|
name: webview_flutter_android
|
||||||
sha256: "5c3b6f992d123084903ec091b84f021c413a92a9af49038e4564a1b26c8452cf"
|
sha256: "5c3b6f992d123084903ec091b84f021c413a92a9af49038e4564a1b26c8452cf"
|
||||||
@@ -798,7 +815,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.11.0"
|
||||||
webview_flutter_wkwebview:
|
webview_flutter_wkwebview:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: c9f9be526fa0d3347374ceaa05c4b3acb85f4f112abd62f7d74b7d301fa515ff
|
sha256: c9f9be526fa0d3347374ceaa05c4b3acb85f4f112abd62f7d74b7d301fa515ff
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
camera: ^0.10.5+5
|
camera: ^0.10.5+5
|
||||||
|
http: 1.3.0
|
||||||
permission_handler: ^11.3.0
|
permission_handler: ^11.3.0
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
@@ -46,6 +47,13 @@ dependencies:
|
|||||||
image_picker_web: ^4.0.0
|
image_picker_web: ^4.0.0
|
||||||
flutter_plugin_android_lifecycle: ^2.0.9
|
flutter_plugin_android_lifecycle: ^2.0.9
|
||||||
webview_flutter: ^4.11.0
|
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
|
# arcore_flutter_plugin: ^0.2.0-alpha
|
||||||
# flutter_unity_widget: ^2022.2.1
|
# flutter_unity_widget: ^2022.2.1
|
||||||
# arcore_flutter_plugin:
|
# arcore_flutter_plugin:
|
||||||
@@ -102,6 +110,20 @@ flutter:
|
|||||||
- assets/icons/Saya.svg
|
- assets/icons/Saya.svg
|
||||||
- assets/icons/Scan.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
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/to/resolution-aware-images
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,14 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||||
#include <file_selector_windows/file_selector_windows.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
DesktopWebviewWindowPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
desktop_webview_window
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
|||||||