html content
@ -2,6 +2,8 @@
|
|||||||
<application
|
<application
|
||||||
android:label="furibase"
|
android:label="furibase"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|||||||
4
android/app/src/main/res/xml/network_security_config.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<base-config cleartextTrafficPermitted="true"/>
|
||||||
|
</network-security-config>
|
||||||
180
assets/html/findwords/findwords.html
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Game Nusantara</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
background: #f2f2f2;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 480px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 4px;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
.letter {
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
}
|
||||||
|
.found {
|
||||||
|
background-color: #a2f5a2 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 id="game-title">Game Nusantara</h1>
|
||||||
|
<div id="game-board"></div>
|
||||||
|
|
||||||
|
<h3>Kata yang harus ditemukan:</h3>
|
||||||
|
<ul id="target-words" style="padding-left: 1rem;"></ul>
|
||||||
|
<p id="penjelasan" style="margin-top: 1rem; font-size: 0.9rem; color: #444;"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Template Find The Word Game (drag to select)
|
||||||
|
const words = ['TENANG', 'SABAR', 'SYUKUR', 'CINTA', 'GEMBIRA', 'BANGGA'];
|
||||||
|
const board = document.getElementById('game-board');
|
||||||
|
const size = 12; // 12x12 grid
|
||||||
|
let grid = Array(size * size).fill('');
|
||||||
|
|
||||||
|
function randomLetter() {
|
||||||
|
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
return alphabet[Math.floor(Math.random() * alphabet.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeWord(word) {
|
||||||
|
const dir = Math.random() < 0.5 ? 'H' : 'V';
|
||||||
|
let x, y, success = false;
|
||||||
|
while (!success) {
|
||||||
|
x = Math.floor(Math.random() * (dir === 'H' ? size - word.length : size));
|
||||||
|
y = Math.floor(Math.random() * (dir === 'V' ? size - word.length : size));
|
||||||
|
let fits = true;
|
||||||
|
for (let i = 0; i < word.length; i++) {
|
||||||
|
let idx = dir === 'H' ? y * size + (x + i) : (y + i) * size + x;
|
||||||
|
if (grid[idx] && grid[idx] !== word[i]) {
|
||||||
|
fits = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fits) {
|
||||||
|
for (let i = 0; i < word.length; i++) {
|
||||||
|
let idx = dir === 'H' ? y * size + (x + i) : (y + i) * size + x;
|
||||||
|
grid[idx] = word[i];
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
words.forEach(w => placeWord(w));
|
||||||
|
grid = grid.map(cell => cell || randomLetter());
|
||||||
|
|
||||||
|
function renderGrid() {
|
||||||
|
board.className = 'grid';
|
||||||
|
board.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
|
||||||
|
board.innerHTML = '';
|
||||||
|
grid.forEach((char, i) => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = char;
|
||||||
|
div.className = 'letter';
|
||||||
|
div.dataset.index = i;
|
||||||
|
div.style.aspectRatio = '1/1';
|
||||||
|
div.style.border = '1px solid #ccc';
|
||||||
|
div.style.display = 'flex';
|
||||||
|
div.style.alignItems = 'center';
|
||||||
|
div.style.justifyContent = 'center';
|
||||||
|
div.style.fontSize = '1.2rem';
|
||||||
|
div.style.fontWeight = 'bold';
|
||||||
|
div.style.userSelect = 'none';
|
||||||
|
div.style.cursor = 'pointer';
|
||||||
|
board.appendChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGrid();
|
||||||
|
|
||||||
|
// Daftar kata yang harus ditemukan
|
||||||
|
// (Daftar kata tidak lagi ditampilkan sebagai list)
|
||||||
|
|
||||||
|
let currentSelection = [];
|
||||||
|
let currentWord = '';
|
||||||
|
let wordsFound = new Set();
|
||||||
|
let isMouseDown = false;
|
||||||
|
|
||||||
|
board.addEventListener('mousedown', (e) => {
|
||||||
|
if (!e.target.classList.contains('letter')) return;
|
||||||
|
isMouseDown = true;
|
||||||
|
selectCell(e.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
board.addEventListener('mouseover', (e) => {
|
||||||
|
if (!isMouseDown || !e.target.classList.contains('letter')) return;
|
||||||
|
selectCell(e.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', () => {
|
||||||
|
if (words.includes(currentWord)) {
|
||||||
|
currentSelection.forEach(c => {
|
||||||
|
c.style.backgroundColor = '#a2f5a2';
|
||||||
|
c.classList.add('found');
|
||||||
|
});
|
||||||
|
const penjelasanBox = document.getElementById('penjelasan');
|
||||||
|
const regex = new RegExp(currentWord, 'gi');
|
||||||
|
penjelasanBox.innerHTML = penjelasanBox.innerHTML.replace(regex, `<span style="color:green; font-weight:bold">${currentWord}</span>`);
|
||||||
|
|
||||||
|
wordsFound.add(currentWord);
|
||||||
|
if (wordsFound.size === words.length) {
|
||||||
|
alert('Selamat! Kamu telah menemukan semua kata positif. Ingat, berpikir positif setiap hari bisa membuat hidupmu lebih ceria dan penuh semangat 🌈');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentSelection.forEach(c => c.style.backgroundColor = '');
|
||||||
|
}
|
||||||
|
currentSelection = [];
|
||||||
|
currentWord = '';
|
||||||
|
isMouseDown = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function selectCell(cell) {
|
||||||
|
if (cell.classList.contains('found') || currentSelection.includes(cell)) return;
|
||||||
|
cell.style.backgroundColor = '#ffeaa7';
|
||||||
|
currentSelection.push(cell);
|
||||||
|
currentWord += cell.textContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Penjelasan pentingnya emosi positif
|
||||||
|
const penjelasan = `Di dalam hidup, kita bisa merasa banyak hal. Tapi tahukah kamu? Emosi positif seperti <strong>tenang</strong>, <strong>sabar</strong>, <strong>syukur</strong>, <strong>cinta</strong>, <strong>gembira</strong>, dan <strong>bangga</strong> adalah kunci untuk hidup yang sehat dan bahagia. Yuk, temukan kata-kata positif itu di puzzle, lalu pikirkan kapan terakhir kali kamu merasakannya!`;
|
||||||
|
document.getElementById('penjelasan').innerHTML = penjelasan;
|
||||||
|
|
||||||
|
function includeScript(file) {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = file;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
assets/html/findwords/hati.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/findwords/latar.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/html/findwords/parkir - Copy.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/html/findwords/parkir.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/findwords/sekolah.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
16
assets/html/findwords/test.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Test</title>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
document.body.innerHTML += '<p style="color:green;">✅ JS is working!</p>';
|
||||||
|
};
|
||||||
|
window.onload = showAlert;
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello WebView</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
assets/html/freekake.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
assets/html/memory/ayambetutu.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/html/memory/ayamtaliwang.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/html/memory/bali.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/memory/bikaambon.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
assets/html/memory/freekake.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
assets/html/memory/gudeg.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/html/memory/kalsel.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
177
assets/html/memory/memory.html
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Game Nusantara</title>
|
||||||
|
<link rel="icon" href="data:,">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
background: #f2f2f2;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 480px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.grid, .drag-area, .drop-area {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
|
||||||
|
}
|
||||||
|
.card, .letter, .drop-zone, .drag-item {
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.hidden { background: #ccc; color: transparent; }
|
||||||
|
.matched { background: #d4edda; }
|
||||||
|
.drop-zone { height: 80px; background: #eee; border: 2px dashed #bbb; }
|
||||||
|
.drag-item[draggable="true"] { cursor: grab; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 id="game-title">Game Nusantara</h1>
|
||||||
|
<div id="game-board"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const items = [
|
||||||
|
'pempek.png', 'sumsel.png',
|
||||||
|
'sopkonro.png', 'sulsel.png',
|
||||||
|
'rendang.png', 'sumbar.png',
|
||||||
|
'tinutuan.png', 'sulut.png',
|
||||||
|
'ayambetutu.png', 'bali.png',
|
||||||
|
'bikaambon.png', 'sumut.png',
|
||||||
|
'gudeg.png', 'yogyakarta.png',
|
||||||
|
'sotobanjar.png', 'kalsel.png',
|
||||||
|
'ayamtaliwang.png', 'ntb.png'
|
||||||
|
];
|
||||||
|
|
||||||
|
const board = document.getElementById('game-board');
|
||||||
|
board.className = 'grid';
|
||||||
|
board.style.gridTemplateColumns = 'repeat(3, 1fr)';
|
||||||
|
|
||||||
|
let selectedItems = shuffle([...items]);
|
||||||
|
let shuffled = shuffle(selectedItems.slice(0, 18));
|
||||||
|
let selected = [], matched = [];
|
||||||
|
|
||||||
|
function shuffle(array) {
|
||||||
|
return array.sort(() => Math.random() - 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
board.innerHTML = '';
|
||||||
|
shuffled.forEach((img, i) => {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'card hidden';
|
||||||
|
card.style.backgroundImage = 'url("freekake.png")';
|
||||||
|
card.style.backgroundSize = 'contain';
|
||||||
|
card.style.backgroundRepeat = 'no-repeat';
|
||||||
|
card.style.backgroundPosition = 'center';
|
||||||
|
card.dataset.index = i;
|
||||||
|
card.style.aspectRatio = '1/1';
|
||||||
|
card.style.borderRadius = '12px';
|
||||||
|
card.style.overflow = 'hidden';
|
||||||
|
card.style.backgroundColor = '#fff';
|
||||||
|
card.style.display = 'flex';
|
||||||
|
card.style.flexDirection = 'column';
|
||||||
|
card.style.alignItems = 'center';
|
||||||
|
card.style.justifyContent = 'center';
|
||||||
|
card.style.padding = '8px';
|
||||||
|
card.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
|
||||||
|
board.appendChild(card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function revealCard(i) {
|
||||||
|
const el = board.children[i];
|
||||||
|
el.classList.remove('hidden');
|
||||||
|
el.style.backgroundImage = 'none';
|
||||||
|
el.innerHTML = `<img src="${shuffled[i]}" alt="" style="width: 100%; height: auto; object-fit: contain;">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideCard(i) {
|
||||||
|
const el = board.children[i];
|
||||||
|
el.classList.add('hidden');
|
||||||
|
el.style.backgroundImage = 'url("freekake.png")';
|
||||||
|
el.style.backgroundSize = 'contain';
|
||||||
|
el.style.backgroundRepeat = 'no-repeat';
|
||||||
|
el.style.backgroundPosition = 'center';
|
||||||
|
el.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMatch() {
|
||||||
|
const [a, b] = selected;
|
||||||
|
const pairs = {
|
||||||
|
'pempek.png': 'sumsel.png', 'sumsel.png': 'pempek.png',
|
||||||
|
'sopkonro.png': 'sulsel.png', 'sulsel.png': 'sopkonro.png',
|
||||||
|
'rendang.png': 'sumbar.png', 'sumbar.png': 'rendang.png',
|
||||||
|
'tinutuan.png': 'sulut.png', 'sulut.png': 'tinutuan.png',
|
||||||
|
'ayambetutu.png': 'bali.png', 'bali.png': 'ayambetutu.png',
|
||||||
|
'bikaambon.png': 'sumut.png', 'sumut.png': 'bikaambon.png',
|
||||||
|
'gudeg.png': 'yogyakarta.png', 'yogyakarta.png': 'gudeg.png',
|
||||||
|
'sotobanjar.png': 'kalsel.png', 'kalsel.png': 'sotobanjar.png',
|
||||||
|
'ayamtaliwang.png': 'ntb.png', 'ntb.png': 'ayamtaliwang.png'
|
||||||
|
};
|
||||||
|
if (pairs[shuffled[a]] === shuffled[b]) {
|
||||||
|
matched.push(a, b);
|
||||||
|
board.children[a].classList.add('matched');
|
||||||
|
board.children[a].style.backgroundColor = '#d4edda';
|
||||||
|
board.children[b].classList.add('matched');
|
||||||
|
board.children[b].style.backgroundColor = '#d4edda';
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
hideCard(a);
|
||||||
|
hideCard(b);
|
||||||
|
}, 800);
|
||||||
|
}
|
||||||
|
selected = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
board.addEventListener('click', (e) => {
|
||||||
|
const index = e.target.closest('.card')?.dataset.index;
|
||||||
|
if (!index || selected.includes(+index) || matched.includes(+index)) return;
|
||||||
|
revealCard(index);
|
||||||
|
selected.push(+index);
|
||||||
|
if (selected.length === 2) checkMatch();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 🔍 Expose render and notify Flutter
|
||||||
|
window.render = render;
|
||||||
|
|
||||||
|
if (window.flutter_inappwebview) {
|
||||||
|
window.flutter_inappwebview.callHandler('pageReady', {
|
||||||
|
boardExists: !!document.getElementById("game-board"),
|
||||||
|
hasRender: typeof render === "function"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional helper
|
||||||
|
function includeScript(file) {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = file;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
assets/html/memory/ntb.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/html/memory/pempek.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
assets/html/memory/rendang.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
assets/html/memory/sopkonro.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
assets/html/memory/sotobanjar.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/html/memory/sulsel.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/html/memory/sulut.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/memory/sumbar.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
assets/html/memory/sumsel.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/html/memory/sumut.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/html/memory/tinutuan.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/html/memory/yogyakarta.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
@ -55,7 +55,13 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
|||||||
charSex: "Laki-laki",
|
charSex: "Laki-laki",
|
||||||
charOrigin: "Jawa Barat",
|
charOrigin: "Jawa Barat",
|
||||||
content:
|
content:
|
||||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan! Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang, hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol, Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk di dekatnya saat ia bercerita.
|
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan!
|
||||||
|
Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang,
|
||||||
|
hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras,
|
||||||
|
suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol,
|
||||||
|
Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur
|
||||||
|
orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah
|
||||||
|
duduk di dekatnya saat ia bercerita.
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -119,8 +125,20 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
|||||||
charName: "Cepot",
|
charName: "Cepot",
|
||||||
charSex: "Laki-laki",
|
charSex: "Laki-laki",
|
||||||
charOrigin: "Jawa Barat",
|
charOrigin: "Jawa Barat",
|
||||||
content:
|
content: """
|
||||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan! Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang, hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol, Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk di dekatnya saat ia bercerita.
|
Cepot adalah sosok yang begitu menarik—aneh,
|
||||||
|
ceria, dan penuh kejutan! Ia muncul seperti
|
||||||
|
tokoh dari dongeng lama yang lupa pulang ke rumah,
|
||||||
|
dengan wajah merah seperti apel matang,
|
||||||
|
hidung besar yang tampak siap
|
||||||
|
mencium rahasia, dan mata bulat
|
||||||
|
yang selalu bersinar penuh rasa ingin
|
||||||
|
tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat
|
||||||
|
pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol,
|
||||||
|
Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan
|
||||||
|
yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak
|
||||||
|
menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk
|
||||||
|
di dekatnya saat ia bercerita.
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
105
lib/screen/pustaka/_list_detail_screen.dart
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
|
class _ListDetailScreen extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final String? filepath;
|
||||||
|
|
||||||
|
const _ListDetailScreen({super.key, required this.title, this.filepath});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ListDetailScreen> createState() => _ListDetailScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ListDetailScreenState extends State<_ListDetailScreen> {
|
||||||
|
List<bool> checklist = [];
|
||||||
|
late WebViewController _controller;
|
||||||
|
late String? fPath = widget.filepath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller =
|
||||||
|
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||||
|
checklist = List.generate(paragraphs.length, (index) => false);
|
||||||
|
if (fPath != null && fPath!.isNotEmpty) {
|
||||||
|
_loadContent(fPath!); // <- ini penting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> paragraphs = [
|
||||||
|
"Paragraf pertama tentang ${"widget.title"}.",
|
||||||
|
"Paragraf kedua dengan informasi tambahan.",
|
||||||
|
"Paragraf ketiga yang menjelaskan detail lebih lanjut.",
|
||||||
|
"Paragraf keempat yang melengkapi pembahasan.",
|
||||||
|
];
|
||||||
|
|
||||||
|
void _loadContent(String path) async {
|
||||||
|
try {
|
||||||
|
if (path.startsWith('http')) {
|
||||||
|
_controller.loadRequest(Uri.parse(path));
|
||||||
|
} else {
|
||||||
|
String fileHtml = await rootBundle.loadString(path);
|
||||||
|
_controller.loadHtmlString(fileHtml);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Error loading HTML: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: AppBar(title: Text(widget.title)),
|
||||||
|
body:
|
||||||
|
(fPath != null && fPath!.isNotEmpty)
|
||||||
|
? WebViewWidget(controller: _controller)
|
||||||
|
: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/images/default.png',
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Ini adalah detail dari ${widget.title}.",
|
||||||
|
style: const TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: paragraphs.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(paragraphs[index]),
|
||||||
|
trailing: Checkbox(
|
||||||
|
value: checklist[index],
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
setState(() {
|
||||||
|
checklist[index] = value!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
class ListDetailScreen extends StatefulWidget {
|
class ListDetailScreen extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
@ -13,89 +14,118 @@ class ListDetailScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ListDetailScreenState extends State<ListDetailScreen> {
|
class _ListDetailScreenState extends State<ListDetailScreen> {
|
||||||
List<bool> checklist = [];
|
late InAppWebViewController _webViewController;
|
||||||
late WebViewController _controller;
|
|
||||||
late String? fPath = widget.filepath;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
checklist = List.generate(paragraphs.length, (index) => false);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> paragraphs = [
|
|
||||||
"Paragraf pertama tentang ${"widget.title"}.",
|
|
||||||
"Paragraf kedua dengan informasi tambahan.",
|
|
||||||
"Paragraf ketiga yang menjelaskan detail lebih lanjut.",
|
|
||||||
"Paragraf keempat yang melengkapi pembahasan.",
|
|
||||||
];
|
|
||||||
|
|
||||||
void _loadContent(String path) async {
|
|
||||||
if (path.startsWith('http')) {
|
|
||||||
// Load dari Internet
|
|
||||||
_controller.loadRequest(Uri.parse(path));
|
|
||||||
} else {
|
|
||||||
// Load dari assets lokal
|
|
||||||
String fileHtml = await rootBundle.loadString(path);
|
|
||||||
_controller.loadHtmlString(fileHtml);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
String _getMimeType(String path) {
|
||||||
|
if (path.endsWith('.png')) return 'image/png';
|
||||||
|
if (path.endsWith('.jpg') || path.endsWith('.jpeg')) return 'image/jpeg';
|
||||||
|
if (path.endsWith('.svg')) return 'image/svg+xml';
|
||||||
|
if (path.endsWith('.html')) return 'text/html';
|
||||||
|
if (path.endsWith('.css')) return 'text/css';
|
||||||
|
if (path.endsWith('.js')) return 'application/javascript';
|
||||||
|
return 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
|
||||||
appBar: AppBar(title: Text(widget.title)),
|
appBar: AppBar(title: Text(widget.title)),
|
||||||
body:
|
body:
|
||||||
(fPath != null && fPath!.isNotEmpty)
|
widget.filepath != null
|
||||||
? WebViewWidget(controller: _controller)
|
? InAppWebView(
|
||||||
: Padding(
|
initialUrlRequest: URLRequest(url: WebUri("about:blank")),
|
||||||
padding: const EdgeInsets.all(16.0),
|
initialOptions: InAppWebViewGroupOptions(
|
||||||
child: Column(
|
crossPlatform: InAppWebViewOptions(
|
||||||
children: [
|
javaScriptEnabled: true,
|
||||||
// Gambar di kiri atas dengan teks di kanan
|
allowFileAccessFromFileURLs: true,
|
||||||
Row(
|
allowUniversalAccessFromFileURLs: true,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Image.asset(
|
|
||||||
'assets/images/default.png', // Ganti dengan gambar yang sesuai
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"Ini adalah detail dari ${widget.title}.",
|
|
||||||
style: const TextStyle(fontSize: 18),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
onWebViewCreated: (controller) async {
|
||||||
),
|
_webViewController = controller;
|
||||||
const SizedBox(height: 20),
|
|
||||||
|
|
||||||
// Paragraf dengan checklist
|
final html = await rootBundle.loadString(widget.filepath!);
|
||||||
Expanded(
|
final base = widget.filepath!.substring(
|
||||||
child: ListView.builder(
|
0,
|
||||||
itemCount: paragraphs.length,
|
widget.filepath!.lastIndexOf('/') + 1,
|
||||||
itemBuilder: (context, index) {
|
);
|
||||||
return ListTile(
|
await controller.loadData(
|
||||||
title: Text(paragraphs[index]),
|
data: html,
|
||||||
trailing: Checkbox(
|
baseUrl: WebUri(
|
||||||
value: checklist[index],
|
"http://localhost/$base",
|
||||||
onChanged: (bool? value) {
|
), // agar path relatif seperti img1/* jalan
|
||||||
setState(() {
|
mimeType: 'text/html',
|
||||||
checklist[index] = value!;
|
encoding: 'utf-8',
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
onLoadStop: (controller, url) async {
|
||||||
),
|
debugPrint("🚀 onLoadStop called. URL: $url");
|
||||||
],
|
|
||||||
),
|
var result = await controller.evaluateJavascript(
|
||||||
),
|
source: """
|
||||||
|
(() => {
|
||||||
|
const board = document.getElementById('game-board');
|
||||||
|
const hasRender = typeof renderGrid === 'function';
|
||||||
|
return { hasRender, boardExists: board !== null };
|
||||||
|
})();
|
||||||
|
""",
|
||||||
|
);
|
||||||
|
|
||||||
|
debugPrint("📊 Evaluated JS result: $result");
|
||||||
|
|
||||||
|
final jsCheck = await controller.evaluateJavascript(
|
||||||
|
source: """
|
||||||
|
typeof renderGrid === 'function' &&
|
||||||
|
document.querySelector('#game-board') !== null
|
||||||
|
""",
|
||||||
|
);
|
||||||
|
|
||||||
|
debugPrint(
|
||||||
|
"Apakah renderGrid tersedia dan board muncul? => $jsCheck",
|
||||||
|
);
|
||||||
|
|
||||||
|
final imageLoaded = await controller.evaluateJavascript(
|
||||||
|
source: """
|
||||||
|
Array.from(document.images).every(img => img.complete)
|
||||||
|
""",
|
||||||
|
);
|
||||||
|
|
||||||
|
debugPrint("Semua gambar berhasil dimuat? => $imageLoaded");
|
||||||
|
},
|
||||||
|
|
||||||
|
// (Opsional) tangkap log dari JS
|
||||||
|
onConsoleMessage: (controller, consoleMessage) {
|
||||||
|
debugPrint("📢 JS Console: ${consoleMessage.message}");
|
||||||
|
},
|
||||||
|
shouldInterceptRequest: (controller, request) async {
|
||||||
|
final url = request.url;
|
||||||
|
if (url == null || url.host != 'localhost') return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Strip "http://localhost/" from the path
|
||||||
|
final path = url.path.replaceFirst('/', '');
|
||||||
|
|
||||||
|
final asset = await rootBundle.load(path);
|
||||||
|
final mimeType = _getMimeType(path);
|
||||||
|
|
||||||
|
return WebResourceResponse(
|
||||||
|
contentType: mimeType,
|
||||||
|
data: asset.buffer.asUint8List(),
|
||||||
|
statusCode: 200,
|
||||||
|
reasonPhrase: 'OK',
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print("⚠️ Asset not found: ${url.path} -> $e");
|
||||||
|
return WebResourceResponse(
|
||||||
|
contentType: 'text/plain',
|
||||||
|
data: Uint8List.fromList(utf8.encode('404 Not Found')),
|
||||||
|
statusCode: 404,
|
||||||
|
reasonPhrase: 'Not Found',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: const Center(child: Text("Tidak ada file HTML")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,12 +6,14 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:freekake/components/card_list.dart';
|
import 'package:freekake/components/card_list.dart';
|
||||||
import 'package:freekake/components/collection_container%20copy.dart';
|
import 'package:freekake/components/collection_container%20copy.dart';
|
||||||
import 'package:freekake/helpers/color_helper.dart';
|
import 'package:freekake/helpers/color_helper.dart';
|
||||||
|
import 'package:freekake/screen/pustaka/list_detail_screen.dart';
|
||||||
import 'package:list_detail_extension/list_detail_extension.dart';
|
import 'package:list_detail_extension/list_detail_extension.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
|
|
||||||
class ListEducation extends StatefulWidget {
|
class ListEducation extends StatefulWidget {
|
||||||
const ListEducation({super.key});
|
final String? selectedCategory;
|
||||||
|
const ListEducation({super.key, this.selectedCategory});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ListEducation> createState() => _ListEducationState();
|
State<ListEducation> createState() => _ListEducationState();
|
||||||
@ -22,8 +24,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
late final WebViewController _controller;
|
late final WebViewController _controller;
|
||||||
late String urlOrAssetPath;
|
late String urlOrAssetPath;
|
||||||
bool _shouldShowWebView = false;
|
bool _shouldShowWebView = false;
|
||||||
|
String? selectedCategory;
|
||||||
// load extension
|
|
||||||
final listDetailExtension = ListDetailExtension();
|
final listDetailExtension = ListDetailExtension();
|
||||||
|
|
||||||
Future<void> _initExtension() async {
|
Future<void> _initExtension() async {
|
||||||
@ -69,18 +70,55 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
""",
|
""",
|
||||||
"file": "assets/html/index.html",
|
"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 = [];
|
List<Map<String, dynamic>> filteredItems = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.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);
|
filteredItems = List.from(_listContent);
|
||||||
|
}
|
||||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
_shouldShowWebView = true;
|
_shouldShowWebView = true;
|
||||||
_controller =
|
_controller =
|
||||||
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||||
urlOrAssetPath = "assets/makanan_bergizi/index.html";
|
urlOrAssetPath = "assets/html/index.html";
|
||||||
_loadContent(urlOrAssetPath);
|
_loadContent(urlOrAssetPath);
|
||||||
_initExtension();
|
_initExtension();
|
||||||
}
|
}
|
||||||
@ -92,18 +130,20 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
// Load dari Internet
|
// Load dari Internet
|
||||||
_controller.loadRequest(Uri.parse(path));
|
_controller.loadRequest(Uri.parse(path));
|
||||||
} else {
|
} else {
|
||||||
// Load dari assets lokal
|
try {
|
||||||
// String fileHtml = await rootBundle.loadString(path);
|
await rootBundle.load(path);
|
||||||
String fileHtml = await DefaultAssetBundle.of(
|
await _controller.loadFlutterAsset(path);
|
||||||
context,
|
} catch (e) {
|
||||||
).loadString('assets/html/index.html');
|
print("Gagal memuat file HTML: $path\nError: $e");
|
||||||
_controller.loadHtmlString(fileHtml);
|
}
|
||||||
|
_controller.loadFlutterAsset(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterSearch(String query) {
|
void filterSearch(String query) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
selectedCategory = null;
|
||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
filteredItems = List.from(_listContent);
|
filteredItems = List.from(_listContent);
|
||||||
} else {
|
} else {
|
||||||
@ -117,6 +157,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
|
|
||||||
void filterByCategory(String category) {
|
void filterByCategory(String category) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
selectedCategory = category;
|
||||||
filteredItems =
|
filteredItems =
|
||||||
_listContent.where((item) {
|
_listContent.where((item) {
|
||||||
return item["category"].toLowerCase() == category.toLowerCase();
|
return item["category"].toLowerCase() == category.toLowerCase();
|
||||||
@ -126,7 +167,6 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String searchQuery = "";
|
|
||||||
final List<Map<String, dynamic>> collections = [
|
final List<Map<String, dynamic>> collections = [
|
||||||
{
|
{
|
||||||
"label": "Kesehatan",
|
"label": "Kesehatan",
|
||||||
@ -158,7 +198,8 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
collections
|
collections
|
||||||
.where(
|
.where(
|
||||||
(item) => item["label"].toLowerCase().contains(
|
(item) => item["label"].toLowerCase().contains(
|
||||||
searchQuery.toLowerCase(),
|
// searchQuery.toLowerCase(),
|
||||||
|
searchController.text.toLowerCase(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
@ -176,7 +217,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
// Header Section
|
// Header Section
|
||||||
headerContainer(context, filteredCollections),
|
headerContainer(context, collections),
|
||||||
// Collection Items dengan Filter
|
// Collection Items dengan Filter
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Expanded(child: contentContainer(context)),
|
Expanded(child: contentContainer(context)),
|
||||||
@ -255,6 +296,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children:
|
children:
|
||||||
filteredCollections.map((item) {
|
filteredCollections.map((item) {
|
||||||
|
final isSelected = selectedCategory == item["category"];
|
||||||
return CollectionContainer(
|
return CollectionContainer(
|
||||||
label: item["label"]!,
|
label: item["label"]!,
|
||||||
imageSvg: item["image"]!,
|
imageSvg: item["image"]!,
|
||||||
@ -262,9 +304,16 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
iconh: 20,
|
iconh: 20,
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 70,
|
height: 70,
|
||||||
textColor: Colors.black,
|
textColor:
|
||||||
|
isSelected
|
||||||
|
? const Color.fromARGB(255, 230, 48, 160)
|
||||||
|
: Colors.black,
|
||||||
lblSize: 10,
|
lblSize: 10,
|
||||||
colorContiner: ColorHelper.hexToColor(item["color"]),
|
// colorContiner: ColorHelper.hexToColor(item["color"]),
|
||||||
|
colorContiner:
|
||||||
|
isSelected
|
||||||
|
? const Color.fromARGB(255, 84, 3, 224)
|
||||||
|
: ColorHelper.hexToColor(item["color"]),
|
||||||
onTapAc:
|
onTapAc:
|
||||||
() => {
|
() => {
|
||||||
searchController.clear(),
|
searchController.clear(),
|
||||||
@ -347,36 +396,41 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
GridView _generateList() {
|
GridView _generateList() {
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 1, // 2 Kolom
|
crossAxisCount: 1,
|
||||||
crossAxisSpacing: 10,
|
crossAxisSpacing: 10,
|
||||||
mainAxisSpacing: 10,
|
mainAxisSpacing: 10,
|
||||||
childAspectRatio: 2.5,
|
childAspectRatio: 2.5,
|
||||||
),
|
),
|
||||||
itemCount: _listContent.length,
|
itemCount: filteredItems.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
child: CardList(
|
child: CardList(
|
||||||
title: _listContent[index]["title"] ?? "",
|
title: filteredItems[index]["title"] ?? "",
|
||||||
body: _listContent[index]["body"] ?? "",
|
body: filteredItems[index]["body"] ?? "",
|
||||||
gambar: _listContent[index]['image'],
|
gambar: filteredItems[index]['image'],
|
||||||
point: _listContent[index]['coint'],
|
point: filteredItems[index]['point'],
|
||||||
coint: _listContent[index]['point'],
|
coint: filteredItems[index]['coint'],
|
||||||
tipe: _listContent[index]['tipe'],
|
tipe: filteredItems[index]['type'],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder:
|
builder:
|
||||||
(context) => listDetailExtension.buildPage({
|
// (context) => listDetailExtension.buildPage({
|
||||||
'title': filteredItems[index]['category'],
|
// 'title': filteredItems[index]['category'],
|
||||||
'imagePath': filteredItems[index]['image'],
|
// 'imagePath': filteredItems[index]['image'],
|
||||||
'filepath': filteredItems[index]['file'],
|
// 'filepath': filteredItems[index]['file'],
|
||||||
'paragraphs':
|
// 'paragraphs':
|
||||||
"""
|
// """
|
||||||
"""
|
// """
|
||||||
"<h1> ${_listContent[index]["title"]} </h1> <p> ${_listContent[index]["body"]}",
|
// "<h1> ${filteredItems[index]["title"]} </h1> <p> ${filteredItems[index]["body"]}",
|
||||||
}),
|
// }),
|
||||||
|
(context) => ListDetailScreen(
|
||||||
|
title: filteredItems[index]['category'],
|
||||||
|
// 'imagePath': filteredItems[index]['image'],
|
||||||
|
filepath: filteredItems[index]['file'],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -74,106 +74,11 @@ class _ListDetailScreenState extends State<ListPustakaDetailScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.all(20.0),
|
|
||||||
// child: Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Image.asset(
|
|
||||||
// widget.imagePath,
|
|
||||||
// width: 100,
|
|
||||||
// height: 100,
|
|
||||||
// fit: BoxFit.cover,
|
|
||||||
// ),
|
|
||||||
// const SizedBox(width: 16),
|
|
||||||
// Expanded(
|
|
||||||
// child: Center(
|
|
||||||
// child: Text(
|
|
||||||
// widget.title,
|
|
||||||
// style: const TextStyle(
|
|
||||||
// fontSize: 22,
|
|
||||||
// fontWeight: FontWeight.bold,
|
|
||||||
// color: Colors.black,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
const SizedBox(height: 0),
|
const SizedBox(height: 0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
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: htmlBody(),
|
||||||
// ListView.builder(
|
|
||||||
// itemCount: widget.paragraphs.length,
|
|
||||||
// itemBuilder: (context, index) {
|
|
||||||
// return
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
// child: Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Expanded(
|
|
||||||
// child:
|
|
||||||
// // Text(
|
|
||||||
// // widget.paragraphs[index] +
|
|
||||||
// // style: TextStyle(color: Colors.black),
|
|
||||||
// Html(
|
|
||||||
// // style: {
|
|
||||||
// // "body": Style(
|
|
||||||
// // color: const Color.fromRGBO(0, 0, 0, 1),
|
|
||||||
// // ),
|
|
||||||
// // },
|
|
||||||
// data:
|
|
||||||
// widget.paragraphs +
|
|
||||||
// """
|
|
||||||
// <html>
|
|
||||||
// <!-- Text between angle brackets is an HTML tag and is not displayed.
|
|
||||||
// Most tags, such as the HTML and /HTML tags that surround the contents of
|
|
||||||
// a page, come in pairs; some tags, like HR, for a horizontal rule, stand
|
|
||||||
// alone. Comments, such as the text you're reading, are not displayed when
|
|
||||||
// the Web page is shown. The information between the HEAD and /HEAD tags is
|
|
||||||
// not displayed. The information between the BODY and /BODY tags is displayed.-->
|
|
||||||
// <head>
|
|
||||||
// <title>Enter a title, displayed at the top of the window.</title>
|
|
||||||
// </head>
|
|
||||||
// <!-- The information between the BODY and /BODY tags is displayed.-->
|
|
||||||
// <body>
|
|
||||||
// <h1>Enter the main heading, usually the same as the title.</h1>
|
|
||||||
// <p>Be <b>bold</b> in stating your key points. Put them in a list: </p>
|
|
||||||
// <ul>
|
|
||||||
// <li>The first item in your list</li>
|
|
||||||
// <li>The second item; <i>italicize</i> key words</li>
|
|
||||||
// </ul>
|
|
||||||
// <p>Improve your image by including an image. </p>
|
|
||||||
// <p><img src="http://www.mygifs.com/CoverImage.gif" alt="A Great HTML Resource"></p>
|
|
||||||
// <p>Add a link to your favorite <a href="https://www.dummies.com/">Web site</a>.
|
|
||||||
// Break up your page with a horizontal rule or two. </p>
|
|
||||||
// <hr>
|
|
||||||
// <p>Finally, link to <a href="page2.html">another page</a> in your own Web site.</p>
|
|
||||||
// <!-- And add a copyright notice.-->
|
|
||||||
// <p>© Wiley Publishing, 2011</p>
|
|
||||||
// </body>
|
|
||||||
// </html>
|
|
||||||
// """,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// // ),
|
|
||||||
// // Checkbox(
|
|
||||||
// // value: _readStatus[index],
|
|
||||||
// // onChanged: (bool? value) {
|
|
||||||
// // _toggleReadStatus(index);
|
|
||||||
// // },
|
|
||||||
// // ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
htmlBody(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -44,6 +44,32 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
final List<Map<String, dynamic>> _genres = [
|
||||||
|
{
|
||||||
|
"label": "Game",
|
||||||
|
"type": "game",
|
||||||
|
"image": "assets/icons/healthy.svg",
|
||||||
|
"color": "#cdd0ee",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Novel",
|
||||||
|
"image": "assets/icons/Nutrition.svg",
|
||||||
|
"color": "#e8e29a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "TTS",
|
||||||
|
"type": "puzzle",
|
||||||
|
"image": "assets/icons/Education.svg",
|
||||||
|
"color": "#efd8c6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Pazzle",
|
||||||
|
"type": "puzzle",
|
||||||
|
"image": "assets/icons/Safety.svg",
|
||||||
|
"color": "#cef1da",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
void _onMenuTapped(int index) {
|
void _onMenuTapped(int index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedIndex = index;
|
_selectedIndex = index;
|
||||||
@ -60,14 +86,23 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
final buttonScanSize = screenWidth * 0.20;
|
final buttonScanSize = screenWidth * 0.20;
|
||||||
final double bottomPadding = (9000 / screenWidth).clamp(0, 0.2);
|
final double bottomPadding = (9000 / screenWidth).clamp(0, 0.2);
|
||||||
List<Map<String, dynamic>> filteredCollections =
|
|
||||||
_collections
|
List<Map<String, dynamic>> filterCollections(
|
||||||
|
List<Map<String, dynamic>> collections,
|
||||||
|
String query,
|
||||||
|
) {
|
||||||
|
return collections
|
||||||
.where(
|
.where(
|
||||||
(item) => item["label"]!.toLowerCase().contains(
|
(item) =>
|
||||||
_searchQuery.toLowerCase(),
|
item["label"]!.toLowerCase().contains(query.toLowerCase()),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> filteredCollections = filterCollections(
|
||||||
|
_collections,
|
||||||
|
_searchQuery,
|
||||||
|
);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
||||||
@ -121,16 +156,6 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// // Date Display
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.symmetric(vertical: 10),
|
|
||||||
// child: Text(
|
|
||||||
// DateTime.now().toString(),
|
|
||||||
// style: const TextStyle(color: Colors.white),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// Search Bar
|
// Search Bar
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||||
@ -198,7 +223,10 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => const ListEducation(),
|
builder:
|
||||||
|
(_) => ListEducation(
|
||||||
|
selectedCategory: item["label"],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -231,10 +259,12 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: List.generate(
|
children:
|
||||||
10,
|
_genres.map((genre) {
|
||||||
(index) => Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8.0,
|
||||||
|
),
|
||||||
child: Card(
|
child: Card(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
@ -267,7 +297,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
color: Colors.blueAccent,
|
color: Colors.blueAccent,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Topic ${index + 1}',
|
genre['label'],
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color.fromARGB(255, 0, 0, 0),
|
color: Color.fromARGB(255, 0, 0, 0),
|
||||||
@ -278,14 +308,12 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
// Bottom Navigation
|
|
||||||
// MainMenu(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// BG MEnu
|
// BG MEnu
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import Foundation
|
|||||||
|
|
||||||
import desktop_webview_window
|
import desktop_webview_window
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
|
import flutter_inappwebview_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
|
||||||
@ -14,6 +15,7 @@ import webview_flutter_wkwebview
|
|||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
|
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||||
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"))
|
||||||
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||||
|
|||||||
64
pubspec.lock
@ -206,6 +206,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0-beta.2"
|
version: "3.0.0-beta.2"
|
||||||
|
flutter_inappwebview:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview
|
||||||
|
sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
|
flutter_inappwebview_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_android
|
||||||
|
sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
|
flutter_inappwebview_internal_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_internal_annotations
|
||||||
|
sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
flutter_inappwebview_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_ios
|
||||||
|
sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_inappwebview_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_macos
|
||||||
|
sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_inappwebview_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_platform_interface
|
||||||
|
sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0+1"
|
||||||
|
flutter_inappwebview_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_web
|
||||||
|
sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_inappwebview_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_windows
|
||||||
|
sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|||||||
13
pubspec.yaml
@ -54,6 +54,7 @@ dependencies:
|
|||||||
url: https://github.com/fhauze/list_detail_screen.git
|
url: https://github.com/fhauze/list_detail_screen.git
|
||||||
ref: main
|
ref: main
|
||||||
desktop_webview_window: ^0.2.3
|
desktop_webview_window: ^0.2.3
|
||||||
|
flutter_inappwebview: ^6.0.0
|
||||||
# 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:
|
||||||
@ -124,6 +125,18 @@ flutter:
|
|||||||
- assets/html/seratair.png
|
- assets/html/seratair.png
|
||||||
- assets/html/vitaminmineral.png
|
- assets/html/vitaminmineral.png
|
||||||
|
|
||||||
|
#drag and drop
|
||||||
|
- assets/html/findwords/
|
||||||
|
- assets/html/findwords/test.html
|
||||||
|
- assets/html/findwords/findwords.html
|
||||||
|
- assets/html/freekake.png
|
||||||
|
- assets/html/memory/
|
||||||
|
- assets/html/memory/memory.html
|
||||||
|
|
||||||
|
#assets puzzle memory
|
||||||
|
- assets/html/memory/freekake.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
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <desktop_webview_window/desktop_webview_window_plugin.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 <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.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>
|
||||||
|
|
||||||
@ -16,6 +17,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
|
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
desktop_webview_window
|
desktop_webview_window
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
|
flutter_inappwebview_windows
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|||||||