Compare commits
2 Commits
unity_embe
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bff9c7fc2 | ||
|
|
a211b0675d |
10
.gitignore
vendored
@ -43,12 +43,4 @@ app.*.map.json
|
|||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/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,239 +1,16 @@
|
|||||||
# Furikake App
|
# furibase
|
||||||
|
|
||||||
Project ini adalah aplikasi mobile Furikake.
|
A new Flutter project.
|
||||||
|
|
||||||
## Konfiguras dan perubahan android app
|
## Getting Started
|
||||||
|
|
||||||
Edit android/app/src/main/kotlin ... /MainActivity.kt
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
```
|
A few resources to get you started if this is your first Flutter project:
|
||||||
package com.paj.freekake
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
import io.flutter.embedding.android.FlutterFragmentActivity;
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
//class MainActivity : FlutterActivity()
|
For help getting started with Flutter development, view the
|
||||||
class MainActivity: FlutterFragmentActivity() {
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
}
|
samples, guidance on mobile development, and a full API reference.
|
||||||
```
|
|
||||||
|
|
||||||
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,31 +6,29 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.paj.freekake"
|
namespace = "com.example.furibase"
|
||||||
//compileSdk = flutter.compileSdkVersion
|
//compileSdk = flutter.compileSdkVersion
|
||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
//ndkVersion = "27.0.12077973"
|
ndkVersion = "27.0.12077973"
|
||||||
//ndkVersion = flutter.ndkVersion
|
//ndkVersion = flutter.ndkVersion
|
||||||
ndkVersion = "23.1.7779620"
|
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId = "com.paj.freekake"
|
applicationId = "com.example.furibase"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
//minSdk = flutter.minSdkVersion
|
//minSdk = flutter.minSdkVersion
|
||||||
//targetSdk = flutter.targetSdkVersion
|
//targetSdk = flutter.targetSdkVersion
|
||||||
//minSdk = 24 // Set to 24 or higher
|
minSdk = 24 // Set to 24 or higher
|
||||||
minSdk = 30
|
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
@ -52,8 +50,3 @@ android {
|
|||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(project(":unityLibrary"))
|
|
||||||
implementation(project(":flutter_unity_widget"))
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<application
|
<application
|
||||||
android:label="freekake"
|
android:label="furibase"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.furibase
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity : FlutterActivity()
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package com.paj.freekake
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
|
||||||
import io.flutter.embedding.android.FlutterFragmentActivity;
|
|
||||||
|
|
||||||
//class MainActivity : FlutterActivity()
|
|
||||||
class MainActivity: FlutterFragmentActivity() {
|
|
||||||
}
|
|
||||||
4
android/app/src/main/res/xml/network_security_config.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<base-config cleartextTrafficPermitted="true"/>
|
||||||
|
</network-security-config>
|
||||||
@ -1,11 +1,5 @@
|
|||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
flatDir {
|
|
||||||
dirs(
|
|
||||||
file("${project(":unityLibrary").projectDir}/libs")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@ -18,39 +12,6 @@ subprojects {
|
|||||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
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 {
|
subprojects {
|
||||||
project.evaluationDependsOn(":app")
|
project.evaluationDependsOn(":app")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
# 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.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#Thu May 08 22:45:23 WIB 2025
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||||
|
|||||||
@ -18,30 +18,8 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "8.9.0" apply false
|
id("com.android.application") version "8.7.0" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
include(":app")
|
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")
|
|
||||||
|
|||||||
@ -1,117 +0,0 @@
|
|||||||
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"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
180
assets/html/findwords/findwords.html
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Game Nusantara</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
background: #f2f2f2;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 480px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 4px;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
.letter {
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
}
|
||||||
|
.found {
|
||||||
|
background-color: #a2f5a2 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 id="game-title">Game Nusantara</h1>
|
||||||
|
<div id="game-board"></div>
|
||||||
|
|
||||||
|
<h3>Kata yang harus ditemukan:</h3>
|
||||||
|
<ul id="target-words" style="padding-left: 1rem;"></ul>
|
||||||
|
<p id="penjelasan" style="margin-top: 1rem; font-size: 0.9rem; color: #444;"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Template Find The Word Game (drag to select)
|
||||||
|
const words = ['TENANG', 'SABAR', 'SYUKUR', 'CINTA', 'GEMBIRA', 'BANGGA'];
|
||||||
|
const board = document.getElementById('game-board');
|
||||||
|
const size = 12; // 12x12 grid
|
||||||
|
let grid = Array(size * size).fill('');
|
||||||
|
|
||||||
|
function randomLetter() {
|
||||||
|
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
return alphabet[Math.floor(Math.random() * alphabet.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeWord(word) {
|
||||||
|
const dir = Math.random() < 0.5 ? 'H' : 'V';
|
||||||
|
let x, y, success = false;
|
||||||
|
while (!success) {
|
||||||
|
x = Math.floor(Math.random() * (dir === 'H' ? size - word.length : size));
|
||||||
|
y = Math.floor(Math.random() * (dir === 'V' ? size - word.length : size));
|
||||||
|
let fits = true;
|
||||||
|
for (let i = 0; i < word.length; i++) {
|
||||||
|
let idx = dir === 'H' ? y * size + (x + i) : (y + i) * size + x;
|
||||||
|
if (grid[idx] && grid[idx] !== word[i]) {
|
||||||
|
fits = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fits) {
|
||||||
|
for (let i = 0; i < word.length; i++) {
|
||||||
|
let idx = dir === 'H' ? y * size + (x + i) : (y + i) * size + x;
|
||||||
|
grid[idx] = word[i];
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
words.forEach(w => placeWord(w));
|
||||||
|
grid = grid.map(cell => cell || randomLetter());
|
||||||
|
|
||||||
|
function renderGrid() {
|
||||||
|
board.className = 'grid';
|
||||||
|
board.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
|
||||||
|
board.innerHTML = '';
|
||||||
|
grid.forEach((char, i) => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = char;
|
||||||
|
div.className = 'letter';
|
||||||
|
div.dataset.index = i;
|
||||||
|
div.style.aspectRatio = '1/1';
|
||||||
|
div.style.border = '1px solid #ccc';
|
||||||
|
div.style.display = 'flex';
|
||||||
|
div.style.alignItems = 'center';
|
||||||
|
div.style.justifyContent = 'center';
|
||||||
|
div.style.fontSize = '1.2rem';
|
||||||
|
div.style.fontWeight = 'bold';
|
||||||
|
div.style.userSelect = 'none';
|
||||||
|
div.style.cursor = 'pointer';
|
||||||
|
board.appendChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGrid();
|
||||||
|
|
||||||
|
// Daftar kata yang harus ditemukan
|
||||||
|
// (Daftar kata tidak lagi ditampilkan sebagai list)
|
||||||
|
|
||||||
|
let currentSelection = [];
|
||||||
|
let currentWord = '';
|
||||||
|
let wordsFound = new Set();
|
||||||
|
let isMouseDown = false;
|
||||||
|
|
||||||
|
board.addEventListener('mousedown', (e) => {
|
||||||
|
if (!e.target.classList.contains('letter')) return;
|
||||||
|
isMouseDown = true;
|
||||||
|
selectCell(e.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
board.addEventListener('mouseover', (e) => {
|
||||||
|
if (!isMouseDown || !e.target.classList.contains('letter')) return;
|
||||||
|
selectCell(e.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', () => {
|
||||||
|
if (words.includes(currentWord)) {
|
||||||
|
currentSelection.forEach(c => {
|
||||||
|
c.style.backgroundColor = '#a2f5a2';
|
||||||
|
c.classList.add('found');
|
||||||
|
});
|
||||||
|
const penjelasanBox = document.getElementById('penjelasan');
|
||||||
|
const regex = new RegExp(currentWord, 'gi');
|
||||||
|
penjelasanBox.innerHTML = penjelasanBox.innerHTML.replace(regex, `<span style="color:green; font-weight:bold">${currentWord}</span>`);
|
||||||
|
|
||||||
|
wordsFound.add(currentWord);
|
||||||
|
if (wordsFound.size === words.length) {
|
||||||
|
alert('Selamat! Kamu telah menemukan semua kata positif. Ingat, berpikir positif setiap hari bisa membuat hidupmu lebih ceria dan penuh semangat 🌈');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentSelection.forEach(c => c.style.backgroundColor = '');
|
||||||
|
}
|
||||||
|
currentSelection = [];
|
||||||
|
currentWord = '';
|
||||||
|
isMouseDown = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function selectCell(cell) {
|
||||||
|
if (cell.classList.contains('found') || currentSelection.includes(cell)) return;
|
||||||
|
cell.style.backgroundColor = '#ffeaa7';
|
||||||
|
currentSelection.push(cell);
|
||||||
|
currentWord += cell.textContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Penjelasan pentingnya emosi positif
|
||||||
|
const penjelasan = `Di dalam hidup, kita bisa merasa banyak hal. Tapi tahukah kamu? Emosi positif seperti <strong>tenang</strong>, <strong>sabar</strong>, <strong>syukur</strong>, <strong>cinta</strong>, <strong>gembira</strong>, dan <strong>bangga</strong> adalah kunci untuk hidup yang sehat dan bahagia. Yuk, temukan kata-kata positif itu di puzzle, lalu pikirkan kapan terakhir kali kamu merasakannya!`;
|
||||||
|
document.getElementById('penjelasan').innerHTML = penjelasan;
|
||||||
|
|
||||||
|
function includeScript(file) {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = file;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
assets/html/findwords/hati.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/findwords/latar.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/html/findwords/parkir - Copy.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
assets/html/findwords/parkir.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/findwords/sekolah.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
16
assets/html/findwords/test.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Test</title>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
document.body.innerHTML += '<p style="color:green;">✅ JS is working!</p>';
|
||||||
|
};
|
||||||
|
window.onload = showAlert;
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello WebView</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
assets/html/freekake.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
@ -224,19 +224,19 @@ figcaption {
|
|||||||
|
|
||||||
<div class="div-grid">
|
<div class="div-grid">
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/furikake/nori.jpeg" alt="Nori">
|
<img src="nori.jpeg" alt="Nori">
|
||||||
<p>Nori (Rumput Laut)</p>
|
<p>Nori (Rumput Laut)</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/furikake/wijen.jpeg" alt="Biji Wijen">
|
<img src="wijen.jpeg" alt="Biji Wijen">
|
||||||
<p>Biji Wijen</p>
|
<p>Biji Wijen</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/furikake/ikankering.jpg" alt="Katsuobushi">
|
<img src="ikankering.jpg" alt="Katsuobushi">
|
||||||
<p>Katsuobushi (Ikan Kering)</p>
|
<p>Katsuobushi (Ikan Kering)</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/furikake/gulagaram.jpg" alt="Garam dan Gula">
|
<img src="gulagaram.jpg" alt="Garam dan Gula">
|
||||||
<p>Garam & Gula</p>
|
<p>Garam & Gula</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -259,7 +259,7 @@ figcaption {
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<figure>
|
<figure>
|
||||||
<img src="assets/html/furikake/furikake.jpg" alt="Contoh produk furikake" class="full-width-image">
|
<img src="furikake.jpg" alt="Contoh produk furikake" class="full-width-image">
|
||||||
<figcaption>Berbagai varian produk furikake yang tersedia di pasaran</figcaption>
|
<figcaption>Berbagai varian produk furikake yang tersedia di pasaran</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -177,23 +177,23 @@
|
|||||||
|
|
||||||
<div class="div-grid">
|
<div class="div-grid">
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/karbohidrat.png" alt="Karbohidrat" />
|
<img src="karbohidrat.png" alt="Karbohidrat" />
|
||||||
<p><strong>Karbohidrat</strong><br>Sumber energi seperti nasi, roti, dan kentang.</p>
|
<p><strong>Karbohidrat</strong><br>Sumber energi seperti nasi, roti, dan kentang.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/protein.png" alt="Protein" />
|
<img src="protein.png" alt="Protein" />
|
||||||
<p><strong>Protein</strong><br>Untuk membangun otot, misalnya ikan, telur, dan tahu.</p>
|
<p><strong>Protein</strong><br>Untuk membangun otot, misalnya ikan, telur, dan tahu.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/lemak.png" alt="Lemak" />
|
<img src="lemak.png" alt="Lemak" />
|
||||||
<p><strong>Lemak</strong><br>Memberikan tenaga, seperti dari kacang-kacangan dan minyak sehat.</p>
|
<p><strong>Lemak</strong><br>Memberikan tenaga, seperti dari kacang-kacangan dan minyak sehat.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/vitaminmineral.png" alt="Vitamin dan Mineral" />
|
<img src="vitaminmineral.png" alt="Vitamin dan Mineral" />
|
||||||
<p><strong>Vitamin dan mineral</strong><br>Dari sayur dan buah yang membantu tubuh bekerja dengan baik.</p>
|
<p><strong>Vitamin dan mineral</strong><br>Dari sayur dan buah yang membantu tubuh bekerja dengan baik.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="div-item">
|
<div class="div-item">
|
||||||
<img src="assets/html/seratair.png" alt="Serat dan Air" />
|
<img src="seratair.png" alt="Serat dan Air" />
|
||||||
<p><strong>Serat dan air</strong><br>Membantu pencernaan dan menjaga tubuh tetap segar!</p>
|
<p><strong>Serat dan air</strong><br>Membantu pencernaan dan menjaga tubuh tetap segar!</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -209,7 +209,7 @@
|
|||||||
<li>🍽️ Seperempat piring: Protein (seperti ayam atau tempe)</li>
|
<li>🍽️ Seperempat piring: Protein (seperti ayam atau tempe)</li>
|
||||||
<li>🍽️ Sedikit lemak sehat</li>
|
<li>🍽️ Sedikit lemak sehat</li>
|
||||||
</ul>
|
</ul>
|
||||||
<img src="assets/html/isipiringku.png" alt="Piring Gizi Seimbang" class="full-width-image">
|
<img src="isipiringku.png" alt="Piring Gizi Seimbang" class="full-width-image">
|
||||||
<figcaption>Isi Piringku</figcaption>
|
<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>
|
<p>Selain itu, kita tidak boleh makan terlalu banyak atau terlalu sedikit, karena bisa membuat tubuh tidak sehat. Makan berlebihan bisa menyebabkan obesitas, sedangkan makan terlalu sedikit bisa membuat tubuh lemas dan kurang gizi.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
BIN
assets/html/memory/ayambetutu.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/html/memory/ayamtaliwang.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/html/memory/bali.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/memory/bikaambon.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
assets/html/memory/freekake.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
assets/html/memory/gudeg.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/html/memory/kalsel.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
176
assets/html/memory/memory.html
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<!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>
|
||||||
BIN
assets/html/memory/ntb.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/html/memory/pempek.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
assets/html/memory/rendang.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
assets/html/memory/sopkonro.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
assets/html/memory/sotobanjar.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/html/memory/sulsel.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/html/memory/sulut.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/html/memory/sumbar.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
assets/html/memory/sumsel.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/html/memory/sumut.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/html/memory/tinutuan.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/html/memory/yogyakarta.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
@ -1,9 +1,5 @@
|
|||||||
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/navbar_shape_3.dart';
|
||||||
import 'package:freekake/components/custom_shape.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class BottomNavbar extends StatefulWidget {
|
class BottomNavbar extends StatefulWidget {
|
||||||
const BottomNavbar({super.key});
|
const BottomNavbar({super.key});
|
||||||
|
|||||||
@ -53,7 +53,6 @@ class CardList extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 1, width: 5),
|
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@ -62,16 +61,16 @@ class CardList extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 1, width: 5),
|
const SizedBox(height: 1, width: 5),
|
||||||
// Text(
|
Text(
|
||||||
// body,
|
body,
|
||||||
// style: const TextStyle(
|
style: const TextStyle(
|
||||||
// letterSpacing: 0.2,
|
letterSpacing: 0.2,
|
||||||
// fontSize: 14,
|
fontSize: 14,
|
||||||
// fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
// ),
|
),
|
||||||
// maxLines: 2,
|
maxLines: 2,
|
||||||
// overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
// ),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(0.08),
|
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/components/menu_button.dart';
|
||||||
import 'package:freekake/components/scan_button.dart';
|
import 'package:freekake/providers/menu_selection_provider.dart';
|
||||||
import 'package:freekake/screen/Home_screen.dart';
|
import 'package:freekake/screen/Home_screen.dart';
|
||||||
import 'package:freekake/screen/koleksi_screen.dart';
|
import 'package:freekake/screen/koleksi_screen.dart';
|
||||||
import 'package:freekake/screen/pustaka_screen.dart';
|
import 'package:freekake/screen/pustaka_screen.dart';
|
||||||
import 'package:freekake/screen/saya/profile_screen.dart';
|
import 'package:freekake/screen/saya/profile_screen.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class MainMenu extends StatefulWidget {
|
class MainMenu extends StatefulWidget {
|
||||||
const MainMenu({super.key});
|
const MainMenu({super.key});
|
||||||
|
|||||||
@ -28,8 +28,8 @@ class MenuButton extends StatelessWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
icon ?? '',
|
icon ?? '',
|
||||||
width: w ?? 24,
|
width: w ?? 28,
|
||||||
height: h ?? 24,
|
height: h ?? 28,
|
||||||
// allowDrawingOutsideViewBox: true,
|
// allowDrawingOutsideViewBox: true,
|
||||||
colorFilter: ColorFilter.mode(
|
colorFilter: ColorFilter.mode(
|
||||||
(isSelected ?? false)
|
(isSelected ?? false)
|
||||||
@ -48,7 +48,6 @@ class MenuButton extends StatelessWidget {
|
|||||||
? Color.fromARGB(255, 216, 182, 10)
|
? Color.fromARGB(255, 216, 182, 10)
|
||||||
: Color.fromARGB(255, 239, 224, 232),
|
: Color.fromARGB(255, 239, 224, 232),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 10,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:freekake/screen/camera_screen.dart';
|
import 'package:freekake/screen/camera_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.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 {
|
class ScanButton extends StatelessWidget {
|
||||||
const ScanButton({super.key});
|
const ScanButton({super.key});
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
class ImagePickerHelper {
|
|
||||||
Future<void> pickImage() async {
|
|
||||||
throw UnsupportedError('pickImage is not supported on this platform');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
// 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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
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/material.dart';
|
||||||
import 'package:freekake/components/navbar_container.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:freekake/providers/character_provider.dart';
|
import 'package:freekake/providers/character_provider.dart';
|
||||||
import 'package:freekake/providers/menu_selection_provider.dart';
|
import 'package:freekake/providers/menu_selection_provider.dart';
|
||||||
import 'package:freekake/providers/point_provider.dart';
|
import 'package:freekake/providers/point_provider.dart';
|
||||||
@ -9,12 +9,12 @@ import 'package:provider/provider.dart';
|
|||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||||
|
|
||||||
// await SystemChrome.setPreferredOrientations([
|
await SystemChrome.setPreferredOrientations([
|
||||||
// DeviceOrientation.portraitUp,
|
DeviceOrientation.portraitUp,
|
||||||
// DeviceOrientation.portraitDown, // bisa dihapus jika hanya ingin satu arah
|
DeviceOrientation.portraitDown,
|
||||||
// ]);
|
]);
|
||||||
|
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ class MyApp extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
title: 'Freekake',
|
title: 'AR Character App',
|
||||||
theme: ThemeData.dark(),
|
theme: ThemeData.dark(),
|
||||||
home:
|
home:
|
||||||
// DrawScreen(),
|
// DrawScreen(),
|
||||||
|
|||||||
31
lib/models/users.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
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,7 +5,6 @@ import 'package:freekake/components/buildcard_info.dart';
|
|||||||
import 'package:freekake/components/main_menu.dart';
|
import 'package:freekake/components/main_menu.dart';
|
||||||
import 'package:freekake/components/menu_item.dart';
|
import 'package:freekake/components/menu_item.dart';
|
||||||
import 'package:freekake/components/scan_button.dart';
|
import 'package:freekake/components/scan_button.dart';
|
||||||
import 'package:flutter_unity_widget/flutter_unity_widget.dart';
|
|
||||||
|
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
const HomeScreen({super.key});
|
const HomeScreen({super.key});
|
||||||
@ -17,7 +16,6 @@ class HomeScreen extends StatefulWidget {
|
|||||||
class _HomeScreenState extends State<HomeScreen> {
|
class _HomeScreenState extends State<HomeScreen> {
|
||||||
final String username = "luffy01";
|
final String username = "luffy01";
|
||||||
// Image image
|
// Image image
|
||||||
late UnityWidgetController _unityWidgetController;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -51,98 +49,89 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: UnityWidget(
|
child: RepaintBoundary(
|
||||||
onUnityCreated: onUnityCreated,
|
child: Container(
|
||||||
//isARScene: true,
|
decoration: const BoxDecoration(
|
||||||
onUnityMessage: onUnityMessage,
|
image: DecorationImage(
|
||||||
//onUnitySceneLoaded: onUnitySceneLoaded,
|
image: AssetImage("assets/images/background.jpeg"),
|
||||||
fullscreen: false,
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Positioned.fill(
|
|
||||||
// child: RepaintBoundary(
|
|
||||||
// child: Container(
|
|
||||||
// decoration: const BoxDecoration(
|
|
||||||
// image: DecorationImage(
|
|
||||||
// image: AssetImage("assets/images/background.jpeg"),
|
|
||||||
// fit: BoxFit.cover,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// Positioned(
|
Positioned(
|
||||||
// right: 0,
|
right: 0,
|
||||||
// top: 100,
|
top: 100,
|
||||||
// child: Padding(
|
child: Padding(
|
||||||
// padding: EdgeInsets.only(right: 20),
|
padding: EdgeInsets.only(right: 20),
|
||||||
// child: Container(
|
child: Container(
|
||||||
// width: 40,
|
width: 40,
|
||||||
// height: 40,
|
height: 40,
|
||||||
// decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// borderRadius: BorderRadius.circular(1),
|
borderRadius: BorderRadius.circular(1),
|
||||||
// color: Color.fromARGB(1, 209, 174, 174).withAlpha(0),
|
color: Color.fromARGB(1, 209, 174, 174).withAlpha(0),
|
||||||
// ),
|
),
|
||||||
// child: Center(
|
child: Center(
|
||||||
// child: DropdownButtonHideUnderline(
|
child: DropdownButtonHideUnderline(
|
||||||
// child: DropdownButton2(
|
child: DropdownButton2(
|
||||||
// customButton: Container(
|
customButton: Container(
|
||||||
// height: 50,
|
height: 100,
|
||||||
// width: 50,
|
width: 100,
|
||||||
// decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
// image: const DecorationImage(
|
image: const DecorationImage(
|
||||||
// image: AssetImage('assets/images/cepot-u.png'),
|
image: AssetImage('assets/images/cepot-u.png'),
|
||||||
// fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// openWithLongPress: false,
|
openWithLongPress: false,
|
||||||
// items: [
|
items: [
|
||||||
// ..._MenuItems.firstItems.map(
|
..._MenuItems.firstItems.map(
|
||||||
// (item) => DropdownMenuItem<MenuItem>(
|
(item) => DropdownMenuItem<MenuItem>(
|
||||||
// value: item,
|
value: item,
|
||||||
// child: _MenuItems.buildItem(item),
|
child: _MenuItems.buildItem(item),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ],
|
],
|
||||||
// onChanged: (value) {
|
onChanged: (value) {
|
||||||
// if (value != null) {
|
if (value != null) {
|
||||||
// _MenuItems.onChanged(context, value);
|
_MenuItems.onChanged(context, value);
|
||||||
// } else {
|
} else {
|
||||||
// print("null");
|
print("null");
|
||||||
// }
|
}
|
||||||
// },
|
},
|
||||||
// buttonStyleData: ButtonStyleData(
|
buttonStyleData: ButtonStyleData(
|
||||||
// decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// borderRadius: BorderRadius.circular(40),
|
borderRadius: BorderRadius.circular(40),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// dropdownStyleData: DropdownStyleData(
|
dropdownStyleData: DropdownStyleData(
|
||||||
// width: 140,
|
width: 140,
|
||||||
// padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
// maxHeight: 150,
|
maxHeight: 150,
|
||||||
// // padding: const EdgeInsets.symmetric(vertical: 6),
|
// padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
// decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
// color: Color.fromRGBO(2, 104, 17, 1).withAlpha(50),
|
color: Color.fromRGBO(2, 104, 17, 1).withAlpha(50),
|
||||||
// ),
|
),
|
||||||
// offset: const Offset(40, -4),
|
offset: const Offset(40, -4),
|
||||||
// ),
|
),
|
||||||
// menuItemStyleData: MenuItemStyleData(
|
menuItemStyleData: MenuItemStyleData(
|
||||||
// height: 35,
|
height: 35,
|
||||||
// padding: EdgeInsets.symmetric(horizontal: 10),
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
// ),
|
),
|
||||||
// // menuItemStyleData: const MenuItemStyleData(
|
// menuItemStyleData: const MenuItemStyleData(
|
||||||
// // padding: EdgeInsets.only(left: 16, right: 16),
|
// padding: EdgeInsets.only(left: 16, right: 16),
|
||||||
// // ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
// ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 10,
|
top: 10,
|
||||||
left: 10,
|
left: 10,
|
||||||
@ -165,25 +154,25 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Positioned(
|
Positioned(
|
||||||
// bottom: 150,
|
bottom: 150,
|
||||||
// left: 0,
|
left: 0,
|
||||||
// right: 0,
|
right: 0,
|
||||||
// child: Column(
|
child: Column(
|
||||||
// children: [
|
children: [
|
||||||
// Container(
|
Container(
|
||||||
// padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
// decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// color: Color.fromARGB(255, 247, 224, 236),
|
color: Color.fromARGB(255, 247, 224, 236),
|
||||||
// borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
// boxShadow: [
|
boxShadow: [
|
||||||
// BoxShadow(
|
BoxShadow(
|
||||||
// color: Color.fromARGB(255, 214, 213, 121),
|
color: Color.fromARGB(255, 214, 213, 121),
|
||||||
// blurRadius: 5,
|
blurRadius: 5,
|
||||||
// spreadRadius: 2,
|
spreadRadius: 2,
|
||||||
// ),
|
),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// child: Text(
|
// child: Text(
|
||||||
// "Halo....Jotaslim",
|
// "Halo....Jotaslim",
|
||||||
// style: TextStyle(
|
// style: TextStyle(
|
||||||
@ -192,12 +181,12 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
// color: Color(0xFF000000),
|
// color: Color(0xFF000000),
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// ),
|
),
|
||||||
// SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
// //setHomeImage("assets/images/cepott.png", 300),
|
setHomeImage("assets/images/cepott.png", 300),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// BG MEnu
|
// BG MEnu
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
@ -229,14 +218,6 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
Widget setHomeImage(String src, double size) {
|
Widget setHomeImage(String src, double size) {
|
||||||
return Image.asset(src, width: size);
|
return Image.asset(src, width: size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUnityCreated(controller) {
|
|
||||||
_unityWidgetController = controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onUnityMessage(message) {
|
|
||||||
print('Received message from unity: ${message.toString()}');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MenuItems {
|
class _MenuItems {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:freekake/components/collection_container.dart';
|
import 'package:freekake/components/collection_container.dart';
|
||||||
|
import 'package:freekake/screen/collection/character_view.dart';
|
||||||
|
|
||||||
class CollectionCaraterScreen extends StatefulWidget {
|
class CollectionCaraterScreen extends StatefulWidget {
|
||||||
const CollectionCaraterScreen({super.key});
|
const CollectionCaraterScreen({super.key});
|
||||||
@ -22,7 +23,13 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Favorit", style: TextStyle(color: Colors.black)),
|
Text(
|
||||||
|
"Favorite",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
Divider(height: 20, color: Colors.transparent),
|
Divider(height: 20, color: Colors.transparent),
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
@ -48,7 +55,13 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
|||||||
charSex: "Laki-laki",
|
charSex: "Laki-laki",
|
||||||
charOrigin: "Jawa Barat",
|
charOrigin: "Jawa Barat",
|
||||||
content:
|
content:
|
||||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan! Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang, hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol, Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk di dekatnya saat ia bercerita.
|
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan!
|
||||||
|
Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang,
|
||||||
|
hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras,
|
||||||
|
suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol,
|
||||||
|
Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur
|
||||||
|
orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah
|
||||||
|
duduk di dekatnya saat ia bercerita.
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -70,7 +83,13 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(height: 20, color: Colors.transparent),
|
Divider(height: 20, color: Colors.transparent),
|
||||||
Text("Semua", style: TextStyle(color: Colors.black)),
|
Text(
|
||||||
|
"All",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
Divider(height: 20, color: Colors.transparent),
|
Divider(height: 20, color: Colors.transparent),
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
@ -106,8 +125,20 @@ class _CollectionCaraterScreenState extends State<CollectionCaraterScreen> {
|
|||||||
charName: "Cepot",
|
charName: "Cepot",
|
||||||
charSex: "Laki-laki",
|
charSex: "Laki-laki",
|
||||||
charOrigin: "Jawa Barat",
|
charOrigin: "Jawa Barat",
|
||||||
content:
|
content: """
|
||||||
"""Cepot adalah sosok yang begitu menarik—aneh, ceria, dan penuh kejutan! Ia muncul seperti tokoh dari dongeng lama yang lupa pulang ke rumah, dengan wajah merah seperti apel matang, hidung besar yang tampak siap mencium rahasia, dan mata bulat yang selalu bersinar penuh rasa ingin tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol, Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk di dekatnya saat ia bercerita.
|
Cepot adalah sosok yang begitu menarik—aneh,
|
||||||
|
ceria, dan penuh kejutan! Ia muncul seperti
|
||||||
|
tokoh dari dongeng lama yang lupa pulang ke rumah,
|
||||||
|
dengan wajah merah seperti apel matang,
|
||||||
|
hidung besar yang tampak siap
|
||||||
|
mencium rahasia, dan mata bulat
|
||||||
|
yang selalu bersinar penuh rasa ingin
|
||||||
|
tahu. Ia suka tertawa keras, suka bermain-main dengan kata-kata, dan sangat
|
||||||
|
pandai membuat siapa pun merasa nyaman di dekatnya. \nMeski kadang terlihat konyol,
|
||||||
|
Cepot sebenarnya sangat cerdik—ia tahu kapan harus berbicara, kapan harus diam, dan
|
||||||
|
yang paling penting, ia tahu bagaimana menghibur orang-orang yang sedang sedih. \nAnak-anak
|
||||||
|
menyukainya, orang tua menghormatinya, dan tak jarang hewan-hewan kecil pun tampak betah duduk
|
||||||
|
di dekatnya saat ia bercerita.
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:freekake/components/collection_container.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 {
|
class CollectionSkinScreen extends StatefulWidget {
|
||||||
const CollectionSkinScreen({super.key});
|
const CollectionSkinScreen({super.key});
|
||||||
|
|||||||
105
lib/screen/pustaka/_list_detail_screen.dart
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
|
class _ListDetailScreen extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final String? filepath;
|
||||||
|
|
||||||
|
const _ListDetailScreen({super.key, required this.title, this.filepath});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ListDetailScreen> createState() => _ListDetailScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ListDetailScreenState extends State<_ListDetailScreen> {
|
||||||
|
List<bool> checklist = [];
|
||||||
|
late WebViewController _controller;
|
||||||
|
late String? fPath = widget.filepath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller =
|
||||||
|
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||||
|
checklist = List.generate(paragraphs.length, (index) => false);
|
||||||
|
if (fPath != null && fPath!.isNotEmpty) {
|
||||||
|
_loadContent(fPath!); // <- ini penting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> paragraphs = [
|
||||||
|
"Paragraf pertama tentang ${"widget.title"}.",
|
||||||
|
"Paragraf kedua dengan informasi tambahan.",
|
||||||
|
"Paragraf ketiga yang menjelaskan detail lebih lanjut.",
|
||||||
|
"Paragraf keempat yang melengkapi pembahasan.",
|
||||||
|
];
|
||||||
|
|
||||||
|
void _loadContent(String path) async {
|
||||||
|
try {
|
||||||
|
if (path.startsWith('http')) {
|
||||||
|
_controller.loadRequest(Uri.parse(path));
|
||||||
|
} else {
|
||||||
|
String fileHtml = await rootBundle.loadString(path);
|
||||||
|
_controller.loadHtmlString(fileHtml);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Error loading HTML: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: AppBar(title: Text(widget.title)),
|
||||||
|
body:
|
||||||
|
(fPath != null && fPath!.isNotEmpty)
|
||||||
|
? WebViewWidget(controller: _controller)
|
||||||
|
: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/images/default.png',
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Ini adalah detail dari ${widget.title}.",
|
||||||
|
style: const TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: paragraphs.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(paragraphs[index]),
|
||||||
|
trailing: Checkbox(
|
||||||
|
value: checklist[index],
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
setState(() {
|
||||||
|
checklist[index] = value!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
class ListDetailScreen extends StatefulWidget {
|
class ListDetailScreen extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
@ -13,89 +14,120 @@ class ListDetailScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ListDetailScreenState extends State<ListDetailScreen> {
|
class _ListDetailScreenState extends State<ListDetailScreen> {
|
||||||
List<bool> checklist = [];
|
late InAppWebViewController _webViewController;
|
||||||
late WebViewController _controller;
|
|
||||||
late String? fPath = widget.filepath;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
checklist = List.generate(paragraphs.length, (index) => false);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> paragraphs = [
|
|
||||||
"Paragraf pertama tentang ${"widget.title"}.",
|
|
||||||
"Paragraf kedua dengan informasi tambahan.",
|
|
||||||
"Paragraf ketiga yang menjelaskan detail lebih lanjut.",
|
|
||||||
"Paragraf keempat yang melengkapi pembahasan.",
|
|
||||||
];
|
|
||||||
|
|
||||||
void _loadContent(String path) async {
|
|
||||||
if (path.startsWith('http')) {
|
|
||||||
// Load dari Internet
|
|
||||||
_controller.loadRequest(Uri.parse(path));
|
|
||||||
} else {
|
|
||||||
// Load dari assets lokal
|
|
||||||
String fileHtml = await rootBundle.loadString(path);
|
|
||||||
_controller.loadHtmlString(fileHtml);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
String _getMimeType(String path) {
|
||||||
|
if (path.endsWith('.png')) return 'image/png';
|
||||||
|
if (path.endsWith('.jpg') || path.endsWith('.jpeg')) return 'image/jpeg';
|
||||||
|
if (path.endsWith('.svg')) return 'image/svg+xml';
|
||||||
|
if (path.endsWith('.html')) return 'text/html';
|
||||||
|
if (path.endsWith('.css')) return 'text/css';
|
||||||
|
if (path.endsWith('.js')) return 'application/javascript';
|
||||||
|
return 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
|
||||||
appBar: AppBar(title: Text(widget.title)),
|
appBar: AppBar(title: Text(widget.title)),
|
||||||
body:
|
body:
|
||||||
(fPath != null && fPath!.isNotEmpty)
|
widget.filepath != null
|
||||||
? WebViewWidget(controller: _controller)
|
? InAppWebView(
|
||||||
: Padding(
|
initialUrlRequest: URLRequest(url: WebUri("about:blank")),
|
||||||
padding: const EdgeInsets.all(16.0),
|
initialOptions: InAppWebViewGroupOptions(
|
||||||
child: Column(
|
crossPlatform: InAppWebViewOptions(
|
||||||
children: [
|
javaScriptEnabled: true,
|
||||||
// Gambar di kiri atas dengan teks di kanan
|
allowFileAccessFromFileURLs: true,
|
||||||
Row(
|
allowUniversalAccessFromFileURLs: true,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Image.asset(
|
|
||||||
'assets/images/default.png', // Ganti dengan gambar yang sesuai
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"Ini adalah detail dari ${widget.title}.",
|
|
||||||
style: const TextStyle(fontSize: 18),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
onWebViewCreated: (controller) async {
|
||||||
),
|
_webViewController = controller;
|
||||||
const SizedBox(height: 20),
|
|
||||||
|
|
||||||
// Paragraf dengan checklist
|
final html = await rootBundle.loadString(widget.filepath!);
|
||||||
Expanded(
|
final base = widget.filepath!.substring(
|
||||||
child: ListView.builder(
|
0,
|
||||||
itemCount: paragraphs.length,
|
widget.filepath!.lastIndexOf('/') + 1,
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(paragraphs[index]),
|
|
||||||
trailing: Checkbox(
|
|
||||||
value: checklist[index],
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
checklist[index] = value!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
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,16 +2,21 @@ import 'dart:convert';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:freekake/components/buildcard_info.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:freekake/components/card_list.dart';
|
import 'package:freekake/components/card_list.dart';
|
||||||
import 'package:freekake/components/collection_container%20copy.dart';
|
import 'package:freekake/components/collection_container%20copy.dart';
|
||||||
import 'package:freekake/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/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 {
|
class ListEducation extends StatefulWidget {
|
||||||
const ListEducation({super.key});
|
final String? selectedCategory;
|
||||||
|
const ListEducation({super.key, this.selectedCategory});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ListEducation> createState() => _ListEducationState();
|
State<ListEducation> createState() => _ListEducationState();
|
||||||
@ -22,10 +27,15 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
late final WebViewController _controller;
|
late final WebViewController _controller;
|
||||||
late String urlOrAssetPath;
|
late String urlOrAssetPath;
|
||||||
bool _shouldShowWebView = false;
|
bool _shouldShowWebView = false;
|
||||||
|
String? selectedCategory;
|
||||||
// load extension
|
|
||||||
final listDetailExtension = ListDetailExtension();
|
final listDetailExtension = ListDetailExtension();
|
||||||
|
|
||||||
|
// Data fetch
|
||||||
|
final ApiClient _apiClient = ApiClient();
|
||||||
|
List<Users> _posts = [];
|
||||||
|
bool _isLoading = true;
|
||||||
|
String _error = '';
|
||||||
|
|
||||||
Future<void> _initExtension() async {
|
Future<void> _initExtension() async {
|
||||||
await listDetailExtension.load();
|
await listDetailExtension.load();
|
||||||
}
|
}
|
||||||
@ -69,18 +79,55 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
""",
|
""",
|
||||||
"file": "assets/html/index.html",
|
"file": "assets/html/index.html",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Memori Game",
|
||||||
|
"image": "assets/html/freekake.png",
|
||||||
|
"color": "#cef1da",
|
||||||
|
"category": "Gizi",
|
||||||
|
"type": "Materi",
|
||||||
|
"point": "100",
|
||||||
|
"coint": "20",
|
||||||
|
"body":
|
||||||
|
"""Game untuk melatih daya ingat siswa, sehingga bisa diharapkan bisa
|
||||||
|
menemukan cara sendiri untuk mengingat sesuatu
|
||||||
|
""",
|
||||||
|
"file": "assets/html/memory/memory.html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Find Words",
|
||||||
|
"image": "assets/html/freekake.png",
|
||||||
|
"color": "#cef1da",
|
||||||
|
"category": "Kesehatan",
|
||||||
|
"type": "Materi",
|
||||||
|
"point": "100",
|
||||||
|
"coint": "20",
|
||||||
|
"body": """
|
||||||
|
No Descripptions
|
||||||
|
""",
|
||||||
|
"file": "assets/html/findwords/findwords.html",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
List<Map<String, dynamic>> filteredItems = [];
|
List<Map<String, dynamic>> filteredItems = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
selectedCategory = widget.selectedCategory;
|
||||||
|
print(selectedCategory);
|
||||||
|
if (selectedCategory != null && selectedCategory!.isNotEmpty) {
|
||||||
|
filteredItems =
|
||||||
|
_listContent
|
||||||
|
.where((item) => item["category"] == selectedCategory)
|
||||||
|
.toList();
|
||||||
|
} else {
|
||||||
filteredItems = List.from(_listContent);
|
filteredItems = List.from(_listContent);
|
||||||
|
}
|
||||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
_shouldShowWebView = true;
|
_shouldShowWebView = true;
|
||||||
_controller =
|
_controller =
|
||||||
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted);
|
||||||
urlOrAssetPath = "assets/makanan_bergizi/index.html";
|
urlOrAssetPath = "assets/html/index.html";
|
||||||
_loadContent(urlOrAssetPath);
|
_loadContent(urlOrAssetPath);
|
||||||
_initExtension();
|
_initExtension();
|
||||||
}
|
}
|
||||||
@ -92,18 +139,20 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
// Load dari Internet
|
// Load dari Internet
|
||||||
_controller.loadRequest(Uri.parse(path));
|
_controller.loadRequest(Uri.parse(path));
|
||||||
} else {
|
} else {
|
||||||
// Load dari assets lokal
|
try {
|
||||||
// String fileHtml = await rootBundle.loadString(path);
|
await rootBundle.load(path);
|
||||||
String fileHtml = await DefaultAssetBundle.of(
|
await _controller.loadFlutterAsset(path);
|
||||||
context,
|
} catch (e) {
|
||||||
).loadString('assets/html/index.html');
|
print("Gagal memuat file HTML: $path\nError: $e");
|
||||||
_controller.loadHtmlString(fileHtml);
|
}
|
||||||
|
_controller.loadFlutterAsset(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterSearch(String query) {
|
void filterSearch(String query) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
selectedCategory = null;
|
||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
filteredItems = List.from(_listContent);
|
filteredItems = List.from(_listContent);
|
||||||
} else {
|
} else {
|
||||||
@ -117,6 +166,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
|
|
||||||
void filterByCategory(String category) {
|
void filterByCategory(String category) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
selectedCategory = category;
|
||||||
filteredItems =
|
filteredItems =
|
||||||
_listContent.where((item) {
|
_listContent.where((item) {
|
||||||
return item["category"].toLowerCase() == category.toLowerCase();
|
return item["category"].toLowerCase() == category.toLowerCase();
|
||||||
@ -124,9 +174,43 @@ 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String searchQuery = "";
|
|
||||||
final List<Map<String, dynamic>> collections = [
|
final List<Map<String, dynamic>> collections = [
|
||||||
{
|
{
|
||||||
"label": "Kesehatan",
|
"label": "Kesehatan",
|
||||||
@ -158,7 +242,8 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
collections
|
collections
|
||||||
.where(
|
.where(
|
||||||
(item) => item["label"].toLowerCase().contains(
|
(item) => item["label"].toLowerCase().contains(
|
||||||
searchQuery.toLowerCase(),
|
// searchQuery.toLowerCase(),
|
||||||
|
searchController.text.toLowerCase(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
@ -176,7 +261,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
// Header Section
|
// Header Section
|
||||||
headerContainer(context, filteredCollections),
|
headerContainer(context, collections),
|
||||||
// Collection Items dengan Filter
|
// Collection Items dengan Filter
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Expanded(child: contentContainer(context)),
|
Expanded(child: contentContainer(context)),
|
||||||
@ -255,6 +340,7 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children:
|
children:
|
||||||
filteredCollections.map((item) {
|
filteredCollections.map((item) {
|
||||||
|
final isSelected = selectedCategory == item["category"];
|
||||||
return CollectionContainer(
|
return CollectionContainer(
|
||||||
label: item["label"]!,
|
label: item["label"]!,
|
||||||
imageSvg: item["image"]!,
|
imageSvg: item["image"]!,
|
||||||
@ -262,9 +348,16 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
iconh: 20,
|
iconh: 20,
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 70,
|
height: 70,
|
||||||
textColor: Colors.black,
|
textColor:
|
||||||
lblSize: 8,
|
isSelected
|
||||||
colorContiner: ColorHelper.hexToColor(item["color"]),
|
? const Color.fromARGB(255, 230, 48, 160)
|
||||||
|
: Colors.black,
|
||||||
|
lblSize: 10,
|
||||||
|
// colorContiner: ColorHelper.hexToColor(item["color"]),
|
||||||
|
colorContiner:
|
||||||
|
isSelected
|
||||||
|
? const Color.fromARGB(255, 84, 3, 224)
|
||||||
|
: ColorHelper.hexToColor(item["color"]),
|
||||||
onTapAc:
|
onTapAc:
|
||||||
() => {
|
() => {
|
||||||
searchController.clear(),
|
searchController.clear(),
|
||||||
@ -347,36 +440,41 @@ class _ListEducationState extends State<ListEducation> {
|
|||||||
GridView _generateList() {
|
GridView _generateList() {
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 1, // 2 Kolom
|
crossAxisCount: 1,
|
||||||
crossAxisSpacing: 10,
|
crossAxisSpacing: 10,
|
||||||
mainAxisSpacing: 10,
|
mainAxisSpacing: 10,
|
||||||
childAspectRatio: 2.5,
|
childAspectRatio: 2.5,
|
||||||
),
|
),
|
||||||
itemCount: _listContent.length,
|
itemCount: filteredItems.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
child: CardList(
|
child: CardList(
|
||||||
title: _listContent[index]["title"] ?? "",
|
title: filteredItems[index]["title"] ?? "",
|
||||||
body: _listContent[index]["body"] ?? "",
|
body: filteredItems[index]["body"] ?? "",
|
||||||
gambar: _listContent[index]['image'],
|
gambar: filteredItems[index]['image'],
|
||||||
point: _listContent[index]['coint'],
|
point: filteredItems[index]['point'],
|
||||||
coint: _listContent[index]['point'],
|
coint: filteredItems[index]['coint'],
|
||||||
tipe: _listContent[index]['tipe'],
|
tipe: filteredItems[index]['type'],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder:
|
builder:
|
||||||
(context) => listDetailExtension.buildPage({
|
// (context) => listDetailExtension.buildPage({
|
||||||
'title': filteredItems[index]['category'],
|
// 'title': filteredItems[index]['category'],
|
||||||
'imagePath': filteredItems[index]['image'],
|
// 'imagePath': filteredItems[index]['image'],
|
||||||
'filepath': filteredItems[index]['file'],
|
// 'filepath': filteredItems[index]['file'],
|
||||||
'paragraphs':
|
// 'paragraphs':
|
||||||
"""
|
// """
|
||||||
"""
|
// """
|
||||||
"<h1> ${_listContent[index]["title"]} </h1> <p> ${_listContent[index]["body"]}",
|
// "<h1> ${filteredItems[index]["title"]} </h1> <p> ${filteredItems[index]["body"]}",
|
||||||
}),
|
// }),
|
||||||
|
(context) => ListDetailScreen(
|
||||||
|
title: filteredItems[index]['category'],
|
||||||
|
// 'imagePath': filteredItems[index]['image'],
|
||||||
|
filepath: filteredItems[index]['file'],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -74,106 +74,11 @@ class _ListDetailScreenState extends State<ListPustakaDetailScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.all(20.0),
|
|
||||||
// child: Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Image.asset(
|
|
||||||
// widget.imagePath,
|
|
||||||
// width: 100,
|
|
||||||
// height: 100,
|
|
||||||
// fit: BoxFit.cover,
|
|
||||||
// ),
|
|
||||||
// const SizedBox(width: 16),
|
|
||||||
// Expanded(
|
|
||||||
// child: Center(
|
|
||||||
// child: Text(
|
|
||||||
// widget.title,
|
|
||||||
// style: const TextStyle(
|
|
||||||
// fontSize: 22,
|
|
||||||
// fontWeight: FontWeight.bold,
|
|
||||||
// color: Colors.black,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
const SizedBox(height: 0),
|
const SizedBox(height: 0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
|
padding: const EdgeInsets.only(left: 18.0, right: 18, bottom: 18),
|
||||||
child:
|
child: htmlBody(),
|
||||||
// ListView.builder(
|
|
||||||
// itemCount: widget.paragraphs.length,
|
|
||||||
// itemBuilder: (context, index) {
|
|
||||||
// return
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
// child: Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Expanded(
|
|
||||||
// child:
|
|
||||||
// // Text(
|
|
||||||
// // widget.paragraphs[index] +
|
|
||||||
// // style: TextStyle(color: Colors.black),
|
|
||||||
// Html(
|
|
||||||
// // style: {
|
|
||||||
// // "body": Style(
|
|
||||||
// // color: const Color.fromRGBO(0, 0, 0, 1),
|
|
||||||
// // ),
|
|
||||||
// // },
|
|
||||||
// data:
|
|
||||||
// widget.paragraphs +
|
|
||||||
// """
|
|
||||||
// <html>
|
|
||||||
// <!-- Text between angle brackets is an HTML tag and is not displayed.
|
|
||||||
// Most tags, such as the HTML and /HTML tags that surround the contents of
|
|
||||||
// a page, come in pairs; some tags, like HR, for a horizontal rule, stand
|
|
||||||
// alone. Comments, such as the text you're reading, are not displayed when
|
|
||||||
// the Web page is shown. The information between the HEAD and /HEAD tags is
|
|
||||||
// not displayed. The information between the BODY and /BODY tags is displayed.-->
|
|
||||||
// <head>
|
|
||||||
// <title>Enter a title, displayed at the top of the window.</title>
|
|
||||||
// </head>
|
|
||||||
// <!-- The information between the BODY and /BODY tags is displayed.-->
|
|
||||||
// <body>
|
|
||||||
// <h1>Enter the main heading, usually the same as the title.</h1>
|
|
||||||
// <p>Be <b>bold</b> in stating your key points. Put them in a list: </p>
|
|
||||||
// <ul>
|
|
||||||
// <li>The first item in your list</li>
|
|
||||||
// <li>The second item; <i>italicize</i> key words</li>
|
|
||||||
// </ul>
|
|
||||||
// <p>Improve your image by including an image. </p>
|
|
||||||
// <p><img src="http://www.mygifs.com/CoverImage.gif" alt="A Great HTML Resource"></p>
|
|
||||||
// <p>Add a link to your favorite <a href="https://www.dummies.com/">Web site</a>.
|
|
||||||
// Break up your page with a horizontal rule or two. </p>
|
|
||||||
// <hr>
|
|
||||||
// <p>Finally, link to <a href="page2.html">another page</a> in your own Web site.</p>
|
|
||||||
// <!-- And add a copyright notice.-->
|
|
||||||
// <p>© Wiley Publishing, 2011</p>
|
|
||||||
// </body>
|
|
||||||
// </html>
|
|
||||||
// """,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// // ),
|
|
||||||
// // Checkbox(
|
|
||||||
// // value: _readStatus[index],
|
|
||||||
// // onChanged: (bool? value) {
|
|
||||||
// // _toggleReadStatus(index);
|
|
||||||
// // },
|
|
||||||
// // ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
htmlBody(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -108,7 +108,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
children: [
|
children: [
|
||||||
CollectionContainer(
|
CollectionContainer(
|
||||||
label: "Luffy",
|
label: "Luffy",
|
||||||
imagesrc: 'assets/images/luffy.png',
|
imagesrc: 'images/luffy.png',
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100,
|
height: 100,
|
||||||
onTapAc:
|
onTapAc:
|
||||||
|
|||||||
@ -108,7 +108,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
children: [
|
children: [
|
||||||
CollectionContainer(
|
CollectionContainer(
|
||||||
label: "Luffy",
|
label: "Luffy",
|
||||||
imagesrc: 'assets/images/luffy.png',
|
imagesrc: 'images/luffy.png',
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100,
|
height: 100,
|
||||||
onTapAc:
|
onTapAc:
|
||||||
|
|||||||
@ -44,6 +44,32 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
final List<Map<String, dynamic>> _genres = [
|
||||||
|
{
|
||||||
|
"label": "Game",
|
||||||
|
"type": "game",
|
||||||
|
"image": "assets/icons/healthy.svg",
|
||||||
|
"color": "#cdd0ee",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Novel",
|
||||||
|
"image": "assets/icons/Nutrition.svg",
|
||||||
|
"color": "#e8e29a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "TTS",
|
||||||
|
"type": "puzzle",
|
||||||
|
"image": "assets/icons/Education.svg",
|
||||||
|
"color": "#efd8c6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Pazzle",
|
||||||
|
"type": "puzzle",
|
||||||
|
"image": "assets/icons/Safety.svg",
|
||||||
|
"color": "#cef1da",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
void _onMenuTapped(int index) {
|
void _onMenuTapped(int index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedIndex = index;
|
_selectedIndex = index;
|
||||||
@ -60,14 +86,23 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
final buttonScanSize = screenWidth * 0.20;
|
final buttonScanSize = screenWidth * 0.20;
|
||||||
final double bottomPadding = (9000 / screenWidth).clamp(0, 0.2);
|
final double bottomPadding = (9000 / screenWidth).clamp(0, 0.2);
|
||||||
List<Map<String, dynamic>> filteredCollections =
|
|
||||||
_collections
|
List<Map<String, dynamic>> filterCollections(
|
||||||
|
List<Map<String, dynamic>> collections,
|
||||||
|
String query,
|
||||||
|
) {
|
||||||
|
return collections
|
||||||
.where(
|
.where(
|
||||||
(item) => item["label"]!.toLowerCase().contains(
|
(item) =>
|
||||||
_searchQuery.toLowerCase(),
|
item["label"]!.toLowerCase().contains(query.toLowerCase()),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> filteredCollections = filterCollections(
|
||||||
|
_collections,
|
||||||
|
_searchQuery,
|
||||||
|
);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
backgroundColor: const Color.fromARGB(255, 255, 255, 255),
|
||||||
@ -121,16 +156,6 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// // Date Display
|
|
||||||
// Padding(
|
|
||||||
// padding: const EdgeInsets.symmetric(vertical: 10),
|
|
||||||
// child: Text(
|
|
||||||
// DateTime.now().toString(),
|
|
||||||
// style: const TextStyle(color: Colors.white),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// Search Bar
|
// Search Bar
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||||
@ -198,7 +223,10 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => const ListEducation(),
|
builder:
|
||||||
|
(_) => ListEducation(
|
||||||
|
selectedCategory: item["label"],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -231,10 +259,12 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: List.generate(
|
children:
|
||||||
10,
|
_genres.map((genre) {
|
||||||
(index) => Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8.0,
|
||||||
|
),
|
||||||
child: Card(
|
child: Card(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
@ -267,7 +297,7 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
color: Colors.blueAccent,
|
color: Colors.blueAccent,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Topic ${index + 1}',
|
genre['label'],
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color.fromARGB(255, 0, 0, 0),
|
color: Color.fromARGB(255, 0, 0, 0),
|
||||||
@ -278,14 +308,12 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
// Bottom Navigation
|
|
||||||
// MainMenu(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// BG MEnu
|
// BG MEnu
|
||||||
@ -300,6 +328,8 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
Positioned(bottom: 0, left: 0, right: 0, child: MainMenu()),
|
Positioned(bottom: 0, left: 0, right: 0, child: MainMenu()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: bottomPadding * 98,
|
bottom: bottomPadding * 98,
|
||||||
left: (screenWidth - buttonScanSize) / 2,
|
left: (screenWidth - buttonScanSize) / 2,
|
||||||
@ -309,6 +339,8 @@ class _PustakaScreenState extends State<PustakaScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,211 +0,0 @@
|
|||||||
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,6 +7,7 @@ import 'package:freekake/components/scan_button.dart';
|
|||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
// import 'package:image_picker_web/image_picker_web.dart';
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
|
|
||||||
class AkunSaya extends StatefulWidget {
|
class AkunSaya extends StatefulWidget {
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import 'package:freekake/screen/saya/point_saya.dart';
|
|||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
// import 'package:image_picker_web/image_picker_web.dart';
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
|
|
||||||
class ProfileScreen extends StatefulWidget {
|
class ProfileScreen extends StatefulWidget {
|
||||||
|
|||||||
36
lib/util/api_client.dart
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
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,6 +7,7 @@ import Foundation
|
|||||||
|
|
||||||
import desktop_webview_window
|
import desktop_webview_window
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
|
import flutter_inappwebview_macos
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import webview_flutter_wkwebview
|
import webview_flutter_wkwebview
|
||||||
@ -14,6 +15,7 @@ import webview_flutter_wkwebview
|
|||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
|
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||||
|
|||||||
107
pubspec.lock
@ -129,6 +129,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.3"
|
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:
|
dropdown_button2:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -206,6 +222,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0-beta.2"
|
version: "3.0.0-beta.2"
|
||||||
|
flutter_inappwebview:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview
|
||||||
|
sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
|
flutter_inappwebview_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_android
|
||||||
|
sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
|
flutter_inappwebview_internal_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_internal_annotations
|
||||||
|
sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
flutter_inappwebview_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_ios
|
||||||
|
sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_inappwebview_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_macos
|
||||||
|
sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_inappwebview_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_platform_interface
|
||||||
|
sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0+1"
|
||||||
|
flutter_inappwebview_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_web
|
||||||
|
sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_inappwebview_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_inappwebview_windows
|
||||||
|
sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -235,15 +315,6 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
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:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -822,23 +893,7 @@ packages:
|
|||||||
sha256: "18b1640839cf6546784a524c72aded5b6e86b23e7167dc2311cc96f7658b64bd"
|
sha256: "18b1640839cf6546784a524c72aded5b6e86b23e7167dc2311cc96f7658b64bd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.11.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:
|
webview_flutter_wkwebview:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
55
pubspec.yaml
@ -54,16 +54,13 @@ dependencies:
|
|||||||
url: https://github.com/fhauze/list_detail_screen.git
|
url: https://github.com/fhauze/list_detail_screen.git
|
||||||
ref: main
|
ref: main
|
||||||
desktop_webview_window: ^0.2.3
|
desktop_webview_window: ^0.2.3
|
||||||
|
flutter_inappwebview: ^6.0.0
|
||||||
|
dio: ^5.0.0
|
||||||
# arcore_flutter_plugin: ^0.2.0-alpha
|
# arcore_flutter_plugin: ^0.2.0-alpha
|
||||||
# flutter_unity_widget: ^2022.2.1
|
# flutter_unity_widget: ^2022.2.1
|
||||||
# arcore_flutter_plugin:
|
# arcore_flutter_plugin:
|
||||||
# git:
|
# git:
|
||||||
# url: https://github.com/giandifra/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:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -90,13 +87,57 @@ flutter:
|
|||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- 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
|
# SVG files
|
||||||
- assets/icons/
|
- 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
|
||||||
|
|
||||||
|
#HTML File
|
||||||
- assets/html/
|
- assets/html/
|
||||||
|
- assets/html/index.html
|
||||||
|
- assets/html/furikake/index.html
|
||||||
- assets/html/furikake/
|
- 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
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/to/resolution-aware-images
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||||
#include <file_selector_windows/file_selector_windows.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
|
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
@ -16,6 +17,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
|
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
desktop_webview_window
|
desktop_webview_window
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
|
flutter_inappwebview_windows
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|||||||