Compare commits
97 Commits
main
...
unity_embe
| Author | SHA1 | Date | |
|---|---|---|---|
| c7105d6110 | |||
| e15bfc0bef | |||
| 442e56294f | |||
| 2b7778b152 | |||
| d9b5e53e18 | |||
| 740f137913 | |||
| 89dbf1a900 | |||
| 9899809c18 | |||
| 4040e8f91a | |||
| fe2d68e786 | |||
| f7ed9f5035 | |||
| 7cea1ea4c5 | |||
| 501d417b95 | |||
| db213c151c | |||
| 72aa4f9dfe | |||
| 7946df58d8 | |||
| c08aeb999c | |||
| 206f99b561 | |||
| e7945b1074 | |||
| dbafded5d2 | |||
| fe66f466a2 | |||
| 06fe0bdd7e | |||
| 00749179f6 | |||
| 15e85fc0dd | |||
| 52df106632 | |||
| da4f3f9243 | |||
| 5f8305289c | |||
| ecdad52570 | |||
| 1bd2a67868 | |||
| fa47208e4e | |||
| 41e0248b67 | |||
| b330c207b7 | |||
| 17e955e3a9 | |||
| ce76938284 | |||
| 316d1937b4 | |||
| 85a2655457 | |||
| d2d45ad685 | |||
| 86b1f67dda | |||
| 0e985f5453 | |||
| 2a4f8fc335 | |||
| efcfb609d5 | |||
| dba0e9d6cd | |||
| 93d15dd59f | |||
| 0a8ef32fe4 | |||
| 0b54a5126d | |||
| 927f805484 | |||
| 5230d7dcca | |||
| d05d5242db | |||
| aa2d7a0194 | |||
| 340a66bfb2 | |||
| 467470ce90 | |||
| 3f37619744 | |||
| f57088b04a | |||
| 278750083e | |||
| 854efa1986 | |||
| af92616ef7 | |||
| fa9c15f7c8 | |||
| ad3591b042 | |||
| c6bcf88caf | |||
| 4e19c82046 | |||
| 0e52ced016 | |||
| 3ffa70486e | |||
| e6b81acaf3 | |||
| 4fb5cbd567 | |||
| 8013646d0d | |||
| 66d72b9b1d | |||
| 17bfc6faee | |||
| 967cd86849 | |||
| 9ae836b2a1 | |||
| 8b55983dd6 | |||
| ffb4c5876c | |||
| ff68b8b145 | |||
| e15bba626d | |||
| 42642c2ef3 | |||
| 35860df873 | |||
| 47b3e2e15d | |||
| c4c6097828 | |||
| 1fdcc3773d | |||
| 2e489a97a4 | |||
| aa06f86854 | |||
| 13e99257b8 | |||
| 6dbb7f4ca9 | |||
| b0d343e6fc | |||
| bab3893f8a | |||
| e055ef5484 | |||
| 39514dc0f6 | |||
| 0564cab301 | |||
| b5943099ff | |||
| 929f2ce729 | |||
| 75210e29bc | |||
| cb1c0a8e05 | |||
| 0fb3e74cf7 | |||
| 26a3940365 | |||
| 724b6d47e3 | |||
| a858d66653 | |||
| 6348f74b95 | |||
| bf9a57f23b |
10
.gitignore
vendored
@ -43,4 +43,12 @@ app.*.map.json
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
pubspec.lock
|
||||
|
||||
# Place unity project here
|
||||
/unity
|
||||
|
||||
# flutter will place unity Library dependency here
|
||||
/unityLibrary
|
||||
|
||||
# unityLibrary will place build here
|
||||
/android/unityLibrary
|
||||
243
README.md
@ -1,16 +1,239 @@
|
||||
# furibase
|
||||
# Furikake App
|
||||
|
||||
A new Flutter project.
|
||||
Project ini adalah aplikasi mobile Furikake.
|
||||
|
||||
## Getting Started
|
||||
## Konfiguras dan perubahan android app
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
Edit android/app/src/main/kotlin ... /MainActivity.kt
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
```
|
||||
package com.paj.freekake
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity;
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
//class MainActivity : FlutterActivity()
|
||||
class MainActivity: FlutterFragmentActivity() {
|
||||
}
|
||||
```
|
||||
|
||||
Gunakan konfigurasi ini pada file android/settings.gradle.kts
|
||||
|
||||
```
|
||||
pluginManagement {
|
||||
val flutterSdkPath = run {
|
||||
val properties = java.util.Properties()
|
||||
file("local.properties").inputStream().use { properties.load(it) }
|
||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||
flutterSdkPath
|
||||
}
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.9.0" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
|
||||
include(":unityLibrary")
|
||||
project(":unityLibrary").projectDir = file("./unityLibrary")
|
||||
|
||||
include(":unityLibrary:xrmanifest.androidlib")
|
||||
//project(":unityLibrary:xrmanifest.androidlib").projectDir = file("unityLibrary/xrmanifest.androidlib")
|
||||
|
||||
//include(":unityLibrary:mobilenotifications.androidlib")
|
||||
//project(":unityLibrary:mobilenotifications.androidlib").projectDir = file("unityLibrary/mobilenotifications.androidlib")
|
||||
|
||||
```
|
||||
|
||||
Gunakan konfigurasi ini pada android/app/build.gradle.kts
|
||||
|
||||
```
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.paj.freekake"
|
||||
//compileSdk = flutter.compileSdkVersion
|
||||
compileSdk = 35
|
||||
//ndkVersion = "27.0.12077973"
|
||||
//ndkVersion = flutter.ndkVersion
|
||||
ndkVersion = "23.1.7779620"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "com.paj.freekake"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
//minSdk = flutter.minSdkVersion
|
||||
//targetSdk = flutter.targetSdkVersion
|
||||
//minSdk = 24 // Set to 24 or higher
|
||||
minSdk = 30
|
||||
targetSdk = 35
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":unityLibrary"))
|
||||
implementation(project(":flutter_unity_widget"))
|
||||
}
|
||||
```
|
||||
|
||||
## Konfigurasi UnityLibrary
|
||||
|
||||
Gunakan konfigurasi ini pada file android/unityLibrary/build.gradle:
|
||||
|
||||
```
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation(name: 'unity-classes', ext:'jar')
|
||||
implementation(name: 'arcore_client', ext:'aar')
|
||||
implementation(name: 'ARPresto', ext:'aar')
|
||||
implementation(name: 'UnityARCore', ext:'aar')
|
||||
implementation(name: 'unityandroidpermissions', ext:'aar')
|
||||
implementation project('xrmanifest.androidlib')
|
||||
//implementation project('mobilenotifications.androidlib')
|
||||
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "com.unity3d.player"
|
||||
// ndkPath "/Applications/Unity/Hub/Editor/2022.3.60f1/PlaybackEngines/AndroidPlayer/NDK"
|
||||
compileSdkVersion 35
|
||||
buildToolsVersion '34.0.0'
|
||||
ndkVersion "23.1.7779620"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 30
|
||||
targetSdkVersion 35
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a'
|
||||
}
|
||||
versionCode 1
|
||||
versionName '1.0.2'
|
||||
consumerProguardFiles 'proguard-unity.txt'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
noCompress = ['.unity3d', '.ress', '.resource', '.obb', '.bundle', '.unityexp']
|
||||
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
doNotStrip '*/armeabi-v7a/*.so'
|
||||
doNotStrip '*/arm64-v8a/*.so'
|
||||
jniLibs {
|
||||
useLegacyPackaging true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getSdkDir() {
|
||||
Properties local = new Properties()
|
||||
local.load(new FileInputStream("${rootDir}/local.properties"))
|
||||
return local.getProperty('sdk.dir')
|
||||
}
|
||||
|
||||
def BuildIl2Cpp(String workingDir, String configuration, String architecture, String abi, String[] staticLibraries) {
|
||||
def commandLineArgs = []
|
||||
commandLineArgs.add("--compile-cpp")
|
||||
commandLineArgs.add("--platform=Android")
|
||||
commandLineArgs.add("--architecture=" + architecture)
|
||||
commandLineArgs.add("--outputpath=" + workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.so")
|
||||
commandLineArgs.add("--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi)
|
||||
commandLineArgs.add("--incremental-g-c-time-slice=3")
|
||||
commandLineArgs.add("--dotnetprofile=unityaot-linux")
|
||||
commandLineArgs.add("--enable-debugger")
|
||||
commandLineArgs.add("--profiler-report")
|
||||
commandLineArgs.add("--profiler-output-file=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_conv.traceevents")
|
||||
commandLineArgs.add("--print-command-line")
|
||||
commandLineArgs.add("--data-folder=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput/data")
|
||||
commandLineArgs.add("--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput")
|
||||
commandLineArgs.add("--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache")
|
||||
commandLineArgs.add("--tool-chain-path=" + android.ndkDirectory)
|
||||
staticLibraries.eachWithIndex {fileName, i->
|
||||
commandLineArgs.add("--additional-libraries=" + workingDir + "/src/main/jniStaticLibs/" + abi + "/" + fileName)
|
||||
}
|
||||
def executableExtension = ""
|
||||
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
|
||||
executableExtension = ".exe"
|
||||
commandLineArgs = commandLineArgs*.replace('\"', '\\\"')
|
||||
}
|
||||
exec {
|
||||
executable workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/il2cpp" + executableExtension
|
||||
args commandLineArgs
|
||||
environment "ANDROID_SDK_ROOT", getSdkDir()
|
||||
}
|
||||
delete workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.sym.so"
|
||||
ant.move(file: workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so")
|
||||
}
|
||||
|
||||
android {
|
||||
task BuildIl2CppTask {
|
||||
doLast {
|
||||
BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), 'Debug', 'armv7', 'armeabi-v7a', [ ] as String[]);
|
||||
BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), 'Debug', 'arm64', 'arm64-v8a', [ ] as String[]);
|
||||
}
|
||||
}
|
||||
afterEvaluate {
|
||||
if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders'))
|
||||
project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask
|
||||
if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders'))
|
||||
project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jni.srcDirs = ["src/main/Il2CppOutputProject"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -6,29 +6,31 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.furibase"
|
||||
namespace = "com.paj.freekake"
|
||||
//compileSdk = flutter.compileSdkVersion
|
||||
compileSdk = 35
|
||||
ndkVersion = "27.0.12077973"
|
||||
//ndkVersion = "27.0.12077973"
|
||||
//ndkVersion = flutter.ndkVersion
|
||||
ndkVersion = "23.1.7779620"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "com.example.furibase"
|
||||
applicationId = "com.paj.freekake"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
//minSdk = flutter.minSdkVersion
|
||||
//targetSdk = flutter.targetSdkVersion
|
||||
minSdk = 24 // Set to 24 or higher
|
||||
//minSdk = 24 // Set to 24 or higher
|
||||
minSdk = 30
|
||||
targetSdk = 35
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
@ -50,3 +52,8 @@ android {
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":unityLibrary"))
|
||||
implementation(project(":flutter_unity_widget"))
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="furibase"
|
||||
android:label="freekake"
|
||||
android:name="${applicationName}"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
package com.example.furibase
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : FlutterActivity()
|
||||
@ -0,0 +1,8 @@
|
||||
package com.paj.freekake
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity;
|
||||
|
||||
//class MainActivity : FlutterActivity()
|
||||
class MainActivity: FlutterFragmentActivity() {
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true"/>
|
||||
</network-security-config>
|
||||
@ -1,5 +1,11 @@
|
||||
allprojects {
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs(
|
||||
file("${project(":unityLibrary").projectDir}/libs")
|
||||
)
|
||||
}
|
||||
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
@ -12,6 +18,39 @@ subprojects {
|
||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||
}
|
||||
|
||||
subprojects {
|
||||
afterEvaluate {
|
||||
if (project.extensions.findByName("android") != null) {
|
||||
extensions.configure<com.android.build.gradle.BaseExtension>("android") {
|
||||
if (namespace == null) {
|
||||
namespace = project.group.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (plugins.hasPlugin("com.android.application") || plugins.hasPlugin("com.android.library")) {
|
||||
if (name == "flutter_unity_widget") {
|
||||
extensions.configure<com.android.build.gradle.BaseExtension>("android") {
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
(this as ExtensionAware).extensions.configure<org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions>("kotlinOptions") {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
if (namespace == null) {
|
||||
namespace = project.group.toString()
|
||||
}
|
||||
|
||||
compileSdkVersion(35)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
# org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#Thu May 08 22:45:23 WIB 2025
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
|
||||
@ -18,8 +18,30 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.7.0" apply false
|
||||
id("com.android.application") version "8.9.0" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
|
||||
include(":unityLibrary")
|
||||
project(":unityLibrary").projectDir = file("./unityLibrary")
|
||||
|
||||
include(":unityLibrary:xrmanifest.androidlib")
|
||||
// project(":unityLibrary:xrmanifest.androidlib").projectDir = file("unityLibrary/xrmanifest.androidlib")
|
||||
|
||||
// include(":unityLibrary:mobilenotifications.androidlib")
|
||||
// project(":unityLibrary:mobilenotifications.androidlib").projectDir = file("unityLibrary/mobilenotifications.androidlib")
|
||||
|
||||
|
||||
|
||||
include(":unityLibrary")
|
||||
project(":unityLibrary").projectDir = file("./unityLibrary")
|
||||
|
||||
|
||||
include(":unityLibrary")
|
||||
project(":unityLibrary").projectDir = file("./unityLibrary")
|
||||
|
||||
|
||||
include(":unityLibrary")
|
||||
project(":unityLibrary").projectDir = file("./unityLibrary")
|
||||
|
||||
117
android/unityLibrary/build.gradle
Normal file
@ -0,0 +1,117 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation(name: 'unity-classes', ext:'jar')
|
||||
implementation(name: 'arcore_client', ext:'aar')
|
||||
implementation(name: 'ARPresto', ext:'aar')
|
||||
implementation(name: 'UnityARCore', ext:'aar')
|
||||
implementation(name: 'unityandroidpermissions', ext:'aar')
|
||||
implementation project('xrmanifest.androidlib')
|
||||
//implementation project('mobilenotifications.androidlib')
|
||||
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "com.unity3d.player"
|
||||
// ndkPath "/Applications/Unity/Hub/Editor/2022.3.60f1/PlaybackEngines/AndroidPlayer/NDK"
|
||||
compileSdkVersion 35
|
||||
buildToolsVersion '34.0.0'
|
||||
ndkVersion "23.1.7779620"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 30
|
||||
targetSdkVersion 35
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a'
|
||||
}
|
||||
versionCode 1
|
||||
versionName '1.0.2'
|
||||
consumerProguardFiles 'proguard-unity.txt'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
noCompress = ['.unity3d', '.ress', '.resource', '.obb', '.bundle', '.unityexp']
|
||||
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
doNotStrip '*/armeabi-v7a/*.so'
|
||||
doNotStrip '*/arm64-v8a/*.so'
|
||||
jniLibs {
|
||||
useLegacyPackaging true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getSdkDir() {
|
||||
Properties local = new Properties()
|
||||
local.load(new FileInputStream("${rootDir}/local.properties"))
|
||||
return local.getProperty('sdk.dir')
|
||||
}
|
||||
|
||||
def BuildIl2Cpp(String workingDir, String configuration, String architecture, String abi, String[] staticLibraries) {
|
||||
def commandLineArgs = []
|
||||
commandLineArgs.add("--compile-cpp")
|
||||
commandLineArgs.add("--platform=Android")
|
||||
commandLineArgs.add("--architecture=" + architecture)
|
||||
commandLineArgs.add("--outputpath=" + workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.so")
|
||||
commandLineArgs.add("--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi)
|
||||
commandLineArgs.add("--incremental-g-c-time-slice=3")
|
||||
commandLineArgs.add("--dotnetprofile=unityaot-linux")
|
||||
commandLineArgs.add("--enable-debugger")
|
||||
commandLineArgs.add("--profiler-report")
|
||||
commandLineArgs.add("--profiler-output-file=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_conv.traceevents")
|
||||
commandLineArgs.add("--print-command-line")
|
||||
commandLineArgs.add("--data-folder=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput/data")
|
||||
commandLineArgs.add("--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput")
|
||||
commandLineArgs.add("--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache")
|
||||
commandLineArgs.add("--tool-chain-path=" + android.ndkDirectory)
|
||||
staticLibraries.eachWithIndex {fileName, i->
|
||||
commandLineArgs.add("--additional-libraries=" + workingDir + "/src/main/jniStaticLibs/" + abi + "/" + fileName)
|
||||
}
|
||||
def executableExtension = ""
|
||||
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
|
||||
executableExtension = ".exe"
|
||||
commandLineArgs = commandLineArgs*.replace('\"', '\\\"')
|
||||
}
|
||||
exec {
|
||||
executable workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/il2cpp" + executableExtension
|
||||
args commandLineArgs
|
||||
environment "ANDROID_SDK_ROOT", getSdkDir()
|
||||
}
|
||||
delete workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.sym.so"
|
||||
ant.move(file: workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so")
|
||||
}
|
||||
|
||||
android {
|
||||
task BuildIl2CppTask {
|
||||
doLast {
|
||||
BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), 'Debug', 'armv7', 'armeabi-v7a', [ ] as String[]);
|
||||
BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), 'Debug', 'arm64', 'arm64-v8a', [ ] as String[]);
|
||||
}
|
||||
}
|
||||
afterEvaluate {
|
||||
if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders'))
|
||||
project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask
|
||||
if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders'))
|
||||
project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jni.srcDirs = ["src/main/Il2CppOutputProject"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,180 +0,0 @@
|
||||
<!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>
|
||||
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
@ -1,16 +0,0 @@
|
||||
<!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>
|
||||
|
Before Width: | Height: | Size: 41 KiB |
@ -224,19 +224,19 @@ figcaption {
|
||||
|
||||
<div class="div-grid">
|
||||
<div class="div-item">
|
||||
<img src="nori.jpeg" alt="Nori">
|
||||
<img src="assets/html/furikake/nori.jpeg" alt="Nori">
|
||||
<p>Nori (Rumput Laut)</p>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<img src="wijen.jpeg" alt="Biji Wijen">
|
||||
<img src="assets/html/furikake/wijen.jpeg" alt="Biji Wijen">
|
||||
<p>Biji Wijen</p>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<img src="ikankering.jpg" alt="Katsuobushi">
|
||||
<img src="assets/html/furikake/ikankering.jpg" alt="Katsuobushi">
|
||||
<p>Katsuobushi (Ikan Kering)</p>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<img src="gulagaram.jpg" alt="Garam dan Gula">
|
||||
<img src="assets/html/furikake/gulagaram.jpg" alt="Garam dan Gula">
|
||||
<p>Garam & Gula</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -259,7 +259,7 @@ figcaption {
|
||||
</ul>
|
||||
|
||||
<figure>
|
||||
<img src="furikake.jpg" alt="Contoh produk furikake" class="full-width-image">
|
||||
<img src="assets/html/furikake/furikake.jpg" alt="Contoh produk furikake" class="full-width-image">
|
||||
<figcaption>Berbagai varian produk furikake yang tersedia di pasaran</figcaption>
|
||||
</figure>
|
||||
</section>
|
||||
|
||||
@ -177,23 +177,23 @@
|
||||
|
||||
<div class="div-grid">
|
||||
<div class="div-item">
|
||||
<img src="karbohidrat.png" alt="Karbohidrat" />
|
||||
<img src="assets/html/karbohidrat.png" alt="Karbohidrat" />
|
||||
<p><strong>Karbohidrat</strong><br>Sumber energi seperti nasi, roti, dan kentang.</p>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<img src="protein.png" alt="Protein" />
|
||||
<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="div-item">
|
||||
<img src="lemak.png" alt="Lemak" />
|
||||
<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="div-item">
|
||||
<img src="vitaminmineral.png" alt="Vitamin dan Mineral" />
|
||||
<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="div-item">
|
||||
<img src="seratair.png" alt="Serat dan Air" />
|
||||
<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>
|
||||
@ -209,7 +209,7 @@
|
||||
<li>🍽️ Seperempat piring: Protein (seperti ayam atau tempe)</li>
|
||||
<li>🍽️ Sedikit lemak sehat</li>
|
||||
</ul>
|
||||
<img src="isipiringku.png" alt="Piring Gizi Seimbang" class="full-width-image">
|
||||
<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>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
@ -1,176 +0,0 @@
|
||||
<!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();
|
||||
});
|
||||
|
||||
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>
|
||||
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.6 MiB |
@ -1,5 +1,9 @@
|
||||
import 'package:freekake/components/navbar_shape_3.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freekake/components/navbar_container.dart';
|
||||
import 'package:freekake/components/navbar_shape_1.dart';
|
||||
import 'package:freekake/components/navbar_shape_2.dart';
|
||||
import 'package:freekake/components/navbar_shape_3.dart';
|
||||
import 'package:freekake/components/custom_shape.dart';
|
||||
|
||||
class BottomNavbar extends StatefulWidget {
|
||||
const BottomNavbar({super.key});
|
||||
|
||||
@ -53,6 +53,7 @@ class CardList extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 1, width: 5),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
@ -61,16 +62,16 @@ class CardList extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 1, width: 5),
|
||||
Text(
|
||||
body,
|
||||
style: const TextStyle(
|
||||
letterSpacing: 0.2,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
// Text(
|
||||
// body,
|
||||
// style: const TextStyle(
|
||||
// letterSpacing: 0.2,
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// ),
|
||||
// maxLines: 2,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(0.08),
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freekake/components/bottom_navbar.dart';
|
||||
import 'package:freekake/components/menu_button.dart';
|
||||
import 'package:freekake/providers/menu_selection_provider.dart';
|
||||
import 'package:freekake/components/scan_button.dart';
|
||||
import 'package:freekake/screen/Home_screen.dart';
|
||||
import 'package:freekake/screen/koleksi_screen.dart';
|
||||
import 'package:freekake/screen/pustaka_screen.dart';
|
||||
import 'package:freekake/screen/saya/profile_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MainMenu extends StatefulWidget {
|
||||
const MainMenu({super.key});
|
||||
|
||||
@ -28,8 +28,8 @@ class MenuButton extends StatelessWidget {
|
||||
IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
icon ?? '',
|
||||
width: w ?? 28,
|
||||
height: h ?? 28,
|
||||
width: w ?? 24,
|
||||
height: h ?? 24,
|
||||
// allowDrawingOutsideViewBox: true,
|
||||
colorFilter: ColorFilter.mode(
|
||||
(isSelected ?? false)
|
||||
@ -48,6 +48,7 @@ class MenuButton extends StatelessWidget {
|
||||
? Color.fromARGB(255, 216, 182, 10)
|
||||
: Color.fromARGB(255, 239, 224, 232),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:freekake/screen/camera_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
// import 'package:freekake/screen/camera_screen.dart';
|
||||
import 'package:freekake/screen/camera_screen.dart';
|
||||
|
||||
class ScanButton extends StatelessWidget {
|
||||
const ScanButton({super.key});
|
||||
|
||||
14
lib/helpers/image_picker_mobile.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'dart:io';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class ImagePickerHelper {
|
||||
Future<dynamic> pickImage() async {
|
||||
final ImagePicker picker = ImagePicker();
|
||||
final XFile? pickedFile = await picker.pickImage(source: ImageSource.gallery);
|
||||
|
||||
if (pickedFile != null) {
|
||||
File imageFile = File(pickedFile.path);
|
||||
return imageFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
5
lib/helpers/image_picker_stub.dart
Normal file
@ -0,0 +1,5 @@
|
||||
class ImagePickerHelper {
|
||||
Future<void> pickImage() async {
|
||||
throw UnsupportedError('pickImage is not supported on this platform');
|
||||
}
|
||||
}
|
||||
35
lib/helpers/image_picker_web.dart
Normal file
@ -0,0 +1,35 @@
|
||||
// import 'package:image_picker_web/image_picker_web.dart';
|
||||
// import 'dart:typed_data';
|
||||
|
||||
// class ImagePickerHelper {
|
||||
// Future<dynamic> pickImage() async {
|
||||
// Uint8List? bytesFromPicker = await ImagePickerWeb.getImageAsBytes();
|
||||
// if (bytesFromPicker != null) {
|
||||
// return bytesFromPicker;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
import 'dart:typed_data';
|
||||
import 'dart:html' as html;
|
||||
|
||||
class ImagePickerHelper {
|
||||
Future<void> pickImage() async {
|
||||
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
|
||||
uploadInput.accept = 'image/*';
|
||||
uploadInput.click();
|
||||
|
||||
uploadInput.onChange.listen((event) async {
|
||||
final file = uploadInput.files!.first;
|
||||
final reader = html.FileReader();
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
reader.onLoadEnd.listen((event) {
|
||||
Uint8List imageBytes = reader.result as Uint8List;
|
||||
if (imageBytes != null) {
|
||||
return imageBytes;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
3
lib/helpers/pick_image.dart
Normal file
@ -0,0 +1,3 @@
|
||||
export 'image_picker_stub.dart'
|
||||
if (dart.library.html) 'image_picker_web.dart'
|
||||
if (dart.library.io) 'image_picker_mobile.dart';
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:freekake/components/navbar_container.dart';
|
||||
import 'package:freekake/providers/character_provider.dart';
|
||||
import 'package:freekake/providers/menu_selection_provider.dart';
|
||||
import 'package:freekake/providers/point_provider.dart';
|
||||
@ -9,12 +9,12 @@ import 'package:provider/provider.dart';
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
// await SystemChrome.setPreferredOrientations([
|
||||
// DeviceOrientation.portraitUp,
|
||||
// DeviceOrientation.portraitDown, // bisa dihapus jika hanya ingin satu arah
|
||||
// ]);
|
||||
|
||||
runApp(const MyApp());
|
||||
}
|
||||
@ -32,7 +32,7 @@ class MyApp extends StatelessWidget {
|
||||
],
|
||||
child: MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'AR Character App',
|
||||
title: 'Freekake',
|
||||
theme: ThemeData.dark(),
|
||||
home:
|
||||
// DrawScreen(),
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
class Users {
|
||||
int id;
|
||||
// String nama;
|
||||
// String tgl;
|
||||
// String? alamat;
|
||||
|
||||
Users({
|
||||
required this.id,
|
||||
// required this.nama, this.alamat, required this.tgl
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"id": id,
|
||||
// "nama": nama, "alamat": this.alamat, "tgl": this.tgl
|
||||
};
|
||||
}
|
||||
|
||||
factory Users.fromJson(Map<String, dynamic> map) {
|
||||
return Users(
|
||||
id: map['id'],
|
||||
// nama: map['nama'],
|
||||
// alamat: map['alamat'],
|
||||
// tgl: map['tanggal'],
|
||||
);
|
||||
}
|
||||
|
||||
String toString() {
|
||||
return 'Users{id:$id,}';
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ import 'package:freekake/components/buildcard_info.dart';
|
||||
import 'package:freekake/components/main_menu.dart';
|
||||
import 'package:freekake/components/menu_item.dart';
|
||||
import 'package:freekake/components/scan_button.dart';
|
||||
import 'package:flutter_unity_widget/flutter_unity_widget.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
@ -16,6 +17,7 @@ class HomeScreen extends StatefulWidget {
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
final String username = "luffy01";
|
||||
// Image image
|
||||
late UnityWidgetController _unityWidgetController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -49,89 +51,98 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Positioned.fill(
|
||||
child: RepaintBoundary(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage("assets/images/background.jpeg"),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: UnityWidget(
|
||||
onUnityCreated: onUnityCreated,
|
||||
//isARScene: true,
|
||||
onUnityMessage: onUnityMessage,
|
||||
//onUnitySceneLoaded: onUnitySceneLoaded,
|
||||
fullscreen: false,
|
||||
),
|
||||
),
|
||||
// Positioned.fill(
|
||||
// child: RepaintBoundary(
|
||||
// child: Container(
|
||||
// decoration: const BoxDecoration(
|
||||
// image: DecorationImage(
|
||||
// image: AssetImage("assets/images/background.jpeg"),
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 100,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 20),
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(1),
|
||||
color: Color.fromARGB(1, 209, 174, 174).withAlpha(0),
|
||||
),
|
||||
child: Center(
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton2(
|
||||
customButton: Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/cepot-u.png'),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
openWithLongPress: false,
|
||||
items: [
|
||||
..._MenuItems.firstItems.map(
|
||||
(item) => DropdownMenuItem<MenuItem>(
|
||||
value: item,
|
||||
child: _MenuItems.buildItem(item),
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
_MenuItems.onChanged(context, value);
|
||||
} else {
|
||||
print("null");
|
||||
}
|
||||
},
|
||||
buttonStyleData: ButtonStyleData(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(40),
|
||||
),
|
||||
),
|
||||
dropdownStyleData: DropdownStyleData(
|
||||
width: 140,
|
||||
padding: EdgeInsets.zero,
|
||||
maxHeight: 150,
|
||||
// padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: Color.fromRGBO(2, 104, 17, 1).withAlpha(50),
|
||||
),
|
||||
offset: const Offset(40, -4),
|
||||
),
|
||||
menuItemStyleData: MenuItemStyleData(
|
||||
height: 35,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
),
|
||||
// menuItemStyleData: const MenuItemStyleData(
|
||||
// padding: EdgeInsets.only(left: 16, right: 16),
|
||||
// ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Positioned(
|
||||
// right: 0,
|
||||
// top: 100,
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.only(right: 20),
|
||||
// child: Container(
|
||||
// width: 40,
|
||||
// height: 40,
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(1),
|
||||
// color: Color.fromARGB(1, 209, 174, 174).withAlpha(0),
|
||||
// ),
|
||||
// child: Center(
|
||||
// child: DropdownButtonHideUnderline(
|
||||
// child: DropdownButton2(
|
||||
// customButton: Container(
|
||||
// height: 50,
|
||||
// width: 50,
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// image: const DecorationImage(
|
||||
// image: AssetImage('assets/images/cepot-u.png'),
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// openWithLongPress: false,
|
||||
// items: [
|
||||
// ..._MenuItems.firstItems.map(
|
||||
// (item) => DropdownMenuItem<MenuItem>(
|
||||
// value: item,
|
||||
// child: _MenuItems.buildItem(item),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// onChanged: (value) {
|
||||
// if (value != null) {
|
||||
// _MenuItems.onChanged(context, value);
|
||||
// } else {
|
||||
// print("null");
|
||||
// }
|
||||
// },
|
||||
// buttonStyleData: ButtonStyleData(
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(40),
|
||||
// ),
|
||||
// ),
|
||||
// dropdownStyleData: DropdownStyleData(
|
||||
// width: 140,
|
||||
// padding: EdgeInsets.zero,
|
||||
// maxHeight: 150,
|
||||
// // padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(4),
|
||||
// color: Color.fromRGBO(2, 104, 17, 1).withAlpha(50),
|
||||
// ),
|
||||
// offset: const Offset(40, -4),
|
||||
// ),
|
||||
// menuItemStyleData: MenuItemStyleData(
|
||||
// height: 35,
|
||||
// padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
// ),
|
||||
// // menuItemStyleData: const MenuItemStyleData(
|
||||
// // padding: EdgeInsets.only(left: 16, right: 16),
|
||||
// // ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
Positioned(
|
||||
top: 10,
|
||||
left: 10,
|
||||
@ -154,39 +165,39 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 150,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Color.fromARGB(255, 247, 224, 236),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color.fromARGB(255, 214, 213, 121),
|
||||
blurRadius: 5,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
// child: Text(
|
||||
// "Halo....Jotaslim",
|
||||
// style: TextStyle(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Color(0xFF000000),
|
||||
// ),
|
||||
// ),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
setHomeImage("assets/images/cepott.png", 300),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Positioned(
|
||||
// bottom: 150,
|
||||
// left: 0,
|
||||
// right: 0,
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Container(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Color.fromARGB(255, 247, 224, 236),
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// boxShadow: [
|
||||
// BoxShadow(
|
||||
// color: Color.fromARGB(255, 214, 213, 121),
|
||||
// blurRadius: 5,
|
||||
// spreadRadius: 2,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// child: Text(
|
||||
// "Halo....Jotaslim",
|
||||
// style: TextStyle(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Color(0xFF000000),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(height: 10),
|
||||
// //setHomeImage("assets/images/cepott.png", 300),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// BG MEnu
|
||||
Stack(
|
||||
children: [
|
||||
@ -218,6 +229,14 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
Widget setHomeImage(String src, double size) {
|
||||
return Image.asset(src, width: size);
|
||||
}
|
||||
|
||||
void onUnityCreated(controller) {
|
||||
_unityWidgetController = controller;
|
||||
}
|
||||
|
||||
void onUnityMessage(message) {
|
||||
print('Received message from unity: ${message.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
class _MenuItems {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freekake/components/collection_container.dart';
|
||||
import 'package:freekake/screen/collection/character_view.dart';
|
||||
|
||||
class CollectionCaraterScreen extends StatefulWidget {
|
||||
const CollectionCaraterScreen({super.key});
|
||||
@ -23,13 +22,7 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Favorite",
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text("Favorit", style: TextStyle(color: Colors.black)),
|
||||
Divider(height: 20, color: Colors.transparent),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
@ -55,13 +48,7 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
||||
charSex: "Laki-laki",
|
||||
charOrigin: "Jawa Barat",
|
||||
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.
|
||||
""",
|
||||
),
|
||||
),
|
||||
@ -83,13 +70,7 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
||||
),
|
||||
),
|
||||
Divider(height: 20, color: Colors.transparent),
|
||||
Text(
|
||||
"All",
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text("Semua", style: TextStyle(color: Colors.black)),
|
||||
Divider(height: 20, color: Colors.transparent),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
@ -125,20 +106,8 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
||||
charName: "Cepot",
|
||||
charSex: "Laki-laki",
|
||||
charOrigin: "Jawa Barat",
|
||||
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.
|
||||
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.
|
||||
""",
|
||||
),
|
||||
),
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freekake/components/collection_container.dart';
|
||||
import 'package:freekake/screen/collection/character_view.dart';
|
||||
import 'package:freekake/screen/collection/skin_view.dart';
|
||||
|
||||
class CollectionSkinScreen extends StatefulWidget {
|
||||
const CollectionSkinScreen({super.key});
|
||||
|
||||
@ -1,105 +0,0 @@
|
||||
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,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class ListDetailScreen extends StatefulWidget {
|
||||
final String title;
|
||||
@ -14,120 +13,89 @@ class ListDetailScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ListDetailScreenState extends State<ListDetailScreen> {
|
||||
late InAppWebViewController _webViewController;
|
||||
List<bool> checklist = [];
|
||||
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
|
||||
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(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(title: Text(widget.title)),
|
||||
body:
|
||||
widget.filepath != null
|
||||
? InAppWebView(
|
||||
initialUrlRequest: URLRequest(url: WebUri("about:blank")),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
javaScriptEnabled: true,
|
||||
allowFileAccessFromFileURLs: true,
|
||||
allowUniversalAccessFromFileURLs: true,
|
||||
),
|
||||
(fPath != null && fPath!.isNotEmpty)
|
||||
? WebViewWidget(controller: _controller)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Gambar di kiri atas dengan teks di kanan
|
||||
Row(
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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!;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onWebViewCreated: (controller) async {
|
||||
_webViewController = controller;
|
||||
|
||||
final html = await rootBundle.loadString(widget.filepath!);
|
||||
final base = widget.filepath!.substring(
|
||||
0,
|
||||
widget.filepath!.lastIndexOf('/') + 1,
|
||||
);
|
||||
await controller.loadData(
|
||||
data: html,
|
||||
baseUrl: WebUri(
|
||||
"file:///android_asset/flutter_assets/$base",
|
||||
), // agar path relatif seperti img1/* jalan
|
||||
mimeType: 'text/html',
|
||||
encoding: 'utf-8',
|
||||
);
|
||||
debugPrint("http://localhost/$base");
|
||||
debugPrint("file:///android_asset/flutter_assets/$base");
|
||||
},
|
||||
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")),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,21 +2,16 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:freekake/components/buildcard_info.dart';
|
||||
import 'package:freekake/components/card_list.dart';
|
||||
import 'package:freekake/components/collection_container%20copy.dart';
|
||||
import 'package:freekake/components/main_menu.dart';
|
||||
import 'package:freekake/components/topbar_container.dart';
|
||||
import 'package:freekake/screen/pustaka/pustaka_detail_screen.dart';
|
||||
import 'package:freekake/helpers/color_helper.dart';
|
||||
import 'package:freekake/models/users.dart';
|
||||
import 'package:freekake/screen/pustaka/list_detail_screen.dart';
|
||||
import 'package:freekake/util/api_client.dart';
|
||||
import 'package:list_detail_extension/list_detail_extension.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class ListEducation extends StatefulWidget {
|
||||
final String? selectedCategory;
|
||||
const ListEducation({super.key, this.selectedCategory});
|
||||
const ListEducation({super.key});
|
||||
|
||||
@override
|
||||
State<ListEducation> createState() => _ListEducationState();
|
||||
@ -27,14 +22,9 @@ class _ListEducationState extends State<ListEducation> {
|
||||
late final WebViewController _controller;
|
||||
late String urlOrAssetPath;
|
||||
bool _shouldShowWebView = false;
|
||||
String? selectedCategory;
|
||||
final listDetailExtension = ListDetailExtension();
|
||||
|
||||
// Data fetch
|
||||
final ApiClient _apiClient = ApiClient();
|
||||
List<Users> _posts = [];
|
||||
bool _isLoading = true;
|
||||
String _error = '';
|
||||
// load extension
|
||||
final listDetailExtension = ListDetailExtension();
|
||||
|
||||
Future<void> _initExtension() async {
|
||||
await listDetailExtension.load();
|
||||
@ -79,55 +69,18 @@ class _ListEducationState extends State<ListEducation> {
|
||||
""",
|
||||
"file": "assets/html/index.html",
|
||||
},
|
||||
{
|
||||
"title": "Memori Game",
|
||||
"image": "assets/html/freekake.png",
|
||||
"color": "#cef1da",
|
||||
"category": "Gizi",
|
||||
"type": "Materi",
|
||||
"point": "100",
|
||||
"coint": "20",
|
||||
"body":
|
||||
"""Game untuk melatih daya ingat siswa, sehingga bisa diharapkan bisa
|
||||
menemukan cara sendiri untuk mengingat sesuatu
|
||||
""",
|
||||
"file": "assets/html/memory/memory.html",
|
||||
},
|
||||
{
|
||||
"title": "Find Words",
|
||||
"image": "assets/html/freekake.png",
|
||||
"color": "#cef1da",
|
||||
"category": "Kesehatan",
|
||||
"type": "Materi",
|
||||
"point": "100",
|
||||
"coint": "20",
|
||||
"body": """
|
||||
No Descripptions
|
||||
""",
|
||||
"file": "assets/html/findwords/findwords.html",
|
||||
},
|
||||
];
|
||||
List<Map<String, dynamic>> filteredItems = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
selectedCategory = widget.selectedCategory;
|
||||
print(selectedCategory);
|
||||
if (selectedCategory != null && selectedCategory!.isNotEmpty) {
|
||||
filteredItems =
|
||||
_listContent
|
||||
.where((item) => item["category"] == selectedCategory)
|
||||
.toList();
|
||||
} else {
|
||||
filteredItems = List.from(_listContent);
|
||||
}
|
||||
filteredItems = List.from(_listContent);
|
||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||
_shouldShowWebView = true;
|
||||
_controller =
|
||||
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||
urlOrAssetPath = "assets/html/index.html";
|
||||
urlOrAssetPath = "assets/makanan_bergizi/index.html";
|
||||
_loadContent(urlOrAssetPath);
|
||||
_initExtension();
|
||||
}
|
||||
@ -139,20 +92,18 @@ class _ListEducationState extends State<ListEducation> {
|
||||
// Load dari Internet
|
||||
_controller.loadRequest(Uri.parse(path));
|
||||
} else {
|
||||
try {
|
||||
await rootBundle.load(path);
|
||||
await _controller.loadFlutterAsset(path);
|
||||
} catch (e) {
|
||||
print("Gagal memuat file HTML: $path\nError: $e");
|
||||
}
|
||||
_controller.loadFlutterAsset(path);
|
||||
// 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) {
|
||||
setState(() {
|
||||
selectedCategory = null;
|
||||
if (query.isEmpty) {
|
||||
filteredItems = List.from(_listContent);
|
||||
} else {
|
||||
@ -166,7 +117,6 @@ class _ListEducationState extends State<ListEducation> {
|
||||
|
||||
void filterByCategory(String category) {
|
||||
setState(() {
|
||||
selectedCategory = category;
|
||||
filteredItems =
|
||||
_listContent.where((item) {
|
||||
return item["category"].toLowerCase() == category.toLowerCase();
|
||||
@ -174,43 +124,9 @@ class _ListEducationState extends State<ListEducation> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _fetchPosts() async {
|
||||
try {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_error = '';
|
||||
});
|
||||
|
||||
// Melakukan permintaan GET ke endpoint
|
||||
final Response response = await _apiClient.dio.get('auth/users');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Konversi data JSON ke List
|
||||
List<dynamic> postJson = response.data;
|
||||
_posts = postJson.map((json) => Users.fromJson(json)).toList();
|
||||
} else {
|
||||
_error = 'Gagal memuat data: ${response.statusCode}';
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
if (e.response != null) {
|
||||
_error =
|
||||
'Server Error: ${e.response?.statusCode} - ${e.response?.statusMessage}';
|
||||
} else {
|
||||
_error = 'Network Error: ${e.message}';
|
||||
}
|
||||
print('DioError: $e');
|
||||
} catch (e) {
|
||||
_error = 'Terjadi kesalahan tidak terduga: $e';
|
||||
print('General Error: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String searchQuery = "";
|
||||
final List<Map<String, dynamic>> collections = [
|
||||
{
|
||||
"label": "Kesehatan",
|
||||
@ -242,8 +158,7 @@ class _ListEducationState extends State<ListEducation> {
|
||||
collections
|
||||
.where(
|
||||
(item) => item["label"].toLowerCase().contains(
|
||||
// searchQuery.toLowerCase(),
|
||||
searchController.text.toLowerCase(),
|
||||
searchQuery.toLowerCase(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
@ -261,7 +176,7 @@ class _ListEducationState extends State<ListEducation> {
|
||||
body: Column(
|
||||
children: [
|
||||
// Header Section
|
||||
headerContainer(context, collections),
|
||||
headerContainer(context, filteredCollections),
|
||||
// Collection Items dengan Filter
|
||||
SizedBox(height: 20),
|
||||
Expanded(child: contentContainer(context)),
|
||||
@ -340,7 +255,6 @@ class _ListEducationState extends State<ListEducation> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children:
|
||||
filteredCollections.map((item) {
|
||||
final isSelected = selectedCategory == item["category"];
|
||||
return CollectionContainer(
|
||||
label: item["label"]!,
|
||||
imageSvg: item["image"]!,
|
||||
@ -348,16 +262,9 @@ class _ListEducationState extends State<ListEducation> {
|
||||
iconh: 20,
|
||||
width: 70,
|
||||
height: 70,
|
||||
textColor:
|
||||
isSelected
|
||||
? const Color.fromARGB(255, 230, 48, 160)
|
||||
: Colors.black,
|
||||
lblSize: 10,
|
||||
// colorContiner: ColorHelper.hexToColor(item["color"]),
|
||||
colorContiner:
|
||||
isSelected
|
||||
? const Color.fromARGB(255, 84, 3, 224)
|
||||
: ColorHelper.hexToColor(item["color"]),
|
||||
textColor: Colors.black,
|
||||
lblSize: 8,
|
||||
colorContiner: ColorHelper.hexToColor(item["color"]),
|
||||
onTapAc:
|
||||
() => {
|
||||
searchController.clear(),
|
||||
@ -440,41 +347,36 @@ class _ListEducationState extends State<ListEducation> {
|
||||
GridView _generateList() {
|
||||
return GridView.builder(
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 1,
|
||||
crossAxisCount: 1, // 2 Kolom
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisSpacing: 10,
|
||||
childAspectRatio: 2.5,
|
||||
),
|
||||
itemCount: filteredItems.length,
|
||||
itemCount: _listContent.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
child: CardList(
|
||||
title: filteredItems[index]["title"] ?? "",
|
||||
body: filteredItems[index]["body"] ?? "",
|
||||
gambar: filteredItems[index]['image'],
|
||||
point: filteredItems[index]['point'],
|
||||
coint: filteredItems[index]['coint'],
|
||||
tipe: filteredItems[index]['type'],
|
||||
title: _listContent[index]["title"] ?? "",
|
||||
body: _listContent[index]["body"] ?? "",
|
||||
gambar: _listContent[index]['image'],
|
||||
point: _listContent[index]['coint'],
|
||||
coint: _listContent[index]['point'],
|
||||
tipe: _listContent[index]['tipe'],
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
// (context) => listDetailExtension.buildPage({
|
||||
// 'title': filteredItems[index]['category'],
|
||||
// 'imagePath': filteredItems[index]['image'],
|
||||
// 'filepath': filteredItems[index]['file'],
|
||||
// 'paragraphs':
|
||||
// """
|
||||
// """
|
||||
// "<h1> ${filteredItems[index]["title"]} </h1> <p> ${filteredItems[index]["body"]}",
|
||||
// }),
|
||||
(context) => ListDetailScreen(
|
||||
title: filteredItems[index]['category'],
|
||||
// 'imagePath': filteredItems[index]['image'],
|
||||
filepath: filteredItems[index]['file'],
|
||||
),
|
||||
(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"]}",
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@ -74,11 +74,106 @@ 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),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
|
||||
child: htmlBody(),
|
||||
child:
|
||||
// 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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -108,7 +108,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
children: [
|
||||
CollectionContainer(
|
||||
label: "Luffy",
|
||||
imagesrc: 'images/luffy.png',
|
||||
imagesrc: 'assets/images/luffy.png',
|
||||
width: 100,
|
||||
height: 100,
|
||||
onTapAc:
|
||||
|
||||
@ -108,7 +108,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
children: [
|
||||
CollectionContainer(
|
||||
label: "Luffy",
|
||||
imagesrc: 'images/luffy.png',
|
||||
imagesrc: 'assets/images/luffy.png',
|
||||
width: 100,
|
||||
height: 100,
|
||||
onTapAc:
|
||||
|
||||
@ -44,32 +44,6 @@ 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) {
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
@ -86,23 +60,14 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final buttonScanSize = screenWidth * 0.20;
|
||||
final double bottomPadding = (9000 / screenWidth).clamp(0, 0.2);
|
||||
|
||||
List<Map<String, dynamic>> filterCollections(
|
||||
List<Map<String, dynamic>> collections,
|
||||
String query,
|
||||
) {
|
||||
return collections
|
||||
.where(
|
||||
(item) =>
|
||||
item["label"]!.toLowerCase().contains(query.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> filteredCollections = filterCollections(
|
||||
_collections,
|
||||
_searchQuery,
|
||||
);
|
||||
List<Map<String, dynamic>> filteredCollections =
|
||||
_collections
|
||||
.where(
|
||||
(item) => item["label"]!.toLowerCase().contains(
|
||||
_searchQuery.toLowerCase(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
||||
@ -156,6 +121,16 @@ 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
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||
@ -223,10 +198,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(_) => ListEducation(
|
||||
selectedCategory: item["label"],
|
||||
),
|
||||
builder: (_) => const ListEducation(),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -259,61 +231,61 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children:
|
||||
_genres.map((genre) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
elevation: 5,
|
||||
color: ColorHelper.hexToColor("#efd8c6"),
|
||||
// color: const Color.fromARGB(140, 255, 255, 255),
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(15),
|
||||
// ),
|
||||
child: GestureDetector(
|
||||
onTap:
|
||||
() => {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEducation(),
|
||||
),
|
||||
),
|
||||
},
|
||||
child: Container(
|
||||
width: 80,
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.book,
|
||||
size: 50,
|
||||
color: Colors.blueAccent,
|
||||
),
|
||||
Text(
|
||||
genre['label'],
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color.fromARGB(255, 0, 0, 0),
|
||||
),
|
||||
),
|
||||
],
|
||||
children: List.generate(
|
||||
10,
|
||||
(index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
elevation: 5,
|
||||
color: ColorHelper.hexToColor("#efd8c6"),
|
||||
// color: const Color.fromARGB(140, 255, 255, 255),
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(15),
|
||||
// ),
|
||||
child: GestureDetector(
|
||||
onTap:
|
||||
() => {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ListEducation(),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
child: Container(
|
||||
width: 80,
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.book,
|
||||
size: 50,
|
||||
color: Colors.blueAccent,
|
||||
),
|
||||
Text(
|
||||
'Topic ${index + 1}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color.fromARGB(255, 0, 0, 0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Bottom Navigation
|
||||
// MainMenu(),
|
||||
],
|
||||
),
|
||||
// BG MEnu
|
||||
@ -328,17 +300,13 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
||||
Positioned(bottom: 0, left: 0, right: 0, child: MainMenu()),
|
||||
],
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
bottom: bottomPadding * 98,
|
||||
left: (screenWidth - buttonScanSize) / 2,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, -20),
|
||||
child: ScanButton(),
|
||||
),
|
||||
),
|
||||
],
|
||||
Positioned(
|
||||
bottom: bottomPadding * 98,
|
||||
left: (screenWidth - buttonScanSize) / 2,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, -20),
|
||||
child: ScanButton(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
211
lib/screen/saya/akun_saya copy.dart
Normal file
@ -0,0 +1,211 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freekake/components/bottom_navbar.dart';
|
||||
import 'package:freekake/components/main_menu.dart';
|
||||
import 'package:freekake/components/scan_button.dart';
|
||||
import 'package:freekake/helpers/pick_image.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
class AkunSaya extends StatefulWidget {
|
||||
@override
|
||||
_AkunSayaState createState() => _AkunSayaState();
|
||||
}
|
||||
|
||||
class _AkunSayaState extends State<AkunSaya> {
|
||||
dynamic _profileImage;
|
||||
dynamic _headerImage;
|
||||
//final ImagePicker _picker = ImagePicker();
|
||||
|
||||
Future<void> _pickImage(bool isProfile) async {
|
||||
final imagePicker = ImagePickerHelper();
|
||||
dynamic pic = await imagePicker.pickImage();
|
||||
|
||||
if (pic != null) {
|
||||
setState(() {
|
||||
if (isProfile) {
|
||||
_profileImage = pic;
|
||||
} else {
|
||||
_headerImage = pic;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Saya"),
|
||||
backgroundColor: Color.fromARGB(225, 79, 76, 182),
|
||||
),
|
||||
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
||||
body: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0, left: 20, right: 20),
|
||||
child: Container(
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color.fromARGB(255, 205, 202, 189),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
// Header image (bisa diubah)
|
||||
SizedBox(
|
||||
height: 80,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(40),
|
||||
bottomRight: Radius.circular(40),
|
||||
),
|
||||
color: Color.fromARGB(225, 79, 76, 182),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 40),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: ListView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 40),
|
||||
children: [
|
||||
TextFormField(
|
||||
initialValue: "Cepot",
|
||||
decoration: const InputDecoration(
|
||||
border: UnderlineInputBorder(),
|
||||
labelText: 'Nama',
|
||||
labelStyle: TextStyle(color: Colors.black),
|
||||
),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
TextFormField(
|
||||
initialValue: "cpt09",
|
||||
decoration: const InputDecoration(
|
||||
border: UnderlineInputBorder(),
|
||||
labelText: 'Nama Pengguna',
|
||||
labelStyle: TextStyle(color: Colors.black),
|
||||
),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
initialValue: "Jl. Sentosa jaya",
|
||||
decoration: const InputDecoration(
|
||||
border: UnderlineInputBorder(),
|
||||
labelText: 'Alamat',
|
||||
labelStyle: TextStyle(color: Colors.black),
|
||||
),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
|
||||
TextFormField(
|
||||
initialValue: "******",
|
||||
decoration: const InputDecoration(
|
||||
border: UnderlineInputBorder(),
|
||||
labelText: 'Kata Sandi',
|
||||
labelStyle: TextStyle(color: Colors.black),
|
||||
),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
TextFormField(
|
||||
initialValue: "+62923",
|
||||
decoration: const InputDecoration(
|
||||
border: UnderlineInputBorder(),
|
||||
labelText: 'No. HP',
|
||||
labelStyle: TextStyle(color: Colors.black),
|
||||
),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Profile Picture (bisa diubah)
|
||||
Positioned(
|
||||
top: 25,
|
||||
left: MediaQuery.of(context).size.width / 2 - 50,
|
||||
child: GestureDetector(
|
||||
onTap: () => _pickImage(true),
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 50,
|
||||
backgroundColor: Colors.grey[300],
|
||||
backgroundImage:
|
||||
_profileImage != null
|
||||
? (kIsWeb
|
||||
? MemoryImage(_profileImage) as ImageProvider
|
||||
: FileImage(_profileImage) as ImageProvider)
|
||||
: null,
|
||||
child:
|
||||
_profileImage == null
|
||||
? Icon(Icons.person, size: 50, color: Colors.white)
|
||||
: null,
|
||||
),
|
||||
CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundColor: Colors.blue,
|
||||
child: Icon(Icons.edit, color: Colors.white, size: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Positioned(
|
||||
top: 130,
|
||||
left: MediaQuery.of(context).size.width / 2 - 50,
|
||||
child: GestureDetector(
|
||||
onTap: () => _pickImage(true),
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: [
|
||||
Text(
|
||||
"Nama Akun",
|
||||
style: TextStyle(
|
||||
color: Colors.deepPurple,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListItem(IconData icon, String label, {bool isLogout = false}) {
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
icon,
|
||||
color:
|
||||
isLogout
|
||||
? const Color.fromARGB(255, 181, 47, 47)
|
||||
: const Color.fromARGB(255, 255, 255, 255),
|
||||
),
|
||||
title: Text(label, style: TextStyle(fontSize: 16, color: Colors.black)),
|
||||
trailing: Icon(Icons.arrow_forward_ios, size: 16),
|
||||
onTap: () {},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,6 @@ import 'package:freekake/components/scan_button.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'dart:io';
|
||||
|
||||
// import 'package:image_picker_web/image_picker_web.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
class AkunSaya extends StatefulWidget {
|
||||
|
||||
@ -12,7 +12,6 @@ import 'package:freekake/screen/saya/point_saya.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'dart:io';
|
||||
|
||||
// import 'package:image_picker_web/image_picker_web.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
class ProfileScreen extends StatefulWidget {
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class ApiClient {
|
||||
final Dio _dio = Dio();
|
||||
final String _baseUrl = 'https://api.freekake.com/';
|
||||
|
||||
ApiClient() {
|
||||
_dio.options.baseUrl = _baseUrl;
|
||||
_dio.options.connectTimeout = const Duration(seconds: 5);
|
||||
_dio.options.receiveTimeout = const Duration(seconds: 3);
|
||||
|
||||
_dio.interceptors.add(
|
||||
InterceptorsWrapper(
|
||||
onRequest: (options, handler) {
|
||||
print('REQUEST[${options.method}] => PATH: ${options.path}');
|
||||
// options.headers['Authorization'] = 'Bearer your_token_here';
|
||||
return handler.next(options);
|
||||
},
|
||||
onResponse: (response, handler) {
|
||||
print(
|
||||
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}',
|
||||
);
|
||||
return handler.next(response);
|
||||
},
|
||||
onError: (DioException e, handler) {
|
||||
print(
|
||||
'ERROR[${e.response?.statusCode}] => PATH: ${e.requestOptions.path}',
|
||||
);
|
||||
return handler.next(e);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Dio get dio => _dio;
|
||||
}
|
||||
@ -7,7 +7,6 @@ import Foundation
|
||||
|
||||
import desktop_webview_window
|
||||
import file_selector_macos
|
||||
import flutter_inappwebview_macos
|
||||
import shared_preferences_foundation
|
||||
import url_launcher_macos
|
||||
import webview_flutter_wkwebview
|
||||
@ -15,7 +14,6 @@ import webview_flutter_wkwebview
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||
|
||||
107
pubspec.lock
@ -129,22 +129,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.3"
|
||||
dio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.8.0+1"
|
||||
dio_web_adapter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dio_web_adapter
|
||||
sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
dropdown_button2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -222,70 +206,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -315,6 +235,15 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_unity_widget:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "flutter_3.24_android_hotfix"
|
||||
resolved-ref: d2f6dc853d5b5054668ea9d79bb138d2d072696c
|
||||
url: "https://github.com/juicycleff/flutter-unity-view-widget.git"
|
||||
source: git
|
||||
version: "2022.2.1"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -893,7 +822,23 @@ packages:
|
||||
sha256: "18b1640839cf6546784a524c72aded5b6e86b23e7167dc2311cc96f7658b64bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
version: "2.10.0"
|
||||
webview_flutter_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_web
|
||||
sha256: "18a7ccc1c31dd9a5c759a1b7217a2a1e04bd8f65712714a4070bfac19a23ca9e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.3+4"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_web
|
||||
sha256: "18a7ccc1c31dd9a5c759a1b7217a2a1e04bd8f65712714a4070bfac19a23ca9e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.3+4"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
55
pubspec.yaml
@ -54,13 +54,16 @@ dependencies:
|
||||
url: https://github.com/fhauze/list_detail_screen.git
|
||||
ref: main
|
||||
desktop_webview_window: ^0.2.3
|
||||
flutter_inappwebview: ^6.0.0
|
||||
dio: ^5.0.0
|
||||
# arcore_flutter_plugin: ^0.2.0-alpha
|
||||
# flutter_unity_widget: ^2022.2.1
|
||||
# arcore_flutter_plugin:
|
||||
# git:
|
||||
# url: https://github.com/giandifra/arcore_flutter_plugin.git
|
||||
# flutter_unity_widget: ^2022.2.1
|
||||
flutter_unity_widget:
|
||||
git:
|
||||
url: https://github.com/juicycleff/flutter-unity-view-widget.git
|
||||
ref: flutter_3.24_android_hotfix
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -87,57 +90,13 @@ flutter:
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/images/
|
||||
- assets/images/Artboard 15@4x.png
|
||||
- assets/images/Artboard 16@4x.png
|
||||
- assets/images/background.jpeg
|
||||
- assets/images/cepott.png
|
||||
- assets/images/ft_cepot.png
|
||||
- assets/images/ft_luffy.png
|
||||
- assets/images/klipartz.png
|
||||
- assets/images/luffy-kimono.png
|
||||
- assets/images/luffy-king.png
|
||||
- assets/images/luffy-u.png
|
||||
- assets/images/luffy.gif
|
||||
- assets/images/luffy.png
|
||||
|
||||
# SVG files
|
||||
- assets/icons/E-furrybuddy.svg
|
||||
- assets/icons/E-furrybuddy1.svg
|
||||
- assets/icons/Education.svg
|
||||
- assets/icons/furrybuddy.svg
|
||||
- assets/icons/healthy.svg
|
||||
- assets/icons/Koleksi.svg
|
||||
- assets/icons/Nutrition.svg
|
||||
- assets/icons/Pustaka.svg
|
||||
- assets/icons/Safety.svg
|
||||
- assets/icons/Saya.svg
|
||||
- assets/icons/Scan.svg
|
||||
- assets/icons/
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
# https://flutter.dev/to/resolution-aware-images
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.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 <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
@ -17,8 +16,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
file_selector_windows
|
||||
flutter_inappwebview_windows
|
||||
permission_handler_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||